google-cloud-spanner 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/google-cloud-spanner.rb +25 -0
- data/lib/google/cloud/spanner.rb +71 -11
- data/lib/google/cloud/spanner/batch_client.rb +355 -0
- data/lib/google/cloud/spanner/batch_snapshot.rb +588 -0
- data/lib/google/cloud/spanner/client.rb +27 -20
- data/lib/google/cloud/spanner/commit.rb +6 -5
- data/lib/google/cloud/spanner/convert.rb +39 -0
- data/lib/google/cloud/spanner/credentials.rb +7 -7
- data/lib/google/cloud/spanner/data.rb +5 -5
- data/lib/google/cloud/spanner/database.rb +13 -7
- data/lib/google/cloud/spanner/database/job.rb +7 -2
- data/lib/google/cloud/spanner/database/list.rb +1 -1
- data/lib/google/cloud/spanner/fields.rb +16 -12
- data/lib/google/cloud/spanner/instance.rb +25 -13
- data/lib/google/cloud/spanner/instance/config.rb +2 -2
- data/lib/google/cloud/spanner/instance/config/list.rb +1 -1
- data/lib/google/cloud/spanner/instance/job.rb +7 -2
- data/lib/google/cloud/spanner/instance/list.rb +1 -1
- data/lib/google/cloud/spanner/partition.rb +208 -0
- data/lib/google/cloud/spanner/pool.rb +6 -6
- data/lib/google/cloud/spanner/project.rb +59 -16
- data/lib/google/cloud/spanner/results.rb +12 -5
- data/lib/google/cloud/spanner/service.rb +85 -61
- data/lib/google/cloud/spanner/session.rb +45 -9
- data/lib/google/cloud/spanner/snapshot.rb +10 -2
- data/lib/google/cloud/spanner/status.rb +6 -5
- data/lib/google/cloud/spanner/transaction.rb +11 -3
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/duration.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/struct.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/timestamp.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/keys.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/mutation.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/query_plan.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/result_set.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/spanner.rb +138 -6
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/transaction.rb +1 -1
- data/lib/google/cloud/spanner/v1/doc/overview.rb +6 -5
- data/lib/google/cloud/spanner/v1/spanner_client.rb +257 -33
- data/lib/google/cloud/spanner/v1/spanner_client_config.json +10 -0
- data/lib/google/cloud/spanner/version.rb +1 -1
- data/lib/google/spanner/v1/spanner_pb.rb +35 -0
- data/lib/google/spanner/v1/spanner_services_pb.rb +20 -2
- metadata +12 -9
@@ -237,6 +237,8 @@ module Google
|
|
237
237
|
validate_single_use_args! single_use
|
238
238
|
ensure_service!
|
239
239
|
|
240
|
+
params, types = Convert.to_input_params_and_types params, types
|
241
|
+
|
240
242
|
single_use_tx = single_use_transaction single_use
|
241
243
|
results = nil
|
242
244
|
@pool.with_session do |session|
|
@@ -245,7 +247,7 @@ module Google
|
|
245
247
|
end
|
246
248
|
results
|
247
249
|
end
|
248
|
-
|
250
|
+
alias query execute
|
249
251
|
|
250
252
|
##
|
251
253
|
# Read rows from a database table, as a simple alternative to
|
@@ -349,6 +351,9 @@ module Google
|
|
349
351
|
validate_single_use_args! single_use
|
350
352
|
ensure_service!
|
351
353
|
|
354
|
+
columns = Array(columns).map(&:to_s)
|
355
|
+
keys = Convert.to_key_set keys
|
356
|
+
|
352
357
|
single_use_tx = single_use_transaction single_use
|
353
358
|
results = nil
|
354
359
|
@pool.with_session do |session|
|
@@ -414,7 +419,7 @@ module Google
|
|
414
419
|
session.upsert table, rows
|
415
420
|
end
|
416
421
|
end
|
417
|
-
|
422
|
+
alias save upsert
|
418
423
|
|
419
424
|
##
|
420
425
|
# Inserts new rows in a table. If any of the rows already exist, the
|
@@ -654,7 +659,7 @@ module Google
|
|
654
659
|
# end
|
655
660
|
#
|
656
661
|
def commit &block
|
657
|
-
|
662
|
+
raise ArgumentError, "Must provide a block" unless block_given?
|
658
663
|
|
659
664
|
@pool.with_session do |session|
|
660
665
|
session.commit(&block)
|
@@ -721,10 +726,10 @@ module Google
|
|
721
726
|
# end
|
722
727
|
# end
|
723
728
|
#
|
724
|
-
def transaction deadline: 120
|
729
|
+
def transaction deadline: 120
|
725
730
|
ensure_service!
|
726
731
|
unless Thread.current[:transaction_id].nil?
|
727
|
-
|
732
|
+
raise "Nested transactions are not allowed"
|
728
733
|
end
|
729
734
|
|
730
735
|
deadline = validate_deadline deadline
|
@@ -734,7 +739,7 @@ module Google
|
|
734
739
|
@pool.with_transaction do |tx|
|
735
740
|
begin
|
736
741
|
Thread.current[:transaction_id] = tx.transaction_id
|
737
|
-
|
742
|
+
yield tx
|
738
743
|
commit_resp = @project.service.commit \
|
739
744
|
tx.session.path, tx.mutations, transaction_id: tx.transaction_id
|
740
745
|
return Convert.timestamp_to_time commit_resp.commit_timestamp
|
@@ -751,7 +756,7 @@ module Google
|
|
751
756
|
# Create new transaction on the session and retry the block
|
752
757
|
tx = tx.session.create_transaction
|
753
758
|
retry
|
754
|
-
rescue => err
|
759
|
+
rescue StandardError => err
|
755
760
|
# Rollback transaction when handling unexpected error
|
756
761
|
tx.session.rollback tx.transaction_id
|
757
762
|
# Return nil if raised with rollback.
|
@@ -829,7 +834,7 @@ module Google
|
|
829
834
|
|
830
835
|
ensure_service!
|
831
836
|
unless Thread.current[:transaction_id].nil?
|
832
|
-
|
837
|
+
raise "Nested snapshots are not allowed"
|
833
838
|
end
|
834
839
|
|
835
840
|
@pool.with_session do |session|
|
@@ -945,7 +950,8 @@ module Google
|
|
945
950
|
ensure_service!
|
946
951
|
grpc = @project.service.create_session \
|
947
952
|
Admin::Database::V1::DatabaseAdminClient.database_path(
|
948
|
-
project_id, instance_id, database_id
|
953
|
+
project_id, instance_id, database_id
|
954
|
+
)
|
949
955
|
Session.from_grpc(grpc, @project.service)
|
950
956
|
end
|
951
957
|
|
@@ -966,22 +972,22 @@ module Google
|
|
966
972
|
# @private Raise an error unless an active connection to the service is
|
967
973
|
# available.
|
968
974
|
def ensure_service!
|
969
|
-
|
975
|
+
raise "Must have active connection to service" unless @project.service
|
970
976
|
end
|
971
977
|
|
972
978
|
##
|
973
979
|
# Check for valid snapshot arguments
|
974
980
|
def validate_single_use_args! opts
|
975
981
|
return true if opts.nil? || opts.empty?
|
976
|
-
valid_keys = [
|
977
|
-
|
978
|
-
|
982
|
+
valid_keys = %i[strong timestamp read_timestamp staleness
|
983
|
+
exact_staleness bounded_timestamp
|
984
|
+
min_read_timestamp bounded_staleness max_staleness]
|
979
985
|
if opts.keys.count == 1 && valid_keys.include?(opts.keys.first)
|
980
986
|
return true
|
981
987
|
end
|
982
|
-
|
983
|
-
|
984
|
-
|
988
|
+
raise ArgumentError,
|
989
|
+
"Must provide only one of the following single_use values: " \
|
990
|
+
"#{valid_keys}"
|
985
991
|
end
|
986
992
|
|
987
993
|
##
|
@@ -1018,9 +1024,10 @@ module Google
|
|
1018
1024
|
valid_args_count = [strong, timestamp, read_timestamp, staleness,
|
1019
1025
|
exact_staleness].compact.count
|
1020
1026
|
return true if valid_args_count <= 1
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1027
|
+
raise ArgumentError,
|
1028
|
+
"Can only provide one of the following arguments: " \
|
1029
|
+
"(strong, timestamp, read_timestamp, staleness, " \
|
1030
|
+
"exact_staleness)"
|
1024
1031
|
end
|
1025
1032
|
|
1026
1033
|
def validate_deadline deadline
|
@@ -1050,7 +1057,7 @@ module Google
|
|
1050
1057
|
end
|
1051
1058
|
# No metadata? Try the inner error
|
1052
1059
|
delay_from_aborted(err.cause)
|
1053
|
-
rescue
|
1060
|
+
rescue StandardError
|
1054
1061
|
# Any error indicates the backoff should be handled elsewhere
|
1055
1062
|
return nil
|
1056
1063
|
end
|
@@ -105,7 +105,7 @@ module Google
|
|
105
105
|
end
|
106
106
|
rows
|
107
107
|
end
|
108
|
-
|
108
|
+
alias save upsert
|
109
109
|
|
110
110
|
##
|
111
111
|
# Inserts new rows in a table. If any of the rows already exist, the
|
@@ -308,7 +308,8 @@ module Google
|
|
308
308
|
@mutations += [
|
309
309
|
Google::Spanner::V1::Mutation.new(
|
310
310
|
delete: Google::Spanner::V1::Mutation::Delete.new(
|
311
|
-
table: table, key_set: key_set(keys)
|
311
|
+
table: table, key_set: key_set(keys)
|
312
|
+
)
|
312
313
|
)
|
313
314
|
]
|
314
315
|
keys
|
@@ -326,14 +327,14 @@ module Google
|
|
326
327
|
keys = [keys] unless keys.is_a? Array
|
327
328
|
return Google::Spanner::V1::KeySet.new(all: true) if keys.empty?
|
328
329
|
if keys_are_ranges? keys
|
329
|
-
keys = [keys] unless keys.is_a? Array
|
330
330
|
key_ranges = keys.map do |r|
|
331
331
|
Convert.to_key_range(r)
|
332
332
|
end
|
333
333
|
return Google::Spanner::V1::KeySet.new(ranges: key_ranges)
|
334
334
|
end
|
335
|
-
key_list =
|
336
|
-
|
335
|
+
key_list = keys.map do |key|
|
336
|
+
key = [key] unless key.is_a? Array
|
337
|
+
Convert.raw_to_value(key).list_value
|
337
338
|
end
|
338
339
|
Google::Spanner::V1::KeySet.new keys: key_list
|
339
340
|
end
|
@@ -258,6 +258,45 @@ module Google
|
|
258
258
|
|
259
259
|
Google::Spanner::V1::KeyRange.new range_opts
|
260
260
|
end
|
261
|
+
|
262
|
+
def to_key_set keys
|
263
|
+
return Google::Spanner::V1::KeySet.new(all: true) if keys.nil?
|
264
|
+
keys = [keys] unless keys.is_a? Array
|
265
|
+
return Google::Spanner::V1::KeySet.new(all: true) if keys.empty?
|
266
|
+
|
267
|
+
if keys_are_ranges? keys
|
268
|
+
key_ranges = keys.map { |r| to_key_range(r) }
|
269
|
+
return Google::Spanner::V1::KeySet.new(ranges: key_ranges)
|
270
|
+
end
|
271
|
+
|
272
|
+
key_list = keys.map do |key|
|
273
|
+
key = [key] unless key.is_a? Array
|
274
|
+
raw_to_value(key).list_value
|
275
|
+
end
|
276
|
+
Google::Spanner::V1::KeySet.new keys: key_list
|
277
|
+
end
|
278
|
+
|
279
|
+
def keys_are_ranges? keys
|
280
|
+
keys.each do |key|
|
281
|
+
return true if key.is_a? ::Range
|
282
|
+
return true if key.is_a? Google::Cloud::Spanner::Range
|
283
|
+
end
|
284
|
+
false
|
285
|
+
end
|
286
|
+
|
287
|
+
def to_input_params_and_types params, types
|
288
|
+
input_params = nil
|
289
|
+
input_param_types = nil
|
290
|
+
unless params.nil?
|
291
|
+
input_param_pairs = to_query_params params, types
|
292
|
+
input_params = Google::Protobuf::Struct.new \
|
293
|
+
fields: Hash[input_param_pairs.map { |k, v| [k, v.first] }]
|
294
|
+
input_param_types = Hash[
|
295
|
+
input_param_pairs.map { |k, v| [k, v.last] }]
|
296
|
+
end
|
297
|
+
|
298
|
+
[input_params, input_param_types]
|
299
|
+
end
|
261
300
|
end
|
262
301
|
|
263
302
|
# rubocop:enable all
|
@@ -38,20 +38,20 @@ module Google
|
|
38
38
|
# spanner.project_id #=> "my-project"
|
39
39
|
#
|
40
40
|
class Credentials < Google::Auth::Credentials
|
41
|
-
SCOPE = %w
|
42
|
-
https://www.googleapis.com/auth/spanner.data
|
43
|
-
PATH_ENV_VARS = %w
|
41
|
+
SCOPE = %w[https://www.googleapis.com/auth/cloud-platform
|
42
|
+
https://www.googleapis.com/auth/spanner.data].freeze
|
43
|
+
PATH_ENV_VARS = %w[SPANNER_CREDENTIALS
|
44
44
|
SPANNER_KEYFILE
|
45
45
|
GOOGLE_CLOUD_CREDENTIALS
|
46
46
|
GOOGLE_CLOUD_KEYFILE
|
47
|
-
GCLOUD_KEYFILE
|
48
|
-
JSON_ENV_VARS = %w
|
47
|
+
GCLOUD_KEYFILE].freeze
|
48
|
+
JSON_ENV_VARS = %w[SPANNER_CREDENTIALS_JSON
|
49
49
|
SPANNER_KEYFILE_JSON
|
50
50
|
GOOGLE_CLOUD_CREDENTIALS_JSON
|
51
51
|
GOOGLE_CLOUD_KEYFILE_JSON
|
52
|
-
GCLOUD_KEYFILE_JSON
|
52
|
+
GCLOUD_KEYFILE_JSON].freeze
|
53
53
|
DEFAULT_PATHS = \
|
54
|
-
["~/.config/gcloud/application_default_credentials.json"]
|
54
|
+
["~/.config/gcloud/application_default_credentials.json"].freeze
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -80,7 +80,7 @@ module Google
|
|
80
80
|
# @return [Array<Object>] An array containing the values.
|
81
81
|
#
|
82
82
|
def values
|
83
|
-
keys.count
|
83
|
+
Array.new(keys.count) { |i| self[i] }
|
84
84
|
end
|
85
85
|
|
86
86
|
##
|
@@ -113,8 +113,8 @@ module Google
|
|
113
113
|
@grpc_fields[key].type)
|
114
114
|
end
|
115
115
|
name_count = @grpc_fields.find_all { |f| f.name == String(key) }.count
|
116
|
-
return nil if name_count
|
117
|
-
|
116
|
+
return nil if name_count.zero?
|
117
|
+
raise DuplicateNameError if name_count > 1
|
118
118
|
index = @grpc_fields.find_index { |f| f.name == String(key) }
|
119
119
|
Convert.value_to_raw(@grpc_values[index], @grpc_fields[index].type)
|
120
120
|
end
|
@@ -148,7 +148,7 @@ module Google
|
|
148
148
|
# or indexes and corresponding values.
|
149
149
|
#
|
150
150
|
def to_h
|
151
|
-
|
151
|
+
raise DuplicateNameError if fields.duplicate_names?
|
152
152
|
hashified_pairs = pairs.map do |key, value|
|
153
153
|
if value.is_a? Data
|
154
154
|
[key, value.to_h]
|
@@ -171,7 +171,7 @@ module Google
|
|
171
171
|
def to_s
|
172
172
|
named_values = pairs.map do |key, value|
|
173
173
|
if key.is_a? Integer
|
174
|
-
|
174
|
+
value.inspect
|
175
175
|
else
|
176
176
|
"(#{key})#{value.inspect}"
|
177
177
|
end
|
@@ -48,7 +48,11 @@ module Google
|
|
48
48
|
# job.reload! # API call
|
49
49
|
# job.done? #=> true
|
50
50
|
#
|
51
|
-
#
|
51
|
+
# if job.error?
|
52
|
+
# status = job.error
|
53
|
+
# else
|
54
|
+
# database = job.database
|
55
|
+
# end
|
52
56
|
#
|
53
57
|
class Database
|
54
58
|
##
|
@@ -101,7 +105,7 @@ module Google
|
|
101
105
|
|
102
106
|
##
|
103
107
|
# The database is still being created. Operations on the database may
|
104
|
-
#
|
108
|
+
# raise with `FAILED_PRECONDITION` in this state.
|
105
109
|
# @return [Boolean]
|
106
110
|
def creating?
|
107
111
|
state == :CREATING
|
@@ -260,7 +264,7 @@ module Google
|
|
260
264
|
policy = Policy.from_grpc grpc
|
261
265
|
return policy unless block_given?
|
262
266
|
yield policy
|
263
|
-
|
267
|
+
update_policy policy
|
264
268
|
end
|
265
269
|
|
266
270
|
##
|
@@ -290,14 +294,15 @@ module Google
|
|
290
294
|
#
|
291
295
|
# policy.add "roles/owner", "user:owner@example.com"
|
292
296
|
#
|
293
|
-
# database.
|
297
|
+
# database.update_policy policy # API call
|
294
298
|
#
|
295
|
-
def
|
299
|
+
def update_policy new_policy
|
296
300
|
ensure_service!
|
297
301
|
grpc = service.set_database_policy \
|
298
302
|
instance_id, database_id, new_policy.to_grpc
|
299
303
|
Policy.from_grpc grpc
|
300
304
|
end
|
305
|
+
alias policy= update_policy
|
301
306
|
|
302
307
|
##
|
303
308
|
# Tests the specified permissions against the [Cloud
|
@@ -361,12 +366,13 @@ module Google
|
|
361
366
|
# @private Raise an error unless an active connection to the service is
|
362
367
|
# available.
|
363
368
|
def ensure_service!
|
364
|
-
|
369
|
+
raise "Must have active connection to service" unless service
|
365
370
|
end
|
366
371
|
|
367
372
|
def session_path instance_id, database_id, session_id
|
368
373
|
V1::SpannerClient.session_path(
|
369
|
-
project_id, instance_id, database_id, session_id
|
374
|
+
project_id, instance_id, database_id, session_id
|
375
|
+
)
|
370
376
|
end
|
371
377
|
end
|
372
378
|
end
|
@@ -41,7 +41,12 @@ module Google
|
|
41
41
|
# job.done? #=> false
|
42
42
|
# job.reload! # API call
|
43
43
|
# job.done? #=> true
|
44
|
-
#
|
44
|
+
#
|
45
|
+
# if job.error?
|
46
|
+
# status = job.error
|
47
|
+
# else
|
48
|
+
# database = job.database
|
49
|
+
# end
|
45
50
|
#
|
46
51
|
class Job
|
47
52
|
##
|
@@ -169,7 +174,7 @@ module Google
|
|
169
174
|
@grpc.reload!
|
170
175
|
self
|
171
176
|
end
|
172
|
-
|
177
|
+
alias refresh! reload!
|
173
178
|
|
174
179
|
##
|
175
180
|
# Reloads the job until the operation is complete. The delay between
|
@@ -53,7 +53,7 @@ module Google
|
|
53
53
|
@fields << field(type)
|
54
54
|
end
|
55
55
|
else
|
56
|
-
|
56
|
+
raise ArgumentError, "can only accept Array or Hash"
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -135,8 +135,8 @@ module Google
|
|
135
135
|
def [] key
|
136
136
|
return types[key] if key.is_a? Integer
|
137
137
|
name_count = @fields.find_all { |f| f.name == String(key) }.count
|
138
|
-
return nil if name_count
|
139
|
-
|
138
|
+
return nil if name_count.zero?
|
139
|
+
raise DuplicateNameError if name_count > 1
|
140
140
|
index = @fields.find_index { |f| f.name == String(key) }
|
141
141
|
types[index]
|
142
142
|
end
|
@@ -151,7 +151,8 @@ module Google
|
|
151
151
|
# @return [Array<Symbol>] An array containing the type codes.
|
152
152
|
#
|
153
153
|
def to_a
|
154
|
-
keys.count
|
154
|
+
Array.new(keys.count) do |i|
|
155
|
+
field = self[i]
|
155
156
|
if field.is_a? Fields
|
156
157
|
field.to_h
|
157
158
|
elsif field.is_a? Array
|
@@ -169,7 +170,7 @@ module Google
|
|
169
170
|
# or indexes and corresponding types.
|
170
171
|
#
|
171
172
|
def to_h
|
172
|
-
|
173
|
+
raise DuplicateNameError if duplicate_names?
|
173
174
|
hashified_pairs = pairs.map do |key, value|
|
174
175
|
if value.is_a? Fields
|
175
176
|
[key, value.to_h]
|
@@ -189,7 +190,7 @@ module Google
|
|
189
190
|
values = data.map { |datum| Convert.raw_to_value datum }
|
190
191
|
Data.from_grpc values, @fields
|
191
192
|
end
|
192
|
-
|
193
|
+
alias new data
|
193
194
|
|
194
195
|
# @private
|
195
196
|
def == other
|
@@ -201,7 +202,7 @@ module Google
|
|
201
202
|
def to_s
|
202
203
|
named_types = pairs.map do |key, type|
|
203
204
|
if key.is_a? Integer
|
204
|
-
|
205
|
+
type.inspect
|
205
206
|
else
|
206
207
|
"(#{key})#{type.inspect}"
|
207
208
|
end
|
@@ -228,22 +229,25 @@ module Google
|
|
228
229
|
def field pair
|
229
230
|
if pair.is_a?(Array)
|
230
231
|
unless pair.count == 2
|
231
|
-
|
232
|
+
raise ArgumentError, "can only accept pairs of name and type"
|
232
233
|
end
|
233
234
|
if pair.first.nil? || pair.first.is_a?(Integer)
|
234
235
|
Google::Spanner::V1::StructType::Field.new(
|
235
|
-
type: Google::Spanner::V1::Type.new(code: pair.last)
|
236
|
+
type: Google::Spanner::V1::Type.new(code: pair.last)
|
237
|
+
)
|
236
238
|
else
|
237
239
|
Google::Spanner::V1::StructType::Field.new(
|
238
240
|
name: String(pair.first),
|
239
|
-
type: Google::Spanner::V1::Type.new(code: pair.last)
|
241
|
+
type: Google::Spanner::V1::Type.new(code: pair.last)
|
242
|
+
)
|
240
243
|
end
|
241
244
|
else
|
242
245
|
unless pair.is_a?(Symbol)
|
243
|
-
|
246
|
+
raise ArgumentError, "type must be a symbol"
|
244
247
|
end
|
245
248
|
Google::Spanner::V1::StructType::Field.new(
|
246
|
-
type: Google::Spanner::V1::Type.new(code: pair)
|
249
|
+
type: Google::Spanner::V1::Type.new(code: pair)
|
250
|
+
)
|
247
251
|
end
|
248
252
|
end
|
249
253
|
end
|