Skip to content

Commit

Permalink
feat: add support for NUMERIC data type (#193)
Browse files Browse the repository at this point in the history
* feat: add support for NUMERIC type

* feat: add support for NUMERIC in keys

* tests: add integration test for numeric

* fix: uncomment code

* test: remove integration tests from PR

* chore: remove whitespaces

* chore: solve merge conflicts
  • Loading branch information
olavloite committed Jul 15, 2020
1 parent d67f108 commit b38a91d
Show file tree
Hide file tree
Showing 29 changed files with 990 additions and 36 deletions.
44 changes: 43 additions & 1 deletion google-cloud-spanner/clirr-ignored-differences.xml
Expand Up @@ -256,11 +256,53 @@
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
<method>com.google.api.gax.retrying.RetrySettings getPartitionedDmlRetrySettings()</method>
</difference>

<!-- Streaming PDML -->
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
<method>com.google.api.gax.rpc.ServerStream executeStreamingPartitionedDml(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, org.threeten.bp.Duration)</method>
</difference>

<!-- Add support for NUMERIC data type -->
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/AbstractStructReader</className>
<method>java.math.BigDecimal getBigDecimalInternal(int)</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/AbstractStructReader</className>
<method>java.util.List getBigDecimalListInternal(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.math.BigDecimal getBigDecimal(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.math.BigDecimal getBigDecimal(java.lang.String)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.util.List getBigDecimalList(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.util.List getBigDecimalList(java.lang.String)</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/Value</className>
<method>java.math.BigDecimal getNumeric()</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/Value</className>
<method>java.util.List getNumericArray()</method>
</difference>
</differences>
Expand Up @@ -52,6 +52,7 @@
import io.opencensus.trace.Tracing;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.BitSet;
Expand Down Expand Up @@ -358,6 +359,9 @@ private Object writeReplace() {
case FLOAT64:
builder.set(fieldName).to((Double) value);
break;
case NUMERIC:
builder.set(fieldName).to((BigDecimal) value);
break;
case STRING:
builder.set(fieldName).to((String) value);
break;
Expand All @@ -381,6 +385,9 @@ private Object writeReplace() {
case FLOAT64:
builder.set(fieldName).toFloat64Array((Iterable<Double>) value);
break;
case NUMERIC:
builder.set(fieldName).toNumericArray((Iterable<BigDecimal>) value);
break;
case STRING:
builder.set(fieldName).toStringArray((Iterable<String>) value);
break;
Expand Down Expand Up @@ -457,6 +464,8 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
return Long.parseLong(proto.getStringValue());
case FLOAT64:
return valueProtoToFloat64(proto);
case NUMERIC:
return new BigDecimal(proto.getStringValue());
case STRING:
checkType(fieldType, proto, KindCase.STRING_VALUE);
return proto.getStringValue();
Expand Down Expand Up @@ -513,6 +522,18 @@ public Boolean apply(com.google.protobuf.Value input) {
return new Int64Array(listValue);
case FLOAT64:
return new Float64Array(listValue);
case NUMERIC:
{
// Materialize list: element conversion is expensive and should happen only once.
ArrayList<Object> list = new ArrayList<>(listValue.getValuesCount());
for (com.google.protobuf.Value value : listValue.getValuesList()) {
list.add(
value.getKindCase() == KindCase.NULL_VALUE
? null
: new BigDecimal(value.getStringValue()));
}
return list;
}
case STRING:
return Lists.transform(
listValue.getValuesList(),
Expand Down Expand Up @@ -620,6 +641,11 @@ protected double getDoubleInternal(int columnIndex) {
return (Double) rowData.get(columnIndex);
}

@Override
protected BigDecimal getBigDecimalInternal(int columnIndex) {
return (BigDecimal) rowData.get(columnIndex);
}

@Override
protected String getStringInternal(int columnIndex) {
return (String) rowData.get(columnIndex);
Expand Down Expand Up @@ -685,6 +711,12 @@ protected Float64Array getDoubleListInternal(int columnIndex) {
return (Float64Array) rowData.get(columnIndex);
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<NUMERIC> produces a List<BigDecimal>.
protected List<BigDecimal> getBigDecimalListInternal(int columnIndex) {
return (List<BigDecimal>) rowData.get(columnIndex);
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<STRING> produces a List<String>.
protected List<String> getStringListInternal(int columnIndex) {
Expand Down Expand Up @@ -1176,6 +1208,11 @@ protected double getDoubleInternal(int columnIndex) {
return currRow().getDoubleInternal(columnIndex);
}

@Override
protected BigDecimal getBigDecimalInternal(int columnIndex) {
return currRow().getBigDecimalInternal(columnIndex);
}

@Override
protected String getStringInternal(int columnIndex) {
return currRow().getStringInternal(columnIndex);
Expand Down Expand Up @@ -1226,6 +1263,11 @@ protected List<Double> getDoubleListInternal(int columnIndex) {
return currRow().getDoubleListInternal(columnIndex);
}

@Override
protected List<BigDecimal> getBigDecimalListInternal(int columnIndex) {
return currRow().getBigDecimalListInternal(columnIndex);
}

@Override
protected List<String> getStringListInternal(int columnIndex) {
return currRow().getStringListInternal(columnIndex);
Expand Down
Expand Up @@ -21,6 +21,7 @@
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
import com.google.cloud.Timestamp;
import java.math.BigDecimal;
import java.util.List;

/**
Expand All @@ -38,6 +39,8 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract double getDoubleInternal(int columnIndex);

protected abstract BigDecimal getBigDecimalInternal(int columnIndex);

protected abstract String getStringInternal(int columnIndex);

protected abstract ByteArray getBytesInternal(int columnIndex);
Expand All @@ -58,6 +61,8 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract List<Double> getDoubleListInternal(int columnIndex);

protected abstract List<BigDecimal> getBigDecimalListInternal(int columnIndex);

protected abstract List<String> getStringListInternal(int columnIndex);

protected abstract List<ByteArray> getBytesListInternal(int columnIndex);
Expand Down Expand Up @@ -127,6 +132,19 @@ public double getDouble(String columnName) {
return getDoubleInternal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
checkNonNullOfType(columnIndex, Type.numeric(), columnIndex);
return getBigDecimalInternal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.numeric(), columnName);
return getBigDecimalInternal(columnIndex);
}

@Override
public String getString(int columnIndex) {
checkNonNullOfType(columnIndex, Type.string(), columnIndex);
Expand Down Expand Up @@ -257,6 +275,19 @@ public List<Double> getDoubleList(String columnName) {
return getDoubleListInternal(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnIndex);
return getBigDecimalListInternal(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnName);
return getBigDecimalListInternal(columnIndex);
}

@Override
public List<String> getStringList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.string()), columnIndex);
Expand Down
Expand Up @@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import java.math.BigDecimal;
import java.util.List;

/** Forwarding implements of StructReader */
Expand Down Expand Up @@ -133,6 +134,16 @@ public double getDouble(String columnName) {
return delegate.get().getDouble(columnName);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
return delegate.get().getBigDecimal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
return delegate.get().getBigDecimal(columnName);
}

@Override
public String getString(int columnIndex) {
checkValidState();
Expand Down Expand Up @@ -253,6 +264,16 @@ public List<Double> getDoubleList(String columnName) {
return delegate.get().getDoubleList(columnName);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
return delegate.get().getBigDecimalList(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
return delegate.get().getBigDecimalList(columnName);
}

@Override
public List<String> getStringList(int columnIndex) {
checkValidState();
Expand Down
Expand Up @@ -26,6 +26,7 @@
import com.google.protobuf.NullValue;
import com.google.protobuf.Value;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -131,6 +132,11 @@ public Builder append(@Nullable Double value) {
buffer.add(value);
return this;
}
/** Appends a {@code NUMERIC} value to the key. */
public Builder append(@Nullable BigDecimal value) {
buffer.add(value);
return this;
}
/** Appends a {@code STRING} value to the key. */
public Builder append(@Nullable String value) {
buffer.add(value);
Expand Down Expand Up @@ -172,6 +178,8 @@ public Builder appendObject(@Nullable Object value) {
append((Float) value);
} else if (value instanceof Double) {
append((Double) value);
} else if (value instanceof BigDecimal) {
append((BigDecimal) value);
} else if (value instanceof String) {
append((String) value);
} else if (value instanceof ByteArray) {
Expand Down Expand Up @@ -215,6 +223,7 @@ public int size() {
* <li>{@code BOOL} is represented by {@code Boolean}
* <li>{@code INT64} is represented by {@code Long}
* <li>{@code FLOAT64} is represented by {@code Double}
* <li>{@code NUMERIC} is represented by {@code BigDecimal}
* <li>{@code STRING} is represented by {@code String}
* <li>{@code BYTES} is represented by {@link ByteArray}
* <li>{@code TIMESTAMP} is represented by {@link Timestamp}
Expand Down Expand Up @@ -276,6 +285,8 @@ ListValue toProto() {
builder.addValuesBuilder().setStringValue(part.toString());
} else if (part instanceof Double) {
builder.addValuesBuilder().setNumberValue((Double) part);
} else if (part instanceof BigDecimal) {
builder.addValuesBuilder().setStringValue(part.toString());
} else if (part instanceof String) {
builder.addValuesBuilder().setStringValue((String) part);
} else if (part instanceof ByteArray) {
Expand Down
Expand Up @@ -27,6 +27,7 @@
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.spanner.v1.ResultSetStats;
import java.math.BigDecimal;
import java.util.List;

/** Utility methods for working with {@link com.google.cloud.spanner.ResultSet}. */
Expand Down Expand Up @@ -186,6 +187,16 @@ public double getDouble(String columnName) {
return getCurrentRowAsStruct().getDouble(columnName);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
return getCurrentRowAsStruct().getBigDecimal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
return getCurrentRowAsStruct().getBigDecimal(columnName);
}

@Override
public String getString(int columnIndex) {
return getCurrentRowAsStruct().getString(columnIndex);
Expand Down Expand Up @@ -286,6 +297,16 @@ public List<Double> getDoubleList(String columnName) {
return getCurrentRowAsStruct().getDoubleList(columnName);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
return getCurrentRowAsStruct().getBigDecimalList(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
return getCurrentRowAsStruct().getBigDecimalList(columnName);
}

@Override
public List<String> getStringList(int columnIndex) {
return getCurrentRowAsStruct().getStringList(columnIndex);
Expand Down

0 comments on commit b38a91d

Please sign in to comment.