Skip to content
Permalink
Browse files
feat: adds getValue to ResultSet (#1073)
* feat: adds getValue method to result set

Adds a generic getValue method to the result set. It can be used to
retrieve any type from the database.

* feat: removes custom int64 and float64 arrays

* feat: fixes clirr checks

Clirr does not support java 8 default implementations, so it thinks this
are breaking changes. These in fact are not breaking changes, since we
provide implementations in the interfaces.

* test: fixes GrpcResultSet serialize test

* feat: implements getValueInternal in result set

Adds a less intrusive implementation of getValueInternal for the
AbstractResultSet.

* fix: fixes struct value decoding

Uses the correct type for decoding structs from the result set

* feat: makes the structArray method public

Makes it public the method  to retrieve an array of structs from a Value

* test: adds tests for value literals

* feat: accepts null in arrays for getValue

* feat: allows nulls in values from result sets

* docs: fixes java doc for getValue
  • Loading branch information
thiagotnunes committed Apr 25, 2021
1 parent 24fd309 commit 7792c9085a6e4ce1fb9fe2f8df4279f30539d87e
@@ -592,4 +592,17 @@
<className>com/google/cloud/spanner/AsyncTransactionManager$CommitTimestampFuture</className>
<method>java.lang.Object get()</method>
</difference>

<!-- Adds getValue to ResultSet -->
<!-- These are not breaking changes, since we provide default interface implementation -->
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>com.google.cloud.spanner.Value getValue(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>com.google.cloud.spanner.Value getValue(java.lang.String)</method>
</difference>
</differences>
@@ -28,6 +28,7 @@
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.Type.StructField;
import com.google.cloud.spanner.spi.v1.SpannerRpc;
import com.google.cloud.spanner.v1.stub.SpannerStubSettings;
import com.google.common.annotations.VisibleForTesting;
@@ -679,6 +680,62 @@ protected Date getDateInternal(int columnIndex) {
return (Date) rowData.get(columnIndex);
}

@Override
protected Value getValueInternal(int columnIndex) {
final List<Type.StructField> structFields = getType().getStructFields();
final StructField structField = structFields.get(columnIndex);
final Type columnType = structField.getType();
final boolean isNull = rowData.get(columnIndex) == null;
switch (columnType.getCode()) {
case BOOL:
return Value.bool(isNull ? null : getBooleanInternal(columnIndex));
case INT64:
return Value.int64(isNull ? null : getLongInternal(columnIndex));
case NUMERIC:
return Value.numeric(isNull ? null : getBigDecimalInternal(columnIndex));
case FLOAT64:
return Value.float64(isNull ? null : getDoubleInternal(columnIndex));
case STRING:
return Value.string(isNull ? null : getStringInternal(columnIndex));
case BYTES:
return Value.bytes(isNull ? null : getBytesInternal(columnIndex));
case TIMESTAMP:
return Value.timestamp(isNull ? null : getTimestampInternal(columnIndex));
case DATE:
return Value.date(isNull ? null : getDateInternal(columnIndex));
case STRUCT:
return Value.struct(isNull ? null : getStructInternal(columnIndex));
case ARRAY:
switch (columnType.getArrayElementType().getCode()) {
case BOOL:
return Value.boolArray(isNull ? null : getBooleanListInternal(columnIndex));
case INT64:
return Value.int64Array(isNull ? null : getLongListInternal(columnIndex));
case NUMERIC:
return Value.numericArray(isNull ? null : getBigDecimalListInternal(columnIndex));
case FLOAT64:
return Value.float64Array(isNull ? null : getDoubleListInternal(columnIndex));
case STRING:
return Value.stringArray(isNull ? null : getStringListInternal(columnIndex));
case BYTES:
return Value.bytesArray(isNull ? null : getBytesListInternal(columnIndex));
case TIMESTAMP:
return Value.timestampArray(isNull ? null : getTimestampListInternal(columnIndex));
case DATE:
return Value.dateArray(isNull ? null : getDateListInternal(columnIndex));
case STRUCT:
return Value.structArray(
columnType.getArrayElementType(),
isNull ? null : getStructListInternal(columnIndex));
default:
throw new IllegalArgumentException(
"Invalid array value type " + this.type.getArrayElementType());
}
default:
throw new IllegalArgumentException("Invalid value type " + this.type);
}
}

@Override
protected Struct getStructInternal(int columnIndex) {
return (Struct) rowData.get(columnIndex);
@@ -1280,6 +1337,11 @@ protected Date getDateInternal(int columnIndex) {
return currRow().getDateInternal(columnIndex);
}

@Override
protected Value getValueInternal(int columnIndex) {
return currRow().getValueInternal(columnIndex);
}

@Override
protected boolean[] getBooleanArrayInternal(int columnIndex) {
return currRow().getBooleanArrayInternal(columnIndex);
@@ -49,6 +49,10 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract Date getDateInternal(int columnIndex);

protected Value getValueInternal(int columnIndex) {
throw new UnsupportedOperationException("method should be overwritten");
}

protected abstract boolean[] getBooleanArrayInternal(int columnIndex);

protected abstract List<Boolean> getBooleanListInternal(int columnIndex);
@@ -197,6 +201,18 @@ public Date getDate(String columnName) {
return getDateInternal(columnIndex);
}

@Override
public Value getValue(int columnIndex) {
checkNonNull(columnIndex, columnIndex);
return getValueInternal(columnIndex);
}

@Override
public Value getValue(String columnName) {
int columnIndex = getColumnIndex(columnName);
return getValueInternal(columnIndex);
}

@Override
public boolean[] getBooleanArray(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.bool()), columnIndex);
@@ -333,4 +333,16 @@ public List<Struct> getStructList(String columnName) {
checkValidState();
return delegate.get().getStructList(columnName);
}

@Override
public Value getValue(int columnIndex) {
checkValidState();
return delegate.get().getValue(columnIndex);
}

@Override
public Value getValue(String columnName) {
checkValidState();
return delegate.get().getValue(columnName);
}
}
@@ -273,6 +273,16 @@ public Date getDate(String columnName) {
return getCurrentRowAsStruct().getDate(columnName);
}

@Override
public Value getValue(int columnIndex) {
return getCurrentRowAsStruct().getValue(columnIndex);
}

@Override
public Value getValue(String columnName) {
return getCurrentRowAsStruct().getValue(columnName);
}

@Override
public boolean[] getBooleanArray(int columnIndex) {
return getCurrentRowAsStruct().getBooleanArray(columnIndex);
@@ -207,6 +207,11 @@ protected Date getDateInternal(int columnIndex) {
return values.get(columnIndex).getDate();
}

@Override
protected Value getValueInternal(int columnIndex) {
return values.get(columnIndex);
}

@Override
protected Struct getStructInternal(int columnIndex) {
return values.get(columnIndex).getStruct();
@@ -132,6 +132,16 @@ public interface StructReader {
/** Returns the value of a non-{@code NULL} column with type {@link Type#date()}. */
Date getDate(String columnName);

/** Returns the value of a nullable column as a {@link Value}. */
default Value getValue(int columnIndex) {
throw new UnsupportedOperationException("method should be overwritten");
}

/** Returns the value of a nullable column as a {@link Value}. */
default Value getValue(String columnName) {
throw new UnsupportedOperationException("method should be overwritten");
}

/**
* Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bool())}.
*
@@ -543,7 +543,7 @@ private Value() {}
*
* @throws IllegalStateException if {@code isNull()} or the value is not of the expected type
*/
abstract List<Struct> getStructArray();
public abstract List<Struct> getStructArray();

@Override
public String toString() {
@@ -23,6 +23,7 @@
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.Struct;
import com.google.cloud.spanner.Type;
import com.google.cloud.spanner.Value;
import com.google.common.base.Preconditions;
import com.google.spanner.v1.ResultSetStats;
import java.math.BigDecimal;
@@ -231,6 +232,18 @@ public Date getDate(String columnName) {
return delegate.getDate(columnName);
}

@Override
public Value getValue(int columnIndex) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
return delegate.getValue(columnIndex);
}

@Override
public Value getValue(String columnName) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
return delegate.getValue(columnName);
}

@Override
public boolean[] getBooleanArray(int columnIndex) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
@@ -25,6 +25,7 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.Struct;
import com.google.cloud.spanner.Type;
import com.google.cloud.spanner.Value;
import com.google.common.base.Preconditions;
import com.google.spanner.v1.ResultSetStats;
import java.math.BigDecimal;
@@ -231,6 +232,18 @@ public Date getDate(String columnName) {
return delegate.getDate(columnName);
}

@Override
public Value getValue(int columnIndex) {
checkClosed();
return delegate.getValue(columnIndex);
}

@Override
public Value getValue(String columnName) {
checkClosed();
return delegate.getValue(columnName);
}

@Override
public boolean[] getBooleanArray(int columnIndex) {
checkClosed();

0 comments on commit 7792c90

Please sign in to comment.