referencing columns
Douglas Surber
douglas.surber at oracle.com
Fri May 4 14:28:06 UTC 2018
I don’t think separating the types works. Column integrates several concepts and I think the combination is more useful than separating them.
- Row, a sequence of columns
- ColumnIterator
- ColumnCursor points to a particular column and can move to point to other columns
- Column provides access to the column value and metadata
public interface Row extends Iterable<Column>{
public long rowNumber();
public Row cancel();
public ColumnCursor columnCursor();
// forEach, iterator, spliterator
}
public interface ColumnIterator extends Iterator<Column> {
// forEachRemaining, hasNext, next, remove
}
public interface ColumnCursor
public ColumnCursor next();
public boolean hasNext();
public ColumnCursor at(String id);
public ColumnCursor at(int index);
public Column get();
}
public interface Column {
public <T> T get(Class<T> type);
public SqlType sqlType();
public <T> Class<T> javaType();
public String id();
public int index();
}
In order to mix access patterns we have to add more methods. For example add getColumnCursor to Column in order to switch from iteration to motion. Next user code has to use those additional methods to navigate between the types to get to the right one.
An always has to navigate to a Column to actually get a value. Finally there will be method duplication. All in all I think the result is much more complex and definitely much harder to use.
I encourage you to actually write some code using both and see what you think.
Douglas
> On May 4, 2018, at 12:56 AM, Lukas Eder <lukas.eder at gmail.com> wrote:
>
> I agree that iterating over columns is very useful and I've noticed that you've mixed the two paradigms, which is also useful.
>
> If you pursue the thought of this API, will you consider separating the functionality into two types?
>
> - Columns extends Iterable<Column> (which is essentially ResultMap)
> - Column
>
> If not, what would be the motivation to make Column iterate on itself as a type?
>
> Lukas
>
> 2018-05-03 17:33 GMT+02:00 Douglas Surber <douglas.surber at oracle.com <mailto:douglas.surber at oracle.com>>:
> Lukas,
>
> This is orthogonal to the Flow.Processor vs Collector discussion. And please note that ADBA has both.
>
> Using a column cursor to access the columns is an attempt to break out of the get(int) vs get(String) way of thinking. I came up with this by thinking about all the different patterns of column access I’ve seen over the years and trying to wrap them up in a reasonably simple API. It quickly became clear that I needed to separate column selection from value access. Once I did that this class was an obvious consequence.
>
> It provides baked-in support for many different access patterns rather than requiring the programmer to roll his own. What I especially like is the way it supports mixing access patterns, for example locating a column by name, then iterating over a subsequence of successive columns.
>
> The advantage is that it should make it easy to avoid counting columns to come up with the desired index and at the same time handle missing and duplicate identifiers. From a framework perspective simple iteration over columns should be incredibly useful.
>
> Douglas
>
>
>> On May 3, 2018, at 1:23 AM, Lukas Eder <lukas.eder at gmail.com <mailto:lukas.eder at gmail.com>> wrote:
>>
>> Hi Douglas,
>>
>> This type would be very interesting. Akin to JDBC's ResultSetMetaData type, but more object oriented. Mixed with JDBC's ResultSet's notion of being a cursor with a current position.
>>
>> Of course, this cursor-ness is precisely the "old JDBC ResultSet" model, which is understandable from the perspective of a result set being a flattened stream of column/value pairs, but I think that few people think about result sets or records in this way. In JDBC, most people would like to fetch a List<Row> style type. In ADBA, being asynchronous, a Consumer<Row> style type (simplified Collector) seems appropriate. Putting the individual column and its value at the top abstraction level might be surprising.
>>
>> What would be the benefit of this approach?
>>
>>
>> 2018-05-02 19:42 GMT+02:00 Douglas Surber <douglas.surber at oracle.com <mailto:douglas.surber at oracle.com>>:
>> Here is another way to approach referencing columns. Replace ResultMap with Column as defined below. This is not a fully thought out proposal. It is instead an attempt to look at the problem from another direction and not get stuck with the same old JDBC ResultSet model.
>>
>> Douglas
>>
>> /**
>> * A mutable handle to one value of an ordered sequence of columns or of
>> * out parameters. Columns have a 1-based index and optionally an identifier.
>> * Identifiers are not guaranteed to be unique.
>> */
>> public interface Column extends Iterable<Column>, Iterator<Column>, Cloneable {
>>
>> /**
>> * Return the value of this column as an instance of the given type.
>> *
>> * @param <T>
>> * @param type
>> * @return
>> */
>> public <T> T get(Class<T> type);
>>
>> /**
>> * Return the identifier of this column. May be null.
>> *
>> * @return
>> */
>> public String identifier();
>>
>> /**
>> * Return the 1-based index of this Column.
>> *
>> * @return
>> */
>> public int index();
>>
>> /**
>> * Return the SQL type of the value of this column.
>> *
>> * @return
>> */
>> public SqlType type();
>>
>> /**
>> * Modify this Column to point to the next value identified by id.
>> *
>> * @param id
>> * @return this Column
>> */
>> public Column at(String id);
>>
>> /**
>> * Modify this Column to point to the value at index. The first value is at index 1.
>> * Negative numbers count back from the last value. The last value is at
>> * index -1.
>> *
>> * @param index
>> * @return this Column
>> */
>> public Column at(int index);
>>
>> /**
>> * Return a new Column that is a handle to a subsequence of sequence of values
>> * referenced by this Column. The subsequence consists of the length values in
>> * order starting with the value this Column points to when this method is
>> * called. This Column is not modified.
>> *
>> * @param length
>> * @return a new Column.
>> */
>> public Column slice(int length);
>>
>> /**
>> * Return a new Column that is a duplicate of this Column.
>> *
>> * @return a new Column
>> */
>> public Column clone();
>>
>> /**
>> * Modify this Column to point to the next value in the sequence.
>> *
>> * @return this Column
>> */
>> @Override
>> public Column next();
>>
>> @Override
>> public boolean hasNext();
>>
>>
>> static void sample(Column columns) {
>>
>> Map map = new HashMap();
>> for (Column m : columns) {
>> map.put(m.identifier(), m.get(Integer.class));
>> }
>>
>> List l = new ArrayList();
>> for (Column m : columns.at <https://urldefense.proofpoint.com/v2/url?u=http-3A__columns.at&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=DFcFtomvCycx6XeC1vpTp5TdBqlgkiljGpb5LljiXB4&m=QPvt4Up_aA0V_2p8Wq5SJgPn3Q_4ik1C9rJlyYlvBCk&s=xqp-Xj0rZnZIglqGGccfiy1Q_SbHxh29KAqRT79xdm8&e=>(3).slice(5)) {
>> l.add(m.get(String.class));
>> }
>>
>> Column addr = columns.clone().at("street_address_1");
>> String streetAddress1 = addr.get(String.class);
>> String streetAddress2 = addr.next().get(String.class);
>> String city = addr.next().get(String.class);
>> String state = addr.next().get(String.class);
>> String postalCode = addr.next().get(String.class);
>>
>> String givenName = columns.at <https://urldefense.proofpoint.com/v2/url?u=http-3A__columns.at&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=DFcFtomvCycx6XeC1vpTp5TdBqlgkiljGpb5LljiXB4&m=QPvt4Up_aA0V_2p8Wq5SJgPn3Q_4ik1C9rJlyYlvBCk&s=xqp-Xj0rZnZIglqGGccfiy1Q_SbHxh29KAqRT79xdm8&e=>("GIVEN_NAME").get(String.class);
>> String familyName = columns.at <https://urldefense.proofpoint.com/v2/url?u=http-3A__columns.at&d=DwMFaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=DFcFtomvCycx6XeC1vpTp5TdBqlgkiljGpb5LljiXB4&m=QPvt4Up_aA0V_2p8Wq5SJgPn3Q_4ik1C9rJlyYlvBCk&s=xqp-Xj0rZnZIglqGGccfiy1Q_SbHxh29KAqRT79xdm8&e=>("FAMILY_NAME").get(String.class);
>>
>> }
>> }
More information about the jdbc-spec-discuss
mailing list