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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/google-cloud-spanner.rb +25 -0
  3. data/lib/google/cloud/spanner.rb +71 -11
  4. data/lib/google/cloud/spanner/batch_client.rb +355 -0
  5. data/lib/google/cloud/spanner/batch_snapshot.rb +588 -0
  6. data/lib/google/cloud/spanner/client.rb +27 -20
  7. data/lib/google/cloud/spanner/commit.rb +6 -5
  8. data/lib/google/cloud/spanner/convert.rb +39 -0
  9. data/lib/google/cloud/spanner/credentials.rb +7 -7
  10. data/lib/google/cloud/spanner/data.rb +5 -5
  11. data/lib/google/cloud/spanner/database.rb +13 -7
  12. data/lib/google/cloud/spanner/database/job.rb +7 -2
  13. data/lib/google/cloud/spanner/database/list.rb +1 -1
  14. data/lib/google/cloud/spanner/fields.rb +16 -12
  15. data/lib/google/cloud/spanner/instance.rb +25 -13
  16. data/lib/google/cloud/spanner/instance/config.rb +2 -2
  17. data/lib/google/cloud/spanner/instance/config/list.rb +1 -1
  18. data/lib/google/cloud/spanner/instance/job.rb +7 -2
  19. data/lib/google/cloud/spanner/instance/list.rb +1 -1
  20. data/lib/google/cloud/spanner/partition.rb +208 -0
  21. data/lib/google/cloud/spanner/pool.rb +6 -6
  22. data/lib/google/cloud/spanner/project.rb +59 -16
  23. data/lib/google/cloud/spanner/results.rb +12 -5
  24. data/lib/google/cloud/spanner/service.rb +85 -61
  25. data/lib/google/cloud/spanner/session.rb +45 -9
  26. data/lib/google/cloud/spanner/snapshot.rb +10 -2
  27. data/lib/google/cloud/spanner/status.rb +6 -5
  28. data/lib/google/cloud/spanner/transaction.rb +11 -3
  29. data/lib/google/cloud/spanner/v1/doc/google/protobuf/duration.rb +1 -1
  30. data/lib/google/cloud/spanner/v1/doc/google/protobuf/struct.rb +1 -1
  31. data/lib/google/cloud/spanner/v1/doc/google/protobuf/timestamp.rb +1 -1
  32. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/keys.rb +1 -1
  33. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/mutation.rb +1 -1
  34. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/query_plan.rb +1 -1
  35. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/result_set.rb +1 -1
  36. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/spanner.rb +138 -6
  37. data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/transaction.rb +1 -1
  38. data/lib/google/cloud/spanner/v1/doc/overview.rb +6 -5
  39. data/lib/google/cloud/spanner/v1/spanner_client.rb +257 -33
  40. data/lib/google/cloud/spanner/v1/spanner_client_config.json +10 -0
  41. data/lib/google/cloud/spanner/version.rb +1 -1
  42. data/lib/google/spanner/v1/spanner_pb.rb +35 -0
  43. data/lib/google/spanner/v1/spanner_services_pb.rb +20 -2
  44. 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
- alias_method :query, :execute
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
- alias_method :save, :upsert
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
- fail ArgumentError, "Must provide a block" unless block_given?
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, &block
729
+ def transaction deadline: 120
725
730
  ensure_service!
726
731
  unless Thread.current[:transaction_id].nil?
727
- fail "Nested transactions are not allowed"
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
- block.call tx
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
- fail "Nested snapshots are not allowed"
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
- fail "Must have active connection to service" unless @project.service
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 = [:strong, :timestamp, :read_timestamp, :staleness,
977
- :exact_staleness, :bounded_timestamp,
978
- :min_read_timestamp, :bounded_staleness, :max_staleness]
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
- fail ArgumentError,
983
- "Must provide only one of the following single_use values: " \
984
- "#{valid_keys}"
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
- fail ArgumentError,
1022
- "Can only provide one of the following arguments: " \
1023
- "(strong, timestamp, read_timestamp, staleness, exact_staleness)"
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
- alias_method :save, :upsert
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 = Array(keys).map do |i|
336
- Convert.raw_to_value(Array(i)).list_value
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(https://www.googleapis.com/auth/cloud-platform
42
- https://www.googleapis.com/auth/spanner.data)
43
- PATH_ENV_VARS = %w(SPANNER_CREDENTIALS
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(SPANNER_CREDENTIALS_JSON
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.times.map { |i| self[i] }
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 == 0
117
- fail DuplicateNameError if name_count > 1
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
- fail DuplicateNameError if fields.duplicate_names?
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
- "#{value.inspect}"
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
- # database = instance.database "my-new-database"
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
- # fail with `FAILED_PRECONDITION` in this state.
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
- self.policy = policy
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.policy = policy # API call
297
+ # database.update_policy policy # API call
294
298
  #
295
- def policy= new_policy
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
- fail "Must have active connection to service" unless service
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
- # database = job.database
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
- alias_method :refresh!, :reload!
177
+ alias refresh! reload!
173
178
 
174
179
  ##
175
180
  # Reloads the job until the operation is complete. The delay between
@@ -162,7 +162,7 @@ module Google
162
162
  ##
163
163
  # Raise an error unless an active service is available.
164
164
  def ensure_service!
165
- fail "Must have active connection" unless @service
165
+ raise "Must have active connection" unless @service
166
166
  end
167
167
  end
168
168
  end
@@ -53,7 +53,7 @@ module Google
53
53
  @fields << field(type)
54
54
  end
55
55
  else
56
- fail ArgumentError, "can only accept Array or Hash"
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 == 0
139
- fail DuplicateNameError if name_count > 1
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.times.map { |i| self[i] }.map do |field|
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
- fail DuplicateNameError if duplicate_names?
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
- alias_method :new, :data
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
- "#{type.inspect}"
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
- fail ArgumentError, "can only accept pairs of name and type"
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
- fail ArgumentError, "type must be a symbol"
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