google-cloud-spanner 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
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