Skip to content

Commit

Permalink
feat: add JSON type support, with integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zoercai committed Jul 1, 2021
1 parent ffc190c commit f6aaa5f
Show file tree
Hide file tree
Showing 28 changed files with 852 additions and 57 deletions.
Expand Up @@ -378,6 +378,9 @@ private Object writeReplace() {
case STRING:
builder.set(fieldName).to((String) value);
break;
case JSON:
builder.set(fieldName).to(Value.json((String) value));
break;
case BYTES:
builder.set(fieldName).to((ByteArray) value);
break;
Expand All @@ -404,6 +407,9 @@ private Object writeReplace() {
case STRING:
builder.set(fieldName).toStringArray((Iterable<String>) value);
break;
case JSON:
builder.set(fieldName).toJsonArray((Iterable<String>) value);
break;
case BYTES:
builder.set(fieldName).toBytesArray((Iterable<ByteArray>) value);
break;
Expand Down Expand Up @@ -480,6 +486,7 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
case NUMERIC:
return new BigDecimal(proto.getStringValue());
case STRING:
case JSON:
checkType(fieldType, proto, KindCase.STRING_VALUE);
return proto.getStringValue();
case BYTES:
Expand Down Expand Up @@ -543,6 +550,7 @@ static Object decodeArrayValue(Type elementType, ListValue listValue) {
return list;
}
case STRING:
case JSON:
return Lists.transform(
listValue.getValuesList(),
input -> input.getKindCase() == KindCase.NULL_VALUE ? null : input.getStringValue());
Expand Down Expand Up @@ -654,6 +662,11 @@ protected String getStringInternal(int columnIndex) {
return (String) rowData.get(columnIndex);
}

@Override
protected String getJsonInternal(int columnIndex) {
return (String) rowData.get(columnIndex);
}

@Override
protected ByteArray getBytesInternal(int columnIndex) {
return (ByteArray) rowData.get(columnIndex);
Expand Down Expand Up @@ -782,6 +795,12 @@ protected List<String> getStringListInternal(int columnIndex) {
return Collections.unmodifiableList((List<String>) rowData.get(columnIndex));
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<String> produces a List<String>.
protected List<String> getJsonListInternal(int columnIndex) {
return Collections.unmodifiableList((List<String>) rowData.get(columnIndex));
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<BYTES> produces a List<ByteArray>.
protected List<ByteArray> getBytesListInternal(int columnIndex) {
Expand Down Expand Up @@ -1308,6 +1327,11 @@ protected String getStringInternal(int columnIndex) {
return currRow().getStringInternal(columnIndex);
}

@Override
protected String getJsonInternal(int columnIndex) {
return currRow().getJsonInternal(columnIndex);
}

@Override
protected ByteArray getBytesInternal(int columnIndex) {
return currRow().getBytesInternal(columnIndex);
Expand Down Expand Up @@ -1368,6 +1392,11 @@ protected List<String> getStringListInternal(int columnIndex) {
return currRow().getStringListInternal(columnIndex);
}

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

@Override
protected List<ByteArray> getBytesListInternal(int columnIndex) {
return currRow().getBytesListInternal(columnIndex);
Expand Down
Expand Up @@ -43,6 +43,8 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract String getStringInternal(int columnIndex);

protected abstract String getJsonInternal(int columnIndex);

protected abstract ByteArray getBytesInternal(int columnIndex);

protected abstract Timestamp getTimestampInternal(int columnIndex);
Expand All @@ -69,6 +71,8 @@ protected Value getValueInternal(int columnIndex) {

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

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

protected abstract List<ByteArray> getBytesListInternal(int columnIndex);

protected abstract List<Timestamp> getTimestampListInternal(int columnIndex);
Expand Down Expand Up @@ -162,6 +166,19 @@ public String getString(String columnName) {
return getStringInternal(columnIndex);
}

@Override
public String getJson(int columnIndex) {
checkNonNullOfType(columnIndex, Type.json(), columnIndex);
return getJsonInternal(columnIndex);
}

@Override
public String getJson(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.json(), columnName);
return getJsonInternal(columnIndex);
}

@Override
public ByteArray getBytes(int columnIndex) {
checkNonNullOfType(columnIndex, Type.bytes(), columnIndex);
Expand Down Expand Up @@ -317,6 +334,19 @@ public List<String> getStringList(String columnName) {
return getStringListInternal(columnIndex);
}

@Override
public List<String> getJsonList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.json()), columnIndex);
return getJsonListInternal(columnIndex);
}

@Override
public List<String> getJsonList(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.array(Type.json()), columnName);
return getJsonListInternal(columnIndex);
}

@Override
public List<ByteArray> getBytesList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.bytes()), columnIndex);
Expand Down
Expand Up @@ -156,6 +156,18 @@ public String getString(String columnName) {
return delegate.get().getString(columnName);
}

@Override
public String getJson(int columnIndex) {
checkValidState();
return delegate.get().getJson(columnIndex);
}

@Override
public String getJson(String columnName) {
checkValidState();
return delegate.get().getJson(columnName);
}

@Override
public ByteArray getBytes(int columnIndex) {
checkValidState();
Expand Down Expand Up @@ -286,6 +298,18 @@ public List<String> getStringList(String columnName) {
return delegate.get().getStringList(columnName);
}

@Override
public List<String> getJsonList(int columnIndex) {
checkValidState();
return delegate.get().getJsonList(columnIndex);
}

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

@Override
public List<ByteArray> getBytesList(int columnIndex) {
checkValidState();
Expand Down
Expand Up @@ -65,6 +65,7 @@ private Key(List<Object> parts) {
* <li>{@code Float}, {@code Double} for the {@code FLOAT64} Cloud Spanner type
* <li>{@code BigDecimal} for the {@code NUMERIC} Cloud Spanner type
* <li>{@code String} for the {@code STRING} Cloud Spanner type
* <li>{@code String} for the {@code JSON} Cloud Spanner type
* <li>{@link ByteArray} for the {@code BYTES} Cloud Spanner type
* <li>{@link Timestamp} for the {@code TIMESTAMP} Cloud Spanner type
* <li>{@link Date} for the {@code DATE} Cloud Spanner type
Expand Down Expand Up @@ -228,6 +229,7 @@ public int size() {
* <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 JSON} is represented by {@code String}
* <li>{@code BYTES} is represented by {@link ByteArray}
* <li>{@code TIMESTAMP} is represented by {@link Timestamp}
* <li>{@code DATE} is represented by {@link Date}
Expand Down
Expand Up @@ -243,6 +243,16 @@ public String getString(String columnName) {
return getCurrentRowAsStruct().getString(columnName);
}

@Override
public String getJson(int columnIndex) {
return getCurrentRowAsStruct().getJson(columnIndex);
}

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

@Override
public ByteArray getBytes(int columnIndex) {
return getCurrentRowAsStruct().getBytes(columnIndex);
Expand Down Expand Up @@ -363,6 +373,16 @@ public List<String> getStringList(String columnName) {
return getCurrentRowAsStruct().getStringList(columnName);
}

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

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

@Override
public List<ByteArray> getBytesList(int columnIndex) {
return getCurrentRowAsStruct().getBytesList(columnIndex);
Expand Down
Expand Up @@ -192,6 +192,11 @@ protected String getStringInternal(int columnIndex) {
return values.get(columnIndex).getString();
}

@Override
protected String getJsonInternal(int columnIndex) {
return values.get(columnIndex).getJson();
}

@Override
protected ByteArray getBytesInternal(int columnIndex) {
return values.get(columnIndex).getBytes();
Expand Down Expand Up @@ -257,6 +262,11 @@ protected List<String> getStringListInternal(int columnIndex) {
return values.get(columnIndex).getStringArray();
}

@Override
protected List<String> getJsonListInternal(int columnIndex) {
return values.get(columnIndex).getJsonArray();
}

@Override
protected List<ByteArray> getBytesListInternal(int columnIndex) {
return values.get(columnIndex).getBytesArray();
Expand Down Expand Up @@ -341,6 +351,8 @@ private Object getAsObject(int columnIndex) {
return getBigDecimalInternal(columnIndex);
case STRING:
return getStringInternal(columnIndex);
case JSON:
return getJsonInternal(columnIndex);
case BYTES:
return getBytesInternal(columnIndex);
case TIMESTAMP:
Expand All @@ -361,6 +373,8 @@ private Object getAsObject(int columnIndex) {
return getBigDecimalListInternal(columnIndex);
case STRING:
return getStringListInternal(columnIndex);
case JSON:
return getJsonListInternal(columnIndex);
case BYTES:
return getBytesListInternal(columnIndex);
case TIMESTAMP:
Expand Down
Expand Up @@ -114,6 +114,12 @@ public interface StructReader {
/** Returns the value of a non-{@code NULL} column with type {@link Type#string()}. */
String getString(String columnName);

/** Returns the value of a non-{@code NULL} column with type {@link Type#string()}. */
String getJson(int columnIndex);

/** Returns the value of a non-{@code NULL} column with type {@link Type#string()}. */
String getJson(String columnName);

/** Returns the value of a non-{@code NULL} column with type {@link Type#bytes()}. */
ByteArray getBytes(int columnIndex);

Expand Down Expand Up @@ -228,6 +234,12 @@ default Value getValue(String columnName) {
/** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. */
List<String> getStringList(String columnName);

/** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. */
List<String> getJsonList(int columnIndex);

/** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. */
List<String> getJsonList(String columnName);

/** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bytes())}. */
List<ByteArray> getBytesList(int columnIndex);

Expand Down
Expand Up @@ -46,6 +46,7 @@ public final class Type implements Serializable {
private static final Type TYPE_FLOAT64 = new Type(Code.FLOAT64, null, null);
private static final Type TYPE_NUMERIC = new Type(Code.NUMERIC, null, null);
private static final Type TYPE_STRING = new Type(Code.STRING, null, null);
private static final Type TYPE_JSON = new Type(Code.JSON, null, null);
private static final Type TYPE_BYTES = new Type(Code.BYTES, null, null);
private static final Type TYPE_TIMESTAMP = new Type(Code.TIMESTAMP, null, null);
private static final Type TYPE_DATE = new Type(Code.DATE, null, null);
Expand All @@ -54,6 +55,7 @@ public final class Type implements Serializable {
private static final Type TYPE_ARRAY_FLOAT64 = new Type(Code.ARRAY, TYPE_FLOAT64, null);
private static final Type TYPE_ARRAY_NUMERIC = new Type(Code.ARRAY, TYPE_NUMERIC, null);
private static final Type TYPE_ARRAY_STRING = new Type(Code.ARRAY, TYPE_STRING, null);
private static final Type TYPE_ARRAY_JSON = new Type(Code.ARRAY, TYPE_JSON, null);
private static final Type TYPE_ARRAY_BYTES = new Type(Code.ARRAY, TYPE_BYTES, null);
private static final Type TYPE_ARRAY_TIMESTAMP = new Type(Code.ARRAY, TYPE_TIMESTAMP, null);
private static final Type TYPE_ARRAY_DATE = new Type(Code.ARRAY, TYPE_DATE, null);
Expand Down Expand Up @@ -94,6 +96,11 @@ public static Type string() {
return TYPE_STRING;
}

/** Returns the descriptor for the {@code JSON} type. */
public static Type json() {
return TYPE_JSON;
}

/** Returns the descriptor for the {@code BYTES} type: a variable-length byte string. */
public static Type bytes() {
return TYPE_BYTES;
Expand Down Expand Up @@ -129,6 +136,8 @@ public static Type array(Type elementType) {
return TYPE_ARRAY_NUMERIC;
case STRING:
return TYPE_ARRAY_STRING;
case JSON:
return TYPE_ARRAY_JSON;
case BYTES:
return TYPE_ARRAY_BYTES;
case TIMESTAMP:
Expand Down Expand Up @@ -182,6 +191,7 @@ public enum Code {
NUMERIC(TypeCode.NUMERIC),
FLOAT64(TypeCode.FLOAT64),
STRING(TypeCode.STRING),
JSON(TypeCode.JSON),
BYTES(TypeCode.BYTES),
TIMESTAMP(TypeCode.TIMESTAMP),
DATE(TypeCode.DATE),
Expand Down Expand Up @@ -394,6 +404,8 @@ static Type fromProto(com.google.spanner.v1.Type proto) {
return numeric();
case STRING:
return string();
case JSON:
return json();
case BYTES:
return bytes();
case TIMESTAMP:
Expand Down

0 comments on commit f6aaa5f

Please sign in to comment.