Skip to content

Commit 0d8aa7d

Browse files
authored
chore: add samples for JSON (#1375)
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/java-spanner/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes #<issue_number_goes_here> ☕️
1 parent 377049b commit 0d8aa7d

File tree

5 files changed

+293
-6
lines changed

5 files changed

+293
-6
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2021 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner;
18+
19+
// [START spanner_add_json_column]
20+
import com.google.api.gax.longrunning.OperationFuture;
21+
import com.google.cloud.spanner.DatabaseAdminClient;
22+
import com.google.cloud.spanner.Spanner;
23+
import com.google.cloud.spanner.SpannerOptions;
24+
import com.google.common.collect.ImmutableList;
25+
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
26+
import java.util.concurrent.ExecutionException;
27+
28+
class AddJsonColumnSample {
29+
30+
static void addJsonColumn() throws InterruptedException, ExecutionException {
31+
// TODO(developer): Replace these variables before running the sample.
32+
String projectId = "my-project";
33+
String instanceId = "my-instance";
34+
String databaseId = "my-database";
35+
36+
try (Spanner spanner =
37+
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
38+
DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
39+
addJsonColumn(adminClient, instanceId, databaseId);
40+
}
41+
}
42+
43+
static void addJsonColumn(DatabaseAdminClient adminClient, String instanceId, String databaseId)
44+
throws InterruptedException, ExecutionException {
45+
OperationFuture<Void, UpdateDatabaseDdlMetadata> operation =
46+
adminClient.updateDatabaseDdl(
47+
instanceId,
48+
databaseId,
49+
ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSON"),
50+
null);
51+
// Wait for the operation to finish.
52+
// This will throw an ExecutionException if the operation fails.
53+
operation.get();
54+
System.out.printf("Successfully added column `VenueDetails`%n");
55+
}
56+
}
57+
// [END spanner_add_json_column]
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2021 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner;
18+
19+
// [START spanner_query_with_json_parameter]
20+
import com.google.cloud.spanner.DatabaseClient;
21+
import com.google.cloud.spanner.DatabaseId;
22+
import com.google.cloud.spanner.ResultSet;
23+
import com.google.cloud.spanner.Spanner;
24+
import com.google.cloud.spanner.SpannerOptions;
25+
import com.google.cloud.spanner.Statement;
26+
import com.google.cloud.spanner.Value;
27+
28+
class QueryWithJsonParameterSample {
29+
30+
static void queryWithJsonParameter() {
31+
// TODO(developer): Replace these variables before running the sample.
32+
String projectId = "my-project";
33+
String instanceId = "my-instance";
34+
String databaseId = "my-database";
35+
36+
try (Spanner spanner =
37+
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
38+
DatabaseClient client =
39+
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
40+
queryWithJsonParameter(client);
41+
}
42+
}
43+
44+
static void queryWithJsonParameter(DatabaseClient client) {
45+
String exampleJson = "{rating: 9}";
46+
Statement statement =
47+
Statement.newBuilder(
48+
"SELECT VenueId, VenueDetails\n"
49+
+ "FROM Venues\n"
50+
+ "WHERE JSON_VALUE(VenueDetails, '$.rating') = "
51+
+ "JSON_VALUE(@details, '$.rating')")
52+
.bind("details")
53+
.to(Value.json(exampleJson))
54+
.build();
55+
try (ResultSet resultSet = client.singleUse().executeQuery(statement)) {
56+
while (resultSet.next()) {
57+
System.out.printf(
58+
"VenueId: %s, VenueDetails: %s%n",
59+
resultSet.getLong("VenueId"), resultSet.getString("VenueDetails"));
60+
}
61+
}
62+
}
63+
}
64+
// [END spanner_query_with_json_parameter]

samples/snippets/src/main/java/com/example/spanner/SpannerSample.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ static class Venue {
148148
final boolean outdoorVenue;
149149
final float popularityScore;
150150
final BigDecimal revenue;
151+
final Value venueDetails;
151152

152153
Venue(
153154
long venueId,
@@ -158,7 +159,8 @@ static class Venue {
158159
String lastContactDate,
159160
boolean outdoorVenue,
160161
float popularityScore,
161-
BigDecimal revenue) {
162+
BigDecimal revenue,
163+
Value venueDetails) {
162164
this.venueId = venueId;
163165
this.venueName = venueName;
164166
this.venueInfo = venueInfo;
@@ -168,6 +170,7 @@ static class Venue {
168170
this.outdoorVenue = outdoorVenue;
169171
this.popularityScore = popularityScore;
170172
this.revenue = revenue;
173+
this.venueDetails = venueDetails;
171174
}
172175
}
173176

@@ -237,7 +240,9 @@ static String createRestoredSampleDbId(DatabaseId database) {
237240
"2018-09-02",
238241
false,
239242
0.85543f,
240-
new BigDecimal("215100.10")),
243+
new BigDecimal("215100.10"),
244+
Value.json(
245+
"[{\"name\":\"room 1\",\"open\":true},{\"name\":\"room 2\",\"open\":false}]")),
241246
new Venue(
242247
19,
243248
"Venue 19",
@@ -247,7 +252,8 @@ static String createRestoredSampleDbId(DatabaseId database) {
247252
"2019-01-15",
248253
true,
249254
0.98716f,
250-
new BigDecimal("1200100.00")),
255+
new BigDecimal("1200100.00"),
256+
Value.json("{\"rating\":9,\"open\":true}")),
251257
new Venue(
252258
42,
253259
"Venue 42",
@@ -257,7 +263,11 @@ static String createRestoredSampleDbId(DatabaseId database) {
257263
"2018-10-01",
258264
false,
259265
0.72598f,
260-
new BigDecimal("390650.99")));
266+
new BigDecimal("390650.99"),
267+
Value.json(
268+
"{\"name\":null,"
269+
+ "\"open\":{\"Monday\":true,\"Tuesday\":false},"
270+
+ "\"tags\":[\"large\",\"airy\"]}")));
261271
// [END spanner_insert_datatypes_data]
262272

