Skip to content

Commit 9e35f57

Browse files
committed
test: add interval to AllTypes test and RandomResultSetGenerator
1 parent 84d720c commit 9e35f57

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Interval.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ private static String getNullOrDefault(Matcher matcher, int groupIdx) {
134134
return value == null ? "0" : value;
135135
}
136136

137+
/**
138+
* Parse an {@link Interval} value from ISO8601 interval format-
139+
* `P[n]Y[n]M[n]DT[n]H[n]M[n([.,][fraction])]S`
140+
*/
137141
public static Interval parseFromString(String interval) {
138142
Matcher matcher = INTERVAL_PATTERN.matcher(interval);
139143
if (!matcher.matches()) {

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AllTypesMockServerTest.java

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.cloud.Date;
2323
import com.google.cloud.Timestamp;
2424
import com.google.cloud.spanner.Dialect;
25+
import com.google.cloud.spanner.Interval;
2526
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
2627
import com.google.cloud.spanner.ResultSet;
2728
import com.google.cloud.spanner.SingerProto.Genre;
@@ -35,6 +36,7 @@
3536
import com.google.spanner.v1.Type;
3637
import com.google.spanner.v1.TypeCode;
3738
import java.math.BigDecimal;
39+
import java.math.BigInteger;
3840
import java.nio.charset.StandardCharsets;
3941
import java.util.Arrays;
4042
import java.util.Base64;
@@ -78,6 +80,7 @@ public static Object[] data() {
7880
public static final Date DATE_VALUE = Date.fromYearMonthDay(2024, 3, 2);
7981
public static final Timestamp TIMESTAMP_VALUE =
8082
Timestamp.parseTimestamp("2024-03-02T07:07:00.20982735Z");
83+
public static final Interval INTERVAL_VALUE = Interval.parseFromString("P2Y4M3DT10H1M7.3S");
8184

8285
public static final List<Boolean> BOOL_ARRAY_VALUE = Arrays.asList(true, null, false);
8386
public static final List<Long> INT64_ARRAY_VALUE =
@@ -131,6 +134,13 @@ public static Object[] data() {
131134
Timestamp.parseTimestamp("2024-03-03T07:07:00Z"),
132135
Timestamp.MIN_VALUE,
133136
Timestamp.MAX_VALUE);
137+
public static final List<Interval> INTERVAL_ARRAY_VALUE =
138+
Arrays.asList(
139+
INTERVAL_VALUE,
140+
null,
141+
Interval.fromMonthsDaysNanos(9, 39, BigInteger.TEN),
142+
Interval.fromMonthsDaysNanos(-120000, -3660000, new BigInteger("-316224000000000000000")),
143+
Interval.fromMonthsDaysNanos(120000, 3660000, new BigInteger("316224000000000000000")));
134144

135145
@Before
136146
public void setupDialect() {
@@ -158,14 +168,15 @@ private void setupAllTypesResultSet(Dialect dialect) {
158168
// COL8: BYTES
159169
// COL9: DATE
160170
// COL10: TIMESTAMP
161-
// COL11: PG_OID (added only for POSTGRESQL dialect)
162-
// COL12-21: ARRAY<..> for the types above.
171+
// COL11: INTERVAL
172+
// COL12: PG_OID (added only for POSTGRESQL dialect)
173+
// COL13-22: ARRAY<..> for the types above.
163174
// Only for GoogleSQL:
164-
// COL22: PROTO
165-
// COL23: ENUM
166-
// COL24: ARRAY<PROTO>
167-
// COL25: ARRAY<ENUM>
168-
// COL26: ARRAY<PG_OID> (added only for POSTGRESQL dialect)
175+
// COL23: PROTO
176+
// COL24: ENUM
177+
// COL25: ARRAY<PROTO>
178+
// COL26: ARRAY<ENUM>
179+
// COL27: ARRAY<PG_OID> (added only for POSTGRESQL dialect)
169180
ListValue.Builder row1Builder =
170181
ListValue.newBuilder()
171182
.addValues(Value.newBuilder().setBoolValue(BOOL_VALUE))
@@ -183,7 +194,8 @@ private void setupAllTypesResultSet(Dialect dialect) {
183194
.addValues(
184195
Value.newBuilder().setStringValue(Base64.getEncoder().encodeToString(BYTES_VALUE)))
185196
.addValues(Value.newBuilder().setStringValue(DATE_VALUE.toString()))
186-
.addValues(Value.newBuilder().setStringValue(TIMESTAMP_VALUE.toString()));
197+
.addValues(Value.newBuilder().setStringValue(TIMESTAMP_VALUE.toString()))
198+
.addValues(Value.newBuilder().setStringValue(INTERVAL_VALUE.toString()));
187199
if (dialect == Dialect.POSTGRESQL) {
188200
row1Builder.addValues(
189201
Value.newBuilder().setStringValue(String.valueOf(PG_OID_VALUE)).build());
@@ -372,6 +384,23 @@ private void setupAllTypesResultSet(Dialect dialect) {
372384
.setStringValue(timestamp.toString())
373385
.build())
374386
.collect(Collectors.toList()))
387+
.build()))
388+
.addValues(
389+
Value.newBuilder()
390+
.setListValue(
391+
ListValue.newBuilder()
392+
.addAllValues(
393+
INTERVAL_ARRAY_VALUE.stream()
394+
.map(
395+
interval ->
396+
interval == null
397+
? Value.newBuilder()
398+
.setNullValue(NullValue.NULL_VALUE)
399+
.build()
400+
: Value.newBuilder()
401+
.setStringValue(interval.toISO8601())
402+
.build())
403+
.collect(Collectors.toList()))
375404
.build()));
376405

377406
if (dialect == Dialect.GOOGLE_STANDARD_SQL) {
@@ -509,7 +538,9 @@ public static Statement createInsertStatement(Dialect dialect) {
509538
.bind("p" + ++param)
510539
.to(DATE_VALUE)
511540
.bind("p" + ++param)
512-
.to(TIMESTAMP_VALUE);
541+
.to(TIMESTAMP_VALUE)
542+
.bind("p" + ++param)
543+
.to(INTERVAL_VALUE);
513544
if (dialect == Dialect.POSTGRESQL) {
514545
builder.bind("p" + ++param).to(PG_OID_VALUE);
515546
}
@@ -539,7 +570,9 @@ public static Statement createInsertStatement(Dialect dialect) {
539570
.bind("p" + ++param)
540571
.toDateArray(DATE_ARRAY_VALUE)
541572
.bind("p" + ++param)
542-
.toTimestampArray(TIMESTAMP_ARRAY_VALUE);
573+
.toTimestampArray(TIMESTAMP_ARRAY_VALUE)
574+
.bind("p" + ++param)
575+
.toIntervalArray(INTERVAL_ARRAY_VALUE);
543576
if (dialect == Dialect.POSTGRESQL) {
544577
builder.bind("p" + ++param).toInt64Array(PG_OID_ARRAY_VALUE);
545578
}
@@ -574,6 +607,7 @@ public void testSelectAllTypes() {
574607
assertArrayEquals(BYTES_VALUE, resultSet.getBytes(++col).toByteArray());
575608
assertEquals(DATE_VALUE, resultSet.getDate(++col));
576609
assertEquals(TIMESTAMP_VALUE, resultSet.getTimestamp(++col));
610+
assertEquals(INTERVAL_VALUE, resultSet.getInterval(++col));
577611
if (dialect == Dialect.POSTGRESQL) {
578612
assertEquals(PG_OID_VALUE, resultSet.getLong(++col));
579613
}
@@ -596,6 +630,7 @@ public void testSelectAllTypes() {
596630
assertEquals(BYTES_ARRAY_VALUE, resultSet.getBytesList(++col));
597631
assertEquals(DATE_ARRAY_VALUE, resultSet.getDateList(++col));
598632
assertEquals(TIMESTAMP_ARRAY_VALUE, resultSet.getTimestampList(++col));
633+
assertEquals(INTERVAL_ARRAY_VALUE, resultSet.getIntervalList(++col));
599634
if (dialect == Dialect.POSTGRESQL) {
600635
assertEquals(PG_OID_ARRAY_VALUE, resultSet.getLongList(++col));
601636
}
@@ -613,8 +648,8 @@ public void testInsertAllTypes() {
613648
ExecuteSqlRequest request = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class).get(0);
614649
Map<String, Type> paramTypes = request.getParamTypesMap();
615650
Map<String, Value> params = request.getParams().getFieldsMap();
616-
assertEquals(dialect == Dialect.POSTGRESQL ? 22 : 20, paramTypes.size());
617-
assertEquals(dialect == Dialect.POSTGRESQL ? 22 : 20, params.size());
651+
assertEquals(dialect == Dialect.POSTGRESQL ? 24 : 22, paramTypes.size());
652+
assertEquals(dialect == Dialect.POSTGRESQL ? 24 : 22, params.size());
618653

619654
// Verify param types.
620655
ImmutableList<TypeCode> expectedTypes;
@@ -631,6 +666,7 @@ public void testInsertAllTypes() {
631666
TypeCode.BYTES,
632667
TypeCode.DATE,
633668
TypeCode.TIMESTAMP,
669+
TypeCode.INTERVAL,
634670
TypeCode.INT64);
635671
} else {
636672
expectedTypes =
@@ -644,7 +680,8 @@ public void testInsertAllTypes() {
644680
TypeCode.JSON,
645681
TypeCode.BYTES,
646682
TypeCode.DATE,
647-
TypeCode.TIMESTAMP);
683+
TypeCode.TIMESTAMP,
684+
TypeCode.INTERVAL);
648685
}
649686
for (int col = 0; col < expectedTypes.size(); col++) {
650687
assertEquals(expectedTypes.get(col), paramTypes.get("p" + (col + 1)).getCode());
@@ -671,6 +708,7 @@ public void testInsertAllTypes() {
671708
params.get("p" + ++col).getStringValue());
672709
assertEquals(DATE_VALUE.toString(), params.get("p" + ++col).getStringValue());
673710
assertEquals(TIMESTAMP_VALUE.toString(), params.get("p" + ++col).getStringValue());
711+
assertEquals(INTERVAL_VALUE.toString(), params.get("p" + ++col).getStringValue());
674712
if (dialect == Dialect.POSTGRESQL) {
675713
assertEquals(String.valueOf(PG_OID_VALUE), params.get("p" + ++col).getStringValue());
676714
}
@@ -739,6 +777,15 @@ public void testInsertAllTypes() {
739777
? null
740778
: Timestamp.parseTimestamp(value.getStringValue()))
741779
.collect(Collectors.toList()));
780+
assertEquals(
781+
INTERVAL_ARRAY_VALUE,
782+
params.get("p" + ++col).getListValue().getValuesList().stream()
783+
.map(
784+
value ->
785+
value.hasNullValue()
786+
? null
787+
: Interval.parseFromString(value.getStringValue()))
788+
.collect(Collectors.toList()));
742789
if (dialect == Dialect.POSTGRESQL) {
743790
assertEquals(
744791
PG_OID_ARRAY_VALUE,

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.cloud.Date;
2020
import com.google.cloud.Timestamp;
2121
import com.google.cloud.spanner.Dialect;
22+
import com.google.cloud.spanner.Interval;
2223
import com.google.cloud.spanner.SingerProto.Genre;
2324
import com.google.cloud.spanner.SingerProto.SingerInfo;
2425
import com.google.common.io.BaseEncoding;
@@ -34,6 +35,7 @@
3435
import com.google.spanner.v1.TypeAnnotationCode;
3536
import com.google.spanner.v1.TypeCode;
3637
import java.math.BigDecimal;
38+
import java.math.BigInteger;
3739
import java.math.RoundingMode;
3840
import java.util.ArrayList;
3941
import java.util.Arrays;
@@ -68,7 +70,8 @@ public static Type[] generateAllTypes(Dialect dialect) {
6870
: Type.newBuilder().setCode(TypeCode.JSON).build(),
6971
Type.newBuilder().setCode(TypeCode.BYTES).build(),
7072
Type.newBuilder().setCode(TypeCode.DATE).build(),
71-
Type.newBuilder().setCode(TypeCode.TIMESTAMP).build()));
73+
Type.newBuilder().setCode(TypeCode.TIMESTAMP).build(),
74+
Type.newBuilder().setCode(TypeCode.INTERVAL).build()));
7275
if (dialect == Dialect.POSTGRESQL) {
7376
types.add(
7477
Type.newBuilder()
@@ -127,6 +130,10 @@ public static Type[] generateAllTypes(Dialect dialect) {
127130
Type.newBuilder()
128131
.setCode(TypeCode.ARRAY)
129132
.setArrayElementType(Type.newBuilder().setCode(TypeCode.TIMESTAMP))
133+
.build(),
134+
Type.newBuilder()
135+
.setCode(TypeCode.ARRAY)
136+
.setArrayElementType(Type.newBuilder().setCode(TypeCode.INTERVAL))
130137
.build()));
131138

132139
appendProtoTypes(types, dialect);
@@ -293,6 +300,14 @@ private void setRandomValue(Value.Builder builder, Type type) {
293300
.build());
294301
builder.setStringValue(Timestamp.fromProto(ts).toString());
295302
break;
303+
case INTERVAL:
304+
int months = random.nextInt(120000 * 2) - 120000;
305+
int days = random.nextInt(3660000 * 2) - 3660000;
306+
long nanos = random.nextLong() - random.nextLong();
307+
Interval interval =
308+
Interval.fromMonthsDaysNanos(months, days, new BigInteger(String.valueOf(nanos)));
309+
builder.setStringValue(interval.toISO8601());
310+
break;
296311
case STRUCT:
297312
case TYPE_CODE_UNSPECIFIED:
298313
case UNRECOGNIZED:

0 commit comments

Comments
 (0)