Skip to content

Commit a92d1eb

Browse files
committed
chore(spanner): Add sample for Spanner BatchWrite
1 parent d1a2aa3 commit a92d1eb

4 files changed

Lines changed: 165 additions & 51 deletions

File tree

spanner/Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
source "https://rubygems.org"
1616

1717
gem "google-cloud-spanner"
18+
gem "mutex_m"
1819

1920
group :test do
2021
gem "google-apis-iam_v1"

spanner/Gemfile.lock

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
addressable (2.8.6)
5-
public_suffix (>= 2.0.2, < 6.0)
6-
base64 (0.2.0)
7-
concurrent-ruby (1.2.3)
4+
addressable (2.8.9)
5+
public_suffix (>= 2.0.2, < 8.0)
6+
base64 (0.3.0)
7+
bigdecimal (3.3.1)
8+
concurrent-ruby (1.3.6)
89
declarative (0.0.20)
910
diff-lcs (1.5.1)
10-
faraday (2.9.0)
11-
faraday-net_http (>= 2.0, < 3.2)
12-
faraday-net_http (3.1.0)
13-
net-http
14-
faraday-retry (2.2.0)
11+
faraday (2.14.1)
12+
faraday-net_http (>= 2.0, < 3.5)
13+
json
14+
logger
15+
faraday-net_http (3.4.2)
16+
net-http (~> 0.5)
17+
faraday-retry (2.4.0)
1518
faraday (~> 2.0)
16-
gapic-common (0.21.1)
19+
gapic-common (1.3.0)
1720
faraday (>= 1.9, < 3.a)
1821
faraday-retry (>= 1.0, < 3.a)
19-
google-protobuf (~> 3.18)
20-
googleapis-common-protos (>= 1.4.0, < 2.a)
21-
googleapis-common-protos-types (>= 1.11.0, < 2.a)
22-
googleauth (~> 1.9)
23-
grpc (~> 1.59)
22+
google-cloud-env (~> 2.2)
23+
google-logging-utils (~> 0.1)
24+
google-protobuf (~> 4.26)
25+
googleapis-common-protos (~> 1.6)
26+
googleapis-common-protos-types (~> 1.15)
27+
googleauth (~> 1.12)
28+
grpc (~> 1.66)
2429
google-apis-core (0.14.0)
2530
addressable (~> 2.5, >= 2.5.1)
2631
googleauth (~> 1.9)
@@ -31,59 +36,69 @@ GEM
3136
rexml
3237
google-apis-iam_v1 (0.54.0)
3338
google-apis-core (>= 0.14.0, < 2.a)
34-
google-cloud-core (1.6.1)
39+
google-cloud-core (1.8.0)
3540
google-cloud-env (>= 1.0, < 3.a)
3641
google-cloud-errors (~> 1.0)
37-
google-cloud-env (2.1.1)
42+
google-cloud-env (2.3.1)
43+
base64 (~> 0.2)
3844
faraday (>= 1.0, < 3.a)
39-
google-cloud-errors (1.3.1)
40-
google-cloud-spanner (2.21.0)
45+
google-cloud-errors (1.5.0)
46+
google-cloud-spanner (2.35.0)
47+
bigdecimal (~> 3.0)
4148
concurrent-ruby (~> 1.0)
42-
google-cloud-core (~> 1.5)
43-
google-cloud-spanner-admin-database-v1 (~> 0.1)
44-
google-cloud-spanner-admin-instance-v1 (~> 0.1)
45-
google-cloud-spanner-v1 (~> 0.2)
46-
google-cloud-spanner-admin-database-v1 (0.17.1)
47-
gapic-common (>= 0.21.1, < 2.a)
49+
google-cloud-core (~> 1.7)
50+
google-cloud-spanner-admin-database-v1 (~> 1.4)
51+
google-cloud-spanner-admin-instance-v1 (~> 1.6)
52+
google-cloud-spanner-v1 (~> 1.6)
53+
google-cloud-spanner-admin-database-v1 (1.11.1)
54+
gapic-common (~> 1.2)
4855
google-cloud-errors (~> 1.0)
49-
grpc-google-iam-v1 (~> 1.1)
50-
google-cloud-spanner-admin-instance-v1 (0.13.2)
51-
gapic-common (>= 0.21.1, < 2.a)
56+
grpc-google-iam-v1 (~> 1.11)
57+
google-cloud-spanner-admin-instance-v1 (1.6.0)
58+
gapic-common (>= 0.25.0, < 2.a)
5259
google-cloud-errors (~> 1.0)
5360
grpc-google-iam-v1 (~> 1.1)
54-
google-cloud-spanner-v1 (0.24.0)
55-
gapic-common (>= 0.21.1, < 2.a)
61+
google-cloud-spanner-v1 (1.15.0)
62+
gapic-common (~> 1.2)
5663
google-cloud-errors (~> 1.0)
57-
google-protobuf (3.25.3)
58-
googleapis-common-protos (1.5.0)
59-
google-protobuf (~> 3.18)
64+
google-logging-utils (0.2.0)
65+
google-protobuf (4.34.0)
66+
bigdecimal
67+
rake (~> 13.3)
68+
googleapis-common-protos (1.7.0)
69+
google-protobuf (>= 3.18, < 5.a)
6070
googleapis-common-protos-types (~> 1.7)
6171
grpc (~> 1.41)
62-
googleapis-common-protos-types (1.13.0)
63-
google-protobuf (~> 3.18)
64-
googleauth (1.11.0)
72+
googleapis-common-protos-types (1.22.0)
73+
google-protobuf (~> 4.26)
74+
googleauth (1.16.2)
6575
faraday (>= 1.0, < 3.a)
66-
google-cloud-env (~> 2.1)
67-
jwt (>= 1.4, < 3.0)
76+
google-cloud-env (~> 2.2)
77+
google-logging-utils (~> 0.1)
78+
jwt (>= 1.4, < 4.0)
6879
multi_json (~> 1.11)
6980
os (>= 0.9, < 2.0)
7081
signet (>= 0.16, < 2.a)
71-
grpc (1.62.0)
72-
google-protobuf (~> 3.25)
82+
grpc (1.78.1)
83+
google-protobuf (>= 3.25, < 5.0)
7384
googleapis-common-protos-types (~> 1.0)
74-
grpc-google-iam-v1 (1.7.0)
75-
google-protobuf (~> 3.18)
76-
googleapis-common-protos (~> 1.4)
85+
grpc-google-iam-v1 (1.11.0)
86+
google-protobuf (>= 3.18, < 5.a)
87+
googleapis-common-protos (~> 1.7.0)
7788
grpc (~> 1.41)
7889
httpclient (2.8.3)
79-
jwt (2.8.0)
90+
json (2.19.1)
91+
jwt (3.1.2)
8092
base64
93+
logger (1.7.0)
8194
mini_mime (1.1.5)
82-
multi_json (1.15.0)
83-
net-http (0.4.1)
84-
uri
95+
multi_json (1.19.1)
96+
mutex_m (0.3.0)
97+
net-http (0.9.1)
98+
uri (>= 0.11.1)
8599
os (1.1.4)
86-
public_suffix (5.0.4)
100+
public_suffix (7.0.5)
101+
rake (13.3.1)
87102
representable (3.2.0)
88103
declarative (< 0.1.0)
89104
trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -105,21 +120,22 @@ GEM
105120
rspec-support (3.13.1)
106121
rspec_junit_formatter (0.6.0)
107122
rspec-core (>= 2, < 4, != 2.12.0)
108-
signet (0.19.0)
123+
signet (0.21.0)
109124
addressable (~> 2.8)
110125
faraday (>= 0.17.5, < 3.a)
111-
jwt (>= 1.5, < 3.0)
126+
jwt (>= 1.5, < 4.0)
112127
multi_json (~> 1.10)
113128
trailblazer-option (0.1.2)
114129
uber (0.1.0)
115-
uri (0.13.0)
130+
uri (1.1.1)
116131

