3939import com .google .cloud .spanner .testing .EmulatorSpannerHelper ;
4040import com .google .cloud .spanner .testing .RemoteSpannerHelper ;
4141import com .google .common .collect .ImmutableList ;
42+ import com .google .protobuf .ListValue ;
4243import com .google .protobuf .NullValue ;
4344import java .util .ArrayList ;
45+ import java .util .Arrays ;
4446import java .util .Collections ;
4547import java .util .List ;
4648import java .util .concurrent .ExecutionException ;
4749import java .util .concurrent .TimeUnit ;
50+ import java .util .stream .Collectors ;
4851import org .junit .AfterClass ;
4952import org .junit .Before ;
5053import org .junit .BeforeClass ;
5659import org .junit .runners .JUnit4 ;
5760import org .threeten .bp .Duration ;
5861
59- // TODO: Re-enable when jsonb is GA.
60- @ Ignore ("Feature is not yet generally available" )
6162@ Category (ParallelIntegrationTest .class )
6263@ RunWith (JUnit4 .class )
6364public class ITPgJsonbTest {
@@ -118,7 +119,9 @@ public void setUp() throws Exception {
118119 instanceId ,
119120 databaseId ,
120121 Collections .singletonList (
121- "CREATE TABLE \" " + tableName + "\" (id BIGINT PRIMARY KEY, col1 JSONB)" ),
122+ "CREATE TABLE \" "
123+ + tableName
124+ + "\" (id BIGINT PRIMARY KEY, col1 JSONB, colarray JSONB[])" ),
122125 null )
123126 .get (OPERATION_TIMEOUT .toMillis (), TimeUnit .MILLISECONDS );
124127 }
@@ -181,6 +184,8 @@ public void testPgJsonbInSecondaryIndex() {
181184 + " {\" color\" :\" green\" ,\" value\" :\" #0f0\" },"
182185 + " {\" color\" :\" blue\" ,\" value\" :\" #00f\" }"
183186 + "]" ;
187+ private static final List <String > JSON_ARRAY1 = Arrays .asList (JSON_VALUE_1 , JSON_VALUE_2 );
188+ private static final List <String > JSON_ARRAY2 = Arrays .asList ("[]" , "{}" );
184189
185190 @ Test
186191 public void testLiteralPgJsonb () {
@@ -192,18 +197,24 @@ public void testLiteralPgJsonb() {
192197 transaction -> {
193198 transaction .executeUpdate (
194199 Statement .of (
195- "INSERT INTO "
196- + tableName
197- + " (id, col1) VALUES"
198- + " (1, '"
199- + JSON_VALUE_1
200- + "')"
201- + ", (2, '"
202- + JSON_VALUE_2
203- + "')"
204- + ", (3, '{}')"
205- + ", (4, '[]')"
206- + ", (5, null)" ));
200+ String .format (
201+ "INSERT INTO %s (id, col1, colarray) VALUES "
202+ + "(1, '%s', array[%s]::jsonb[]), "
203+ + "(2, '%s', array[%s]::jsonb[]), "
204+ + "(3, '{}', array['{}']::jsonb[]), "
205+ + "(4, '[]', array['[]']::jsonb[]), "
206+ + "(5, null, null)" ,
207+ tableName ,
208+ JSON_VALUE_1 ,
209+ // Convert array into string with literals separated by comma
210+ // [a, b, c, null] -> 'a','b','c',null
211+ JSON_ARRAY1 .stream ()
212+ .map (item -> (item == null ? null : "'" + item + "'" ))
213+ .collect (Collectors .joining ("," )),
214+ JSON_VALUE_2 ,
215+ JSON_ARRAY2 .stream ()
216+ .map (item -> (item == null ? null : "'" + item + "'" ))
217+ .collect (Collectors .joining ("," )))));
207218 return null ;
208219 });
209220
@@ -222,29 +233,48 @@ public void testPgJsonbParameter() {
222233 Statement .newBuilder (
223234 "INSERT INTO "
224235 + tableName
225- + " (id, col1) VALUES"
226- + " (1, $1)"
227- + ", (2, $2 )"
228- + ", (3, $3 )"
229- + ", (4, $4 )"
230- + ", (5, $5 )" )
236+ + " (id, col1, colarray ) VALUES"
237+ + " (1, $1, $2 )"
238+ + ", (2, $3, $4 )"
239+ + ", (3, $5, $6 )"
240+ + ", (4, $7, $8 )"
241+ + ", (5, $9, $10 )" )
231242 .bind ("p1" )
232243 .to (Value .pgJsonb (JSON_VALUE_1 ))
233244 .bind ("p2" )
234- .to (Value .pgJsonb ( JSON_VALUE_2 ))
245+ .to (Value .pgJsonbArray ( JSON_ARRAY1 ))
235246 .bind ("p3" )
236- .to (Value .pgJsonb ("{}" ))
247+ .to (Value .pgJsonb (JSON_VALUE_2 ))
237248 .bind ("p4" )
238- .to (Value .pgJsonb ( "[]" ))
249+ .to (Value .pgJsonbArray ( JSON_ARRAY2 ))
239250 .bind ("p5" )
251+ .to (Value .pgJsonb ("{}" ))
252+ .bind ("p6" )
253+ .to (Value .pgJsonbArray (Collections .singletonList ("{}" )))
254+ .bind ("p7" )
255+ .to (Value .pgJsonb ("[]" ))
256+ .bind ("p8" )
257+ .to (Value .pgJsonbArray (Collections .singletonList ("[]" )))
258+ .bind ("p9" )
240259 .to (Value .pgJsonb (null ))
260+ .bind ("p10" )
261+ .to (Value .pgJsonbArray (null ))
241262 .build ());
242263 return null ;
243264 });
244265
245266 verifyContents ();
246267 }
247268
269+ private ListValue getJsonListValue (List <String > jsonList ) {
270+ return ListValue .newBuilder ()
271+ .addAllValues (
272+ jsonList .stream ()
273+ .map (json -> com .google .protobuf .Value .newBuilder ().setStringValue (json ).build ())
274+ .collect (Collectors .toList ()))
275+ .build ();
276+ }
277+
248278 @ Ignore ("Untyped jsonb parameters are not yet supported" )
249279 @ Test
250280 public void testPgJsonbUntypedParameter () {
@@ -261,12 +291,12 @@ public void testPgJsonbUntypedParameter() {
261291 Statement .newBuilder (
262292 "INSERT INTO "
263293 + tableName
264- + " (id, col1) VALUES"
265- + " (1, $1)"
266- + ", (2, $2 )"
267- + ", (3, $3 )"
268- + ", (4, $4 )"
269- + ", (5, $5 )" )
294+ + " (id, col1, colarray ) VALUES"
295+ + " (1, $1, $2 )"
296+ + ", (2, $3, $4 )"
297+ + ", (3, $5, $6 )"
298+ + ", (4, $7, $8 )"
299+ + ", (5, $9, $10 )" )
270300 .bind ("p1" )
271301 .to (
272302 Value .untyped (
@@ -277,17 +307,47 @@ public void testPgJsonbUntypedParameter() {
277307 .to (
278308 Value .untyped (
279309 com .google .protobuf .Value .newBuilder ()
280- .setStringValue ( JSON_VALUE_2 )
310+ .setListValue ( getJsonListValue ( JSON_ARRAY1 ) )
281311 .build ()))
282312 .bind ("p3" )
283313 .to (
284314 Value .untyped (
285- com .google .protobuf .Value .newBuilder ().setStringValue ("{}" ).build ()))
315+ com .google .protobuf .Value .newBuilder ()
316+ .setStringValue (JSON_VALUE_2 )
317+ .build ()))
286318 .bind ("p4" )
287319 .to (
288320 Value .untyped (
289- com .google .protobuf .Value .newBuilder ().setStringValue ("[]" ).build ()))
321+ com .google .protobuf .Value .newBuilder ()
322+ .setListValue (getJsonListValue (JSON_ARRAY2 ))
323+ .build ()))
290324 .bind ("p5" )
325+ .to (
326+ Value .untyped (
327+ com .google .protobuf .Value .newBuilder ().setStringValue ("{}" ).build ()))
328+ .bind ("p6" )
329+ .to (
330+ Value .untyped (
331+ com .google .protobuf .Value .newBuilder ()
332+ .setListValue (getJsonListValue (Collections .singletonList ("{}" )))
333+ .build ()))
334+ .bind ("p7" )
335+ .to (
336+ Value .untyped (
337+ com .google .protobuf .Value .newBuilder ().setStringValue ("[]" ).build ()))
338+ .bind ("p8" )
339+ .to (
340+ Value .untyped (
341+ com .google .protobuf .Value .newBuilder ()
342+ .setListValue (getJsonListValue (Collections .singletonList ("[]" )))
343+ .build ()))
344+ .bind ("p9" )
345+ .to (
346+ Value .untyped (
347+ com .google .protobuf .Value .newBuilder ()
348+ .setNullValue (NullValue .NULL_VALUE )
349+ .build ()))
350+ .bind ("p10" )
291351 .to (
292352 Value .untyped (
293353 com .google .protobuf .Value .newBuilder ()
@@ -315,30 +375,40 @@ public void testMutationsWithPgJsonbAsString() {
315375 .to (1 )
316376 .set ("col1" )
317377 .to (JSON_VALUE_1 )
378+ .set ("colarray" )
379+ .to (Value .pgJsonbArray (JSON_ARRAY1 ))
318380 .build (),
319381 Mutation .newInsertBuilder (tableName )
320382 .set ("id" )
321383 .to (2 )
322384 .set ("col1" )
323385 .to (JSON_VALUE_2 )
386+ .set ("colarray" )
387+ .to (Value .pgJsonbArray (JSON_ARRAY2 ))
324388 .build (),
325389 Mutation .newInsertBuilder (tableName )
326390 .set ("id" )
327391 .to (3 )
328392 .set ("col1" )
329393 .to ("{}" )
394+ .set ("colarray" )
395+ .to (Value .pgJsonbArray (Collections .singletonList ("{}" )))
330396 .build (),
331397 Mutation .newInsertBuilder (tableName )
332398 .set ("id" )
333399 .to (4 )
334400 .set ("col1" )
335401 .to ("[]" )
402+ .set ("colarray" )
403+ .to (Value .pgJsonbArray (Collections .singletonList ("[]" )))
336404 .build (),
337405 Mutation .newInsertBuilder (tableName )
338406 .set ("id" )
339407 .to (5 )
340408 .set ("col1" )
341409 .to ((String ) null )
410+ .set ("colarray" )
411+ .to (Value .pgJsonbArray (null ))
342412 .build ()));
343413 return null ;
344414 });
@@ -361,30 +431,40 @@ public void testMutationsWithPgJsonbAsValue() {
361431 .to (1 )
362432 .set ("col1" )
363433 .to (Value .pgJsonb (JSON_VALUE_1 ))
434+ .set ("colarray" )
435+ .to (Value .pgJsonbArray (JSON_ARRAY1 ))
364436 .build (),
365437 Mutation .newInsertBuilder (tableName )
366438 .set ("id" )
367439 .to (2 )
368440 .set ("col1" )
369441 .to (Value .pgJsonb (JSON_VALUE_2 ))
442+ .set ("colarray" )
443+ .to (Value .pgJsonbArray (JSON_ARRAY2 ))
370444 .build (),
371445 Mutation .newInsertBuilder (tableName )
372446 .set ("id" )
373447 .to (3 )
374448 .set ("col1" )
375449 .to (Value .pgJsonb ("{}" ))
450+ .set ("colarray" )
451+ .to (Value .pgJsonbArray (Collections .singletonList ("{}" )))
376452 .build (),
377453 Mutation .newInsertBuilder (tableName )
378454 .set ("id" )
379455 .to (4 )
380456 .set ("col1" )
381457 .to (Value .pgJsonb ("[]" ))
458+ .set ("colarray" )
459+ .to (Value .pgJsonbArray (Collections .singletonList ("[]" )))
382460 .build (),
383461 Mutation .newInsertBuilder (tableName )
384462 .set ("id" )
385463 .to (5 )
386464 .set ("col1" )
387465 .to (Value .pgJsonb (null ))
466+ .set ("colarray" )
467+ .to (Value .pgJsonbArray (null ))
388468 .build ()));
389469 return null ;
390470 });
@@ -405,6 +485,21 @@ private void verifyContents() {
405485 assertEquals ("{\" color\" : \" red\" , \" value\" : \" #f00\" }" , resultSet .getPgJsonb ("col1" ));
406486 assertEquals (
407487 Value .pgJsonb ("{\" color\" : \" red\" , \" value\" : \" #f00\" }" ), resultSet .getValue ("col1" ));
488+ assertEquals (
489+ Arrays .asList (
490+ "{\" color\" : \" red\" , \" value\" : \" #f00\" }" ,
491+ "[{\" color\" : \" red\" , \" value\" : \" #f00\" }, "
492+ + "{\" color\" : \" green\" , \" value\" : \" #0f0\" }, "
493+ + "{\" color\" : \" blue\" , \" value\" : \" #00f\" }]" ),
494+ resultSet .getPgJsonbList ("colarray" ));
495+ assertEquals (
496+ Value .pgJsonbArray (
497+ Arrays .asList (
498+ "{\" color\" : \" red\" , \" value\" : \" #f00\" }" ,
499+ "[{\" color\" : \" red\" , \" value\" : \" #f00\" }, "
500+ + "{\" color\" : \" green\" , \" value\" : \" #0f0\" }, "
501+ + "{\" color\" : \" blue\" , \" value\" : \" #00f\" }]" )),
502+ resultSet .getValue ("colarray" ));
408503
409504 assertTrue (resultSet .next ());
410505 assertEquals (
@@ -422,17 +517,26 @@ private void verifyContents() {
422517 + "{\" color\" : \" blue\" , \" value\" : \" #00f\" }"
423518 + "]" ),
424519 resultSet .getValue ("col1" ));
520+ assertEquals (JSON_ARRAY2 , resultSet .getPgJsonbList ("colarray" ));
521+ assertEquals (Value .pgJsonbArray (JSON_ARRAY2 ), resultSet .getValue ("colarray" ));
425522
426523 assertTrue (resultSet .next ());
427524 assertEquals ("{}" , resultSet .getPgJsonb ("col1" ));
428525 assertEquals (Value .pgJsonb ("{}" ), resultSet .getValue ("col1" ));
526+ assertEquals (Collections .singletonList ("{}" ), resultSet .getPgJsonbList ("colarray" ));
527+ assertEquals (
528+ Value .pgJsonbArray (Collections .singletonList ("{}" )), resultSet .getValue ("colarray" ));
429529
430530 assertTrue (resultSet .next ());
431531 assertEquals ("[]" , resultSet .getPgJsonb ("col1" ));
432532 assertEquals (Value .pgJsonb ("[]" ), resultSet .getValue ("col1" ));
533+ assertEquals (Collections .singletonList ("[]" ), resultSet .getPgJsonbList ("colarray" ));
534+ assertEquals (
535+ Value .pgJsonbArray (Collections .singletonList ("[]" )), resultSet .getValue ("colarray" ));
433536
434537 assertTrue (resultSet .next ());
435538 assertTrue (resultSet .isNull ("col1" ));
539+ assertTrue (resultSet .isNull ("colarray" ));
436540
437541 assertFalse (resultSet .next ());
438542 }
0 commit comments