Merge pull request #1572 from youtube/caseInsensitiveMap

Case Insensitive Map for getting Column Index
This commit is contained in:
Anthony Yeh 2016-04-04 15:13:36 -07:00
Родитель b423c73ce6 39ec949e15
Коммит 6b7efe52ef
4 изменённых файлов: 83 добавлений и 13 удалений

Просмотреть файл

@ -20,6 +20,11 @@
<artifactId>jsr305</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
</dependencies>
<pluginRepositories>

Просмотреть файл

@ -4,10 +4,11 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.youtube.vitess.proto.Query.Field;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import java.util.List;
import java.util.Map;
@ -16,6 +17,9 @@ import javax.annotation.Nullable;
/**
* A wrapper for {@code List<Field>} that also facilitates lookup by field name.
*
* <p>Lookups by field name are case-insensitive, as in {@link java.sql.ResultSet}.
* If multiple fields have the same name, the earliest one will be returned.
*
* <p>The field name maps to an index, rather than a Field, because that same
* index is also used to find the value in a separate list.
*/
@ -26,25 +30,43 @@ public class FieldMap {
public FieldMap(Iterable<Field> fields) {
this.fields = ImmutableList.copyOf(checkNotNull(fields));
ImmutableMap.Builder<String, Integer> builder = new ImmutableMap.Builder<>();
indexMap = new CaseInsensitiveMap<String, Integer>();
// columnIndex is 1-based.
int columnIndex = 1;
for (Field field : this.fields) {
builder.put(field.getName(), columnIndex++);
String columnLabel = field.getName();
// If multiple columns have the same name,
// prefer the earlier one as JDBC ResultSet does.
if (!indexMap.containsKey(columnLabel)) {
indexMap.put(columnLabel, columnIndex);
}
++columnIndex;
}
indexMap = builder.build();
}
public List<Field> getList() {
return fields;
}
/**
* Returns the {@link Field} for a 1-based column index.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
public Field get(int columnIndex) {
// columnIndex is 1-based.
checkArgument(columnIndex >= 1, "columnIndex out of range: %s", columnIndex);
return fields.get(columnIndex - 1);
}
/**
* Returns the 1-based index for a column label.
*
* <p>If multiple columns have the same label,
* the earlier one is returned.
*
* @param columnLabel case-insensitive column label
*/
@Nullable
public Integer getIndex(String columnLabel) {
return indexMap.get(columnLabel);

Просмотреть файл

@ -33,10 +33,12 @@ import javax.annotation.concurrent.NotThreadSafe;
* the list of {@link Field}s from the corresponding
* {@link com.youtube.vitess.proto.Query.QueryResult}.
*
* <p>Note that {@code columnIndex} values start at 1 for the first column,
* since the methods on {@code Row} are intended to be compatible with those
* on {@link java.sql.ResultSet} (which uses 1-based {@code columnIndex})
* where possible.
* <p>Methods on {@code Row} are intended to be compatible with those on
* {@link java.sql.ResultSet} where possible.
* This means {@code columnIndex} values start at 1 for the first column,
* and {@code columnLabel} values are case-insensitive. If multiple columns
* have the same case-insensitive {@code columnLabel}, the earliest one will
* be returned.
*/
@NotThreadSafe
public class Row {
@ -115,6 +117,8 @@ public class Row {
/**
* Returns 1-based column number.
*
* @param columnLabel case-insensitive column label
*/
public int findColumn(String columnLabel) throws SQLException {
Integer columnIndex = fieldMap.getIndex(columnLabel);
@ -124,6 +128,9 @@ public class Row {
return columnIndex;
}
/**
* @param columnLabel case-insensitive column label
*/
public Object getObject(String columnLabel) throws SQLException {
return getObject(findColumn(columnLabel));
}
@ -161,6 +168,8 @@ public class Row {
*
* <p>To distinguish between 0 and SQL NULL, use either {@link #wasNull()}
* or {@link #getObject(String,Class)}.
*
* @param columnLabel case-insensitive column label
*/
public int getInt(String columnLabel) throws SQLException {
return getInt(findColumn(columnLabel));
@ -179,6 +188,9 @@ public class Row {
return value == null ? 0 : value;
}
/**
* @param columnLabel case-insensitive column label
*/
public UnsignedLong getULong(String columnLabel) throws SQLException {
return getULong(findColumn(columnLabel));
}
@ -190,6 +202,9 @@ public class Row {
return getObject(columnIndex, UnsignedLong.class);
}
/**
* @param columnLabel case-insensitive column label
*/
public String getString(String columnLabel) throws SQLException {
return getString(findColumn(columnLabel));
}
@ -206,6 +221,8 @@ public class Row {
*
* <p>To distinguish between 0 and SQL NULL, use either {@link #wasNull()}
* or {@link #getObject(String,Class)}.
*
* @param columnLabel case-insensitive column label
*/
public long getLong(String columnLabel) throws SQLException {
return getLong(findColumn(columnLabel));
@ -229,6 +246,8 @@ public class Row {
*
* <p>To distinguish between 0 and SQL NULL, use either {@link #wasNull()}
* or {@link #getObject(String,Class)}.
*
* @param columnLabel case-insensitive column label
*/
public double getDouble(String columnLabel) throws SQLException {
return getDouble(findColumn(columnLabel));
@ -252,6 +271,8 @@ public class Row {
*
* <p>To distinguish between 0 and SQL NULL, use either {@link #wasNull()}
* or {@link #getObject(String,Class)}.
*
* @param columnLabel case-insensitive column label
*/
public float getFloat(String columnLabel) throws SQLException {
return getFloat(findColumn(columnLabel));
@ -272,6 +293,8 @@ public class Row {
/**
* Returns the column value as a {@link Date} with the default time zone.
*
* @param columnLabel case-insensitive column label
*/
public Date getDate(String columnLabel) throws SQLException {
return getDate(findColumn(columnLabel), Calendar.getInstance());
@ -279,6 +302,8 @@ public class Row {
/**
* Returns the column value as a {@link Date} with the given {@link Calendar}.
*
* @param columnLabel case-insensitive column label
*/
public Date getDate(String columnLabel, Calendar cal) throws SQLException {
return getDate(findColumn(columnLabel), cal);
@ -317,6 +342,8 @@ public class Row {
/**
* Returns the column value as {@link Time} with the default time zone.
*
* @param columnLabel case-insensitive column label
*/
public Time getTime(String columnLabel) throws SQLException {
return getTime(findColumn(columnLabel), Calendar.getInstance());
@ -324,6 +351,8 @@ public class Row {
/**
* Returns the column value as {@link Time} with the given {@link Calendar}.
*
* @param columnLabel case-insensitive column label
*/
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
return getTime(findColumn(columnLabel), cal);
@ -362,6 +391,8 @@ public class Row {
/**
* Returns the column value as {@link Timestamp} with the default time zone.
*
* @param columnLabel case-insensitive column label
*/
public Timestamp getTimestamp(String columnLabel) throws SQLException {
return getTimestamp(findColumn(columnLabel), Calendar.getInstance());
@ -369,6 +400,8 @@ public class Row {
/**
* Returns the column value as {@link Timestamp} with the given {@link Calendar}.
*
* @param columnLabel case-insensitive column label
*/
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
return getTimestamp(findColumn(columnLabel), cal);
@ -410,6 +443,9 @@ public class Row {
}
}
/**
* @param columnLabel case-insensitive column label
*/
public byte[] getBytes(String columnLabel) throws SQLException {
return getBytes(findColumn(columnLabel));
}
@ -421,6 +457,9 @@ public class Row {
return getObject(columnIndex, byte[].class);
}
/**
* @param columnLabel case-insensitive column label
*/
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
return getBigDecimal(findColumn(columnLabel));
}
@ -437,6 +476,8 @@ public class Row {
*
* <p>To distinguish between 0 and SQL NULL, use either {@link #wasNull()}
* or {@link #getObject(String,Class)}.
*
* @param columnLabel case-insensitive column label
*/
public short getShort(String columnLabel) throws SQLException {
return getShort(findColumn(columnLabel));
@ -494,6 +535,7 @@ public class Row {
* }
* </pre></blockquote>
*
* @param columnLabel case-insensitive column label
* @throws SQLDataException if the type doesn't match the actual value.
*/
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {

Просмотреть файл

@ -32,12 +32,13 @@ public class CursorTest {
new SimpleCursor(
QueryResult.newBuilder()
.addFields(Field.newBuilder().setName("col1").build())
.addFields(Field.newBuilder().setName("col2").build())
.addFields(Field.newBuilder().setName("col3").build())
.addFields(Field.newBuilder().setName("COL2").build()) // case-insensitive
.addFields(Field.newBuilder().setName("col1").build()) // duplicate
.addFields(Field.newBuilder().setName("col4").build()) // skip duplicate
.build())) {
Assert.assertEquals(1, cursor.findColumn("col1"));
Assert.assertEquals(2, cursor.findColumn("col2"));
Assert.assertEquals(3, cursor.findColumn("col3"));
Assert.assertEquals(1, cursor.findColumn("col1")); // should return first col1
Assert.assertEquals(2, cursor.findColumn("Col2")); // should be case-insensitive
Assert.assertEquals(4, cursor.findColumn("col4")); // index should skip over duplicate
}
}