117132
PLATFORMS
118133
ruby
119134

120135
DEPENDENCIES
121136
google-apis-iam_v1
122137
google-cloud-spanner
138+
mutex_m
123139
retriable
124140
rspec
125141
rspec_junit_formatter

spanner/spanner_batch_write.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START spanner_batch_write_at_least_once]
16+
require "google/cloud/spanner"
17+
18+
##
19+
# This is a snippet for showcasing how to apply a batch of mutations groups.
20+
# All mutations in a group are applied atomically.
21+
#
22+
# @param project_id [String] The ID of the Google Cloud project.
23+
# @param instance_id [String] The ID of the spanner instance.
24+
# @param database_id [String] The ID of the database.
25+
#
26+
def spanner_batch_write project_id:, instance_id:, database_id:
27+
spanner = Google::Cloud::Spanner.new project: project_id
28+
client = spanner.client instance_id, database_id
29+
30+
results = client.batch_write do |b|
31+
# First mutation group
32+
b.mutation_group do |mg|
33+
mg.upsert "Singers", [{ SingerId: 16, FirstName: "Scarlet", LastName: "Terry" }]
34+
end
35+
36+
# Second mutation group
37+
b.mutation_group do |mg|
38+
mg.upsert "Singers", [
39+
{ SingerId: 17, FirstName: "Marc" },
40+
{ SingerId: 18, FirstName: "Catalina", LastName: "Smith" }
41+
]
42+
mg.upsert "Albums", [
43+
{ SingerId: 17, AlbumId: 1, AlbumTitle: "Total Junk" },
44+
{ SingerId: 18, AlbumId: 2, AlbumTitle: "Go, Go, Go" }
45+
]
46+
end
47+
end
48+
49+
results.each do |response|
50+
if response.ok?
51+
puts "Mutation group indexes applied: #{response.indexes}"
52+
else
53+
puts "Mutation group failed to apply: #{response.indexes}"
54+
puts "Error: #{response.status.message}"
55+
end
56+
end
57+
end
58+
# [END spanner_batch_write_at_least_once]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
require "spec_helper"
16+
require_relative "../spanner_batch_write"
17+
18+
describe "spanner_batch_write" do
19+
before :all do
20+
create_singers_albums_database
21+
end
22+
23+
after :all do
24+
cleanup_database_resources
25+
end
26+
27+
it "applies mutation groups" do
28+
expect {
29+
spanner_batch_write project_id: @project_id,
30+
instance_id: @instance_id,
31+
database_id: @database_id
32+
}.to output(/Mutation group indexes applied: (\[0, 1\]|\[0\].*\[1\])/m).to_stdout
33+
34+
# Verify that the records were inserted
35+
client = @spanner.client @instance_id, @database_id
36+
results = client.execute "SELECT COUNT(*) FROM Singers"
37+
expect(results.rows.first[0]).to eq 3 # 16, 17, 18
38+
end
39+
end

0 commit comments

Comments
 (0)