263273
// [START spanner_create_database]
@@ -1258,6 +1268,7 @@ static void createTableWithDatatypes(DatabaseAdminClient dbAdminClient, Database
12581268
+ " OutdoorVenue BOOL, "
12591269
+ " PopularityScore FLOAT64, "
12601270
+ " Revenue NUMERIC, "
1271+
+ " VenueDetails JSON, "
12611272
+ " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)"
12621273
+ ") PRIMARY KEY (VenueId)"),
12631274
null);
@@ -1300,6 +1311,8 @@ static void writeDatatypesData(DatabaseClient dbClient) {
13001311
.to(venue.popularityScore)
13011312
.set("Revenue")
13021313
.to(venue.revenue)
1314+
.set("VenueDetails")
1315+
.to(venue.venueDetails)
13031316
.set("LastUpdateTime")
13041317
.to(Value.COMMIT_TIMESTAMP)
13051318
.build());
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2021 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner;
18+
19+
// [START spanner_update_data_with_json_column]
20+
21+
import com.google.cloud.spanner.DatabaseClient;
22+
import com.google.cloud.spanner.DatabaseId;
23+
import com.google.cloud.spanner.Mutation;
24+
import com.google.cloud.spanner.Spanner;
25+
import com.google.cloud.spanner.SpannerOptions;
26+
import com.google.cloud.spanner.Value;
27+
import com.google.common.collect.ImmutableList;
28+
29+
class UpdateJsonDataSample {
30+
31+
static void updateJsonData() {
32+
// TODO(developer): Replace these variables before running the sample.
33+
String projectId = "my-project";
34+
String instanceId = "my-instance";
35+
String databaseId = "my-database";
36+
37+
try (Spanner spanner =
38+
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
39+
DatabaseClient client =
40+
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
41+
updateJsonData(client);
42+
}
43+
}
44+
45+
static void updateJsonData(DatabaseClient client) {
46+
client.write(
47+
ImmutableList.of(
48+
Mutation.newInsertOrUpdateBuilder("Venues")
49+
.set("VenueId")
50+
.to(4L)
51+
.set("VenueDetails")
52+
.to(
53+
Value.json(
54+
"[{\"name\":\"room 1\",\"open\":true},"
55+
+ "{\"name\":\"room 2\",\"open\":false}]"))
56+
.build(),
57+
Mutation.newInsertOrUpdateBuilder("Venues")
58+
.set("VenueId")
59+
.to(19L)
60+
.set("VenueDetails")
61+
.to(Value.json("{\"rating\":9,\"open\":true}"))
62+
.build(),
63+
Mutation.newInsertOrUpdateBuilder("Venues")
64+
.set("VenueId")
65+
.to(42L)
66+
.set("VenueDetails")
67+
.to(
68+
Value.json(
69+
"{\"name\":null,"
70+
+ "\"open\":{\"Monday\":true,\"Tuesday\":false},"
71+
+ "\"tags\":[\"large\",\"airy\"]}"))
72+
.build()));
73+
System.out.println("Venues successfully updated");
74+
}
75+
}
76+
// [END spanner_update_data_with_json_column]

samples/snippets/src/test/java/com/example/spanner/SpannerStandaloneExamplesIT.java

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.google.cloud.spanner.Mutation;
2828
import com.google.cloud.spanner.Spanner;
2929
import com.google.cloud.spanner.SpannerOptions;
30+
import com.google.cloud.spanner.Value;
3031
import com.google.common.collect.ImmutableList;
3132
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
3233
import java.io.ByteArrayOutputStream;
@@ -90,8 +91,9 @@ public static void createTestDatabase() throws Exception {
9091
+ " SingerInfo BYTES(MAX)"
9192
+ ") PRIMARY KEY (SingerId)",
9293
"CREATE TABLE Venues ("
93-
+ "VenueId INT64 NOT NULL,"
94-
+ "Revenue NUMERIC"
94+
+ "VenueId INT64 NOT NULL,"
95+
+ "Revenue NUMERIC,"
96+
+ "VenueDetails JSON"
9597
+ ") PRIMARY KEY (VenueId)"))
9698
.get();
9799
}
@@ -199,4 +201,79 @@ public void queryWithNumericParameter_shouldReturnResults() {
199201
runExample(() -> QueryWithNumericParameterSample.queryWithNumericParameter(client));
200202
assertThat(out).contains("4 35000");
201203
}
204+
205+
@Test
206+
public void addJsonColumn_shouldSuccessfullyAddColumn()
207+
throws InterruptedException, ExecutionException {
208+
OperationFuture<Void, UpdateDatabaseDdlMetadata> operation =
209+
spanner
210+
.getDatabaseAdminClient()
211+
.updateDatabaseDdl(
212+
instanceId,
213+
databaseId,
214+
ImmutableList.of("ALTER TABLE Venues DROP COLUMN VenueDetails"),
215+
null);
216+
operation.get();
217+
String out =
218+
runExample(
219+
() -> {
220+
try {
221+
AddJsonColumnSample.addJsonColumn(
222+
spanner.getDatabaseAdminClient(), instanceId, databaseId);
223+
} catch (ExecutionException e) {
224+
System.out.printf(
225+
"Adding column `VenueDetails` failed: %s%n", e.getCause().getMessage());
226+
} catch (InterruptedException e) {
227+
System.out.printf("Adding column `VenueDetails` was interrupted%n");
228+
}
229+
});
230+
assertThat(out).contains("Successfully added column `VenueDetails`");
231+
}
232+
233+
@Test
234+
public void updateJsonData_shouldWriteData() {
235+
String projectId = spanner.getOptions().getProjectId();
236+
String out =
237+
runExample(
238+
() ->
239+
UpdateJsonDataSample.updateJsonData(
240+
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId))));
241+
assertThat(out).contains("VenueDetails successfully updated");
242+
}
243+
244+
@Test
245+
public void queryWithJsonParameter_shouldReturnResults() {
246+
String projectId = spanner.getOptions().getProjectId();
247+
DatabaseClient client =
248+
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
249+
client.write(
250+
ImmutableList.of(
251+
Mutation.newInsertOrUpdateBuilder("Venues")
252+
.set("VenueId")
253+
.to(4L)
254+
.set("VenueDetails")
255+
.to(
256+
Value.json(
257+
"[{\"name\":\"room 1\",\"open\":true},"
258+
+ "{\"name\":\"room 2\",\"open\":false}]"))
259+
.build(),
260+
Mutation.newInsertOrUpdateBuilder("Venues")
261+
.set("VenueId")
262+
.to(19L)
263+
.set("VenueDetails")
264+
.to(Value.json("{\"rating\":9,\"open\":true}"))
265+
.build(),
266+
Mutation.newInsertOrUpdateBuilder("Venues")
267+
.set("VenueId")
268+
.to(42L)
269+
.set("VenueDetails")
270+
.to(
271+
Value.json(
272+
"{\"name\":null,"
273+
+ "\"open\":{\"Monday\":true,\"Tuesday\":false},"
274+
+ "\"tags\":[\"large\",\"airy\"]}"))
275+
.build()));
276+
String out = runExample(() -> QueryWithJsonParameterSample.queryWithJsonParameter(client));
277+
assertThat(out).contains("4 35000");
278+
}
202279
}

0 commit comments

Comments
 (0)