google-cloud-spanner 2.0.0 → 2.5.0

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/CONTRIBUTING.md +2 -2
  4. data/LOGGING.md +1 -1
  5. data/lib/google-cloud-spanner.rb +1 -0
  6. data/lib/google/cloud/spanner.rb +7 -5
  7. data/lib/google/cloud/spanner/backup.rb +10 -2
  8. data/lib/google/cloud/spanner/backup/job.rb +8 -8
  9. data/lib/google/cloud/spanner/backup/job/list.rb +2 -2
  10. data/lib/google/cloud/spanner/backup/list.rb +2 -2
  11. data/lib/google/cloud/spanner/batch_snapshot.rb +114 -15
  12. data/lib/google/cloud/spanner/batch_update.rb +3 -1
  13. data/lib/google/cloud/spanner/client.rb +413 -78
  14. data/lib/google/cloud/spanner/commit_response.rb +87 -0
  15. data/lib/google/cloud/spanner/commit_response/commit_stats.rb +51 -0
  16. data/lib/google/cloud/spanner/convert.rb +9 -0
  17. data/lib/google/cloud/spanner/data.rb +4 -5
  18. data/lib/google/cloud/spanner/database.rb +25 -3
  19. data/lib/google/cloud/spanner/database/backup_info.rb +12 -3
  20. data/lib/google/cloud/spanner/database/job/list.rb +2 -2
  21. data/lib/google/cloud/spanner/database/list.rb +4 -4
  22. data/lib/google/cloud/spanner/fields.rb +3 -2
  23. data/lib/google/cloud/spanner/instance/config/list.rb +4 -4
  24. data/lib/google/cloud/spanner/instance/list.rb +4 -4
  25. data/lib/google/cloud/spanner/partition.rb +4 -2
  26. data/lib/google/cloud/spanner/policy.rb +3 -2
  27. data/lib/google/cloud/spanner/pool.rb +10 -10
  28. data/lib/google/cloud/spanner/results.rb +105 -26
  29. data/lib/google/cloud/spanner/service.rb +218 -107
  30. data/lib/google/cloud/spanner/session.rb +361 -30
  31. data/lib/google/cloud/spanner/snapshot.rb +58 -4
  32. data/lib/google/cloud/spanner/status.rb +4 -1
  33. data/lib/google/cloud/spanner/transaction.rb +114 -8
  34. data/lib/google/cloud/spanner/version.rb +1 -1
  35. metadata +12 -10
@@ -29,7 +29,9 @@ module Google
29
29
  # {Google::Cloud::Spanner::Session} instances.
30
30
  #
31
31
  class Pool
32
- attr_accessor :all_sessions, :session_queue, :transaction_queue
32
+ attr_accessor :all_sessions
33
+ attr_accessor :session_queue
34
+ attr_accessor :transaction_queue
33
35
 
34
36
  def initialize client, min: 10, max: 100, keepalive: 1800,
35
37
  write_ratio: 0.3, fail: true, threads: nil
@@ -38,7 +40,7 @@ module Google
38
40
  @max = max
39
41
  @keepalive = keepalive
40
42
  @write_ratio = write_ratio
41
- @write_ratio = 0 if write_ratio < 0
43
+ @write_ratio = 0 if write_ratio.negative?
42
44
  @write_ratio = 1 if write_ratio > 1
43
45
  @fail = fail
44
46
  @threads = threads || [2, Concurrent.processor_count * 2].max
@@ -143,13 +145,13 @@ module Google
143
145
  return new_transaction! if action == :new
144
146
  end
145
147
 
146
- def checkin_transaction tx
148
+ def checkin_transaction txn
147
149
  @mutex.synchronize do
148
- unless all_sessions.include? tx.session
150
+ unless all_sessions.include? txn.session
149
151
  raise ArgumentError, "Cannot checkin session"
150
152
  end
151
153
 
152
- transaction_queue.push tx
154
+ transaction_queue.push txn
153
155
 
154
156
  @resource.signal
155
157
  end
@@ -182,7 +184,7 @@ module Google
182
184
  @mutex.synchronize do
183
185
  available_count = session_queue.count + transaction_queue.count
184
186
  release_count = @min - available_count
185
- release_count = 0 if release_count < 0
187
+ release_count = 0 if release_count.negative?
186
188
 
187
189
  to_keepalive += (session_queue + transaction_queue).select do |x|
188
190
  x.idle_since? @keepalive
@@ -282,10 +284,8 @@ module Google
282
284
  @keepalive_task.execute
283
285
  end
284
286
 
285
- def future
286
- Concurrent::Future.new executor: @thread_pool do
287
- yield
288
- end.execute
287
+ def future &block
288
+ Concurrent::Future.new(executor: @thread_pool, &block).execute
289
289
  end
290
290
  end
291
291
  end
@@ -41,6 +41,8 @@ module Google
41
41
  # end
42
42
  #
43
43
  class Results
44
+ RST_STREAM_INTERNAL_ERROR = "Received RST_STREAM".freeze
45
+ EOS_INTERNAL_ERROR = "Received unexpected EOS on DATA frame from server".freeze
44
46
  ##
45
47
  # The read timestamp chosen for single-use snapshots (read-only
46
48
  # transactions).
@@ -107,12 +109,24 @@ module Google
107
109
  buffer_upper_bound = 10
108
110
  chunked_value = nil
109
111
  resume_token = nil
112
+ should_resume_request = false
113
+ should_retry_request = false
110
114
 
111
115
  # Cannot call Enumerator#each because it won't return the first
112
116
  # value that was already identified when calling Enumerator#peek.
113
117
  # Iterate only using Enumerator#next and break on StopIteration.
114
118
  loop do
115
119
  begin
120
+ if should_resume_request
121
+ @enum = resume_request(resume_token)
122
+ buffered_responses = []
123
+ should_resume_request = false
124
+ elsif should_retry_request
125
+ @enum = retry_request()
126
+ buffered_responses = []
127
+ should_retry_request = false
128
+ end
129
+
116
130
  grpc = @enum.next
117
131
  # metadata should be set before the first iteration...
118
132
  @metadata ||= grpc.metadata
@@ -143,28 +157,36 @@ module Google
143
157
  # Flush the buffered responses now that they are all handled
144
158
  buffered_responses = []
145
159
  end
146
- rescue GRPC::Cancelled, GRPC::DeadlineExceeded, GRPC::Internal,
147
- GRPC::ResourceExhausted, GRPC::Unauthenticated,
148
- GRPC::Unavailable, GRPC::Core::CallError => err
149
- if resume_token.nil? || resume_token.empty?
150
- # Re-raise if the resume_token is not a valid value.
151
- # This can happen if the buffer was flushed.
152
- raise Google::Cloud::Error.from_error(err)
153
- end
160
+ # TODO: once the generated client throws only Google Cloud errors, remove
161
+ # the GRPC errors from the rescue block
162
+ rescue GRPC::Aborted,
163
+ GRPC::Cancelled,
164
+ GRPC::DeadlineExceeded,
165
+ GRPC::Internal,
166
+ GRPC::ResourceExhausted,
167
+ GRPC::Unauthenticated,
168
+ GRPC::Unavailable,
169
+ GRPC::Core::CallError,
170
+ Google::Cloud::AbortedError,
171
+ Google::Cloud::CanceledError,
172
+ Google::Cloud::DeadlineExceededError,
173
+ Google::Cloud::InternalError,
174
+ Google::Cloud::ResourceExhaustedError,
175
+ Google::Cloud::UnauthenticatedError,
176
+ Google::Cloud::UnavailableError => err
154
177
 
155
- # Resume the stream from the last known resume_token
156
- if @execute_query_options
157
- @enum = @service.execute_streaming_sql \
158
- @session_path, @sql,
159
- @execute_query_options.merge(resume_token: resume_token)
178
+ if resumable?(resume_token)
179
+ should_resume_request = true
180
+ elsif retryable?(err)
181
+ should_retry_request = true
182
+ elsif err.is_a?(Google::Cloud::Error)
183
+ raise err
160
184
  else
161
- @enum = @service.streaming_read_table \
162
- @session_path, @table, @columns,
163
- @read_options.merge(resume_token: resume_token)
185
+ raise Google::Cloud::Error.from_error(err)
164
186
  end
165
187
 
166
- # Flush the buffered responses to reset to the resume_token
167
- buffered_responses = []
188
+ # TODO: once the generated client throws only Google Cloud errors, remove
189
+ # this rescue block (for GRPC::BadStatus)
168
190
  rescue GRPC::BadStatus => err
169
191
  raise Google::Cloud::Error.from_error(err)
170
192
  rescue StopIteration
@@ -198,6 +220,60 @@ module Google
198
220
 
199
221
  # rubocop:enable all
200
222
 
223
+ ##
224
+ # @private
225
+ # Checks if a request can be resumed by inspecting the resume token
226
+ def resumable? resume_token
227
+ resume_token && !resume_token.empty?
228
+ end
229
+
230
+ ##
231
+ # @private
232
+ # Checks if a request can be retried. This is based on the error returned.
233
+ # Retryable errors are:
234
+ # - Unavailable error
235
+ # - Internal EOS error
236
+ # - Internal RST_STREAM error
237
+ def retryable? err
238
+ err.instance_of?(Google::Cloud::UnavailableError) ||
239
+ err.instance_of?(GRPC::Unavailable) ||
240
+ (err.instance_of?(Google::Cloud::InternalError) && err.message.include?(EOS_INTERNAL_ERROR)) ||
241
+ (err.instance_of?(GRPC::Internal) && err.details.include?(EOS_INTERNAL_ERROR)) ||
242
+ (err.instance_of?(Google::Cloud::InternalError) && err.message.include?(RST_STREAM_INTERNAL_ERROR)) ||
243
+ (err.instance_of?(GRPC::Internal) && err.details.include?(RST_STREAM_INTERNAL_ERROR))
244
+ end
245
+
246
+ ##
247
+ # @private
248
+ # Resumes a request, by re-executing it with a resume token.
249
+ def resume_request resume_token
250
+ if @execute_query_options
251
+ @service.execute_streaming_sql(
252
+ @session_path,
253
+ @sql,
254
+ **@execute_query_options.merge(resume_token: resume_token)
255
+ )
256
+ else
257
+ @service.streaming_read_table(
258
+ @session_path,
259
+ @table,
260
+ @columns,
261
+ **@read_options.merge(resume_token: resume_token)
262
+ )
263
+ end
264
+ end
265
+
266
+ ##
267
+ # @private
268
+ # Retries a request, by re-executing it from scratch.
269
+ def retry_request
270
+ if @execute_query_options
271
+ @service.execute_streaming_sql @session_path, @sql, **@execute_query_options
272
+ else
273
+ @service.streaming_read_table @session_path, @table, @columns, **@read_options
274
+ end
275
+ end
276
+
201
277
  ##
202
278
  # @private
203
279
  # Get row count from stats. This will be the exact row count for DML
@@ -243,14 +319,14 @@ module Google
243
319
  def self.execute_query service, session_path, sql, params: nil,
244
320
  types: nil, transaction: nil,
245
321
  partition_token: nil, seqno: nil,
246
- query_options: nil
322
+ query_options: nil, call_options: nil
247
323
  execute_query_options = {
248
324
  transaction: transaction, params: params, types: types,
249
325
  partition_token: partition_token, seqno: seqno,
250
- query_options: query_options
326
+ query_options: query_options, call_options: call_options
251
327
  }
252
328
  enum = service.execute_streaming_sql session_path, sql,
253
- execute_query_options
329
+ **execute_query_options
254
330
  from_enum(enum, service).tap do |results|
255
331
  results.instance_variable_set :@session_path, session_path
256
332
  results.instance_variable_set :@sql, sql
@@ -262,12 +338,15 @@ module Google
262
338
  # @private
263
339
  def self.read service, session_path, table, columns, keys: nil,
264
340
  index: nil, limit: nil, transaction: nil,
265
- partition_token: nil
266
- read_options = { keys: keys, index: index, limit: limit,
267
- transaction: transaction,
268
- partition_token: partition_token }
341
+ partition_token: nil, call_options: nil
342
+ read_options = {
343
+ keys: keys, index: index, limit: limit,
344
+ transaction: transaction,
345
+ partition_token: partition_token,
346
+ call_options: call_options
347
+ }
269
348
  enum = service.streaming_read_table \
270
- session_path, table, columns, read_options
349
+ session_path, table, columns, **read_options
271
350
  from_enum(enum, service).tap do |results|
272
351
  results.instance_variable_set :@session_path, session_path
273
352
  results.instance_variable_set :@table, table
@@ -28,8 +28,12 @@ module Google
28
28
  # @private Represents the gRPC Spanner service, including all the API
29
29
  # methods.
30
30
  class Service
31
- attr_accessor :project, :credentials, :timeout, :host, :lib_name,
32
- :lib_version
31
+ attr_accessor :project
32
+ attr_accessor :credentials
33
+ attr_accessor :timeout
34
+ attr_accessor :host
35
+ attr_accessor :lib_name
36
+ attr_accessor :lib_version
33
37
 
34
38
  ##
35
39
  # Creates a new Service instance.
@@ -105,19 +109,26 @@ module Google
105
109
  credentials == :this_channel_is_insecure
106
110
  end
107
111
 
108
- def list_instances token: nil, max: nil
109
- paged_enum = instances.list_instances parent: project_path,
110
- page_size: max,
111
- page_token: token
112
+ def list_instances token: nil, max: nil, call_options: nil
113
+ opts = default_options call_options: call_options
114
+ request = {
115
+ parent: project_path,
116
+ page_size: max,
117
+ page_token: token
118
+ }
119
+ paged_enum = instances.list_instances request, opts
112
120
  paged_enum.response
113
121
  end
114
122
 
115
- def get_instance name
116
- instances.get_instance name: instance_path(name)
123
+ def get_instance name, call_options: nil
124
+ opts = default_options call_options: call_options
125
+ request = { name: instance_path(name) }
126
+ instances.get_instance request, opts
117
127
  end
118
128
 
119
129
  def create_instance instance_id, name: nil, config: nil, nodes: nil,
120
- labels: nil
130
+ labels: nil, call_options: nil
131
+ opts = default_options call_options: call_options
121
132
  labels = Hash[labels.map { |k, v| [String(k), String(v)] }] if labels
122
133
 
123
134
  create_obj = Admin::Instance::V1::Instance.new({
@@ -125,116 +136,163 @@ module Google
125
136
  node_count: nodes, labels: labels
126
137
  }.delete_if { |_, v| v.nil? })
127
138
 
128
- instances.create_instance parent: project_path,
129
- instance_id: instance_id,
130
- instance: create_obj
139
+ request = {
140
+ parent: project_path,
141
+ instance_id: instance_id,
142
+ instance: create_obj
143
+ }
144
+ instances.create_instance request, opts
131
145
  end
132
146
 
133
- def update_instance instance
147
+ def update_instance instance, call_options: nil
148
+ opts = default_options call_options: call_options
134
149
  mask = Google::Protobuf::FieldMask.new(
135
150
  paths: %w[display_name node_count labels]
136
151
  )
137
-
138
- instances.update_instance instance: instance, field_mask: mask
152
+ request = { instance: instance, field_mask: mask }
153
+ instances.update_instance request, opts
139
154
  end
140
155
 
141
- def delete_instance name
142
- instances.delete_instance name: instance_path(name)
156
+ def delete_instance name, call_options: nil
157
+ opts = default_options call_options: call_options
158
+ request = { name: instance_path(name) }
159
+ instances.delete_instance request, opts
143
160
  end
144
161
 
145
- def get_instance_policy name
146
- instances.get_iam_policy resource: instance_path(name)
162
+ def get_instance_policy name, call_options: nil
163
+ opts = default_options call_options: call_options
164
+ request = { resource: instance_path(name) }
165
+ instances.get_iam_policy request, opts
147
166
  end
148
167
 
149
- def set_instance_policy name, new_policy
150
- instances.set_iam_policy resource: instance_path(name),
151
- policy: new_policy
168
+ def set_instance_policy name, new_policy, call_options: nil
169
+ opts = default_options call_options: call_options
170
+ request = {
171
+ resource: instance_path(name),
172
+ policy: new_policy
173
+ }
174
+ instances.set_iam_policy request, opts
152
175
  end
153
176
 
154
- def test_instance_permissions name, permissions
155
- instances.test_iam_permissions resource: instance_path(name),
156
- permissions: permissions
177
+ def test_instance_permissions name, permissions, call_options: nil
178
+ opts = default_options call_options: call_options
179
+ request = {
180
+ resource: instance_path(name),
181
+ permissions: permissions
182
+ }
183
+ instances.test_iam_permissions request, opts
157
184
  end
158
185
 
159
- def list_instance_configs token: nil, max: nil
160
- paged_enum = instances.list_instance_configs \
161
- parent: project_path, page_size: max, page_token: token
186
+ def list_instance_configs token: nil, max: nil, call_options: nil
187
+ opts = default_options call_options: call_options
188
+ request = { parent: project_path, page_size: max, page_token: token }
189
+ paged_enum = instances.list_instance_configs request, opts
162
190
  paged_enum.response
163
191
  end
164
192
 
165
- def get_instance_config name
166
- instances.get_instance_config name: instance_config_path(name)
193
+ def get_instance_config name, call_options: nil
194
+ opts = default_options call_options: call_options
195
+ request = { name: instance_config_path(name) }
196
+ instances.get_instance_config request, opts
167
197
  end
168
198
 
169
- def list_databases instance_id, token: nil, max: nil
170
- paged_enum = databases.list_databases \
199
+ def list_databases instance_id, token: nil, max: nil, call_options: nil
200
+ opts = default_options call_options: call_options
201
+ request = {
171
202
  parent: instance_path(instance_id),
172
203
  page_size: max,
173
204
  page_token: token
205
+ }
206
+ paged_enum = databases.list_databases request, opts
174
207
  paged_enum.response
175
208
  end
176
209
 
177
- def get_database instance_id, database_id
178
- databases.get_database name: database_path(instance_id, database_id)
210
+ def get_database instance_id, database_id, call_options: nil
211
+ opts = default_options call_options: call_options
212
+ request = { name: database_path(instance_id, database_id) }
213
+ databases.get_database request, opts
179
214
  end
180
215
 
181
- def create_database instance_id, database_id, statements: []
182
- databases.create_database \
216
+ def create_database instance_id, database_id, statements: [],
217
+ call_options: nil
218
+ opts = default_options call_options: call_options
219
+ request = {
183
220
  parent: instance_path(instance_id),
184
221
  create_statement: "CREATE DATABASE `#{database_id}`",
185
222
  extra_statements: Array(statements)
223
+ }
224
+ databases.create_database request, opts
186
225
  end
187
226
 
188
- def drop_database instance_id, database_id
189
- databases.drop_database \
190
- database: database_path(instance_id, database_id)
227
+ def drop_database instance_id, database_id, call_options: nil
228
+ opts = default_options call_options: call_options
229
+ request = { database: database_path(instance_id, database_id) }
230
+ databases.drop_database request, opts
191
231
  end
192
232
 
193
- def get_database_ddl instance_id, database_id
194
- databases.get_database_ddl \
195
- database: database_path(instance_id, database_id)
233
+ def get_database_ddl instance_id, database_id, call_options: nil
234
+ opts = default_options call_options: call_options
235
+ request = { database: database_path(instance_id, database_id) }
236
+ databases.get_database_ddl request, opts
196
237
  end
197
238
 
198
239
  def update_database_ddl instance_id, database_id, statements: [],
199
- operation_id: nil
200
- databases.update_database_ddl \
240
+ operation_id: nil, call_options: nil
241
+ opts = default_options call_options: call_options
242
+ request = {
201
243
  database: database_path(instance_id, database_id),
202
244
  statements: Array(statements),
203
245
  operation_id: operation_id
246
+ }
247
+ databases.update_database_ddl request, opts
204
248
  end
205
249
 
206
- def get_database_policy instance_id, database_id
207
- databases.get_iam_policy \
208
- resource: database_path(instance_id, database_id)
250
+ def get_database_policy instance_id, database_id, call_options: nil
251
+ opts = default_options call_options: call_options
252
+ request = { resource: database_path(instance_id, database_id) }
253
+ databases.get_iam_policy request, opts
209
254
  end
210
255
 
211
- def set_database_policy instance_id, database_id, new_policy
212
- databases.set_iam_policy \
256
+ def set_database_policy instance_id, database_id, new_policy,
257
+ call_options: nil
258
+ opts = default_options call_options: call_options
259
+ request = {
213
260
  resource: database_path(instance_id, database_id),
214
261
  policy: new_policy
262
+ }
263
+ databases.set_iam_policy request, opts
215
264
  end
216
265
 
217
- def test_database_permissions instance_id, database_id, permissions
218
- databases.test_iam_permissions \
266
+ def test_database_permissions instance_id, database_id, permissions,
267
+ call_options: nil
268
+ opts = default_options call_options: call_options
269
+ request = {
219
270
  resource: database_path(instance_id, database_id),
220
271
  permissions: permissions
272
+ }
273
+ databases.test_iam_permissions request, opts
221
274
  end
222
275
 
223
- def get_session session_name
224
- opts = default_options_from_session session_name
276
+ def get_session session_name, call_options: nil
277
+ opts = default_options session_name: session_name,
278
+ call_options: call_options
225
279
  service.get_session({ name: session_name }, opts)
226
280
  end
227
281
 
228
- def create_session database_name, labels: nil
229
- opts = default_options_from_session database_name
282
+ def create_session database_name, labels: nil,
283
+ call_options: nil
284
+ opts = default_options session_name: database_name,
285
+ call_options: call_options
230
286
  session = V1::Session.new labels: labels if labels
231
287
  service.create_session(
232
288
  { database: database_name, session: session }, opts
233
289
  )
234
290
  end
235
291
 
236
- def batch_create_sessions database_name, session_count, labels: nil
237
- opts = default_options_from_session database_name
292
+ def batch_create_sessions database_name, session_count, labels: nil,
293
+ call_options: nil
294
+ opts = default_options session_name: database_name,
295
+ call_options: call_options
238
296
  session = V1::Session.new labels: labels if labels
239
297
  # The response may have fewer sessions than requested in the RPC.
240
298
  request = {
@@ -245,16 +303,18 @@ module Google
245
303
  service.batch_create_sessions request, opts
246
304
  end
247
305
 
248
- def delete_session session_name
249
- opts = default_options_from_session session_name
306
+ def delete_session session_name, call_options: nil
307
+ opts = default_options session_name: session_name,
308
+ call_options: call_options
250
309
  service.delete_session({ name: session_name }, opts)
251
310
  end
252
311
 
253
312
  def execute_streaming_sql session_name, sql, transaction: nil,
254
313
  params: nil, types: nil, resume_token: nil,
255
314
  partition_token: nil, seqno: nil,
256
- query_options: nil
257
- opts = default_options_from_session session_name
315
+ query_options: nil, call_options: nil
316
+ opts = default_options session_name: session_name,
317
+ call_options: call_options
258
318
  request = {
259
319
  session: session_name,
260
320
  sql: sql,
@@ -269,8 +329,10 @@ module Google
269
329
  service.execute_streaming_sql request, opts
270
330
  end
271
331
 
272
- def execute_batch_dml session_name, transaction, statements, seqno
273
- opts = default_options_from_session session_name
332
+ def execute_batch_dml session_name, transaction, statements, seqno,
333
+ call_options: nil
334
+ opts = default_options session_name: session_name,
335
+ call_options: call_options
274
336
  statements = statements.map(&:to_grpc)
275
337
  request = {
276
338
  session: session_name,
@@ -293,8 +355,10 @@ module Google
293
355
 
294
356
  def streaming_read_table session_name, table_name, columns, keys: nil,
295
357
  index: nil, transaction: nil, limit: nil,
296
- resume_token: nil, partition_token: nil
297
- opts = default_options_from_session session_name
358
+ resume_token: nil, partition_token: nil,
359
+ call_options: nil
360
+ opts = default_options session_name: session_name,
361
+ call_options: call_options
298
362
  request = {
299
363
  session: session_name, table: table_name, columns: columns,
300
364
  key_set: keys, transaction: transaction, index: index,
@@ -306,11 +370,12 @@ module Google
306
370
 
307
371
  def partition_read session_name, table_name, columns, transaction,
308
372
  keys: nil, index: nil, partition_size_bytes: nil,
309
- max_partitions: nil
373
+ max_partitions: nil, call_options: nil
310
374
  partition_opts = partition_options partition_size_bytes,
311
375
  max_partitions
312
376
 
313
- opts = default_options_from_session session_name
377
+ opts = default_options session_name: session_name,
378
+ call_options: call_options
314
379
  request = {
315
380
  session: session_name, table: table_name, key_set: keys,
316
381
  transaction: transaction, index: index, columns: columns,
@@ -321,11 +386,12 @@ module Google
321
386
 
322
387
  def partition_query session_name, sql, transaction, params: nil,
323
388
  types: nil, partition_size_bytes: nil,
324
- max_partitions: nil
389
+ max_partitions: nil, call_options: nil
325
390
  partition_opts = partition_options partition_size_bytes,
326
391
  max_partitions
327
392
 
328
- opts = default_options_from_session session_name
393
+ opts = default_options session_name: session_name,
394
+ call_options: call_options
329
395
  request = {
330
396
  session: session_name, sql: sql, transaction: transaction,
331
397
  params: params, param_types: types,
@@ -334,38 +400,47 @@ module Google
334
400
  service.partition_query request, opts
335
401
  end
336
402
 
337
- def commit session_name, mutations = [], transaction_id: nil
403
+ def commit session_name, mutations = [], transaction_id: nil,
404
+ commit_options: nil, call_options: nil
338
405
  tx_opts = nil
339
406
  if transaction_id.nil?
340
407
  tx_opts = V1::TransactionOptions.new(
341
408
  read_write: V1::TransactionOptions::ReadWrite.new
342
409
  )
343
410
  end
344
- opts = default_options_from_session session_name
411
+ opts = default_options session_name: session_name,
412
+ call_options: call_options
345
413
  request = {
346
414
  session: session_name, transaction_id: transaction_id,
347
415
  single_use_transaction: tx_opts, mutations: mutations
348
416
  }
417
+
418
+ if commit_options
419
+ request[:return_commit_stats] = commit_options[:return_commit_stats]
420
+ end
421
+
349
422
  service.commit request, opts
350
423
  end
351
424
 
352
- def rollback session_name, transaction_id
353
- opts = default_options_from_session session_name
425
+ def rollback session_name, transaction_id, call_options: nil
426
+ opts = default_options session_name: session_name,
427
+ call_options: call_options
354
428
  request = { session: session_name, transaction_id: transaction_id }
355
429
  service.rollback request, opts
356
430
  end
357
431
 
358
- def begin_transaction session_name
432
+ def begin_transaction session_name, call_options: nil
359
433
  tx_opts = V1::TransactionOptions.new(
360
434
  read_write: V1::TransactionOptions::ReadWrite.new
361
435
  )
362
- opts = default_options_from_session session_name
436
+ opts = default_options session_name: session_name,
437
+ call_options: call_options
363
438
  request = { session: session_name, options: tx_opts }
364
439
  service.begin_transaction request, opts
365
440
  end
366
441
 
367
442
  def create_snapshot session_name, strong: nil, timestamp: nil,
368
- staleness: nil
443
+ staleness: nil, call_options: nil
369
444
  tx_opts = V1::TransactionOptions.new(
370
445
  read_only: V1::TransactionOptions::ReadOnly.new(
371
446
  {
@@ -376,80 +451,108 @@ module Google
376
451
  }.delete_if { |_, v| v.nil? }
377
452
  )
378
453
  )
379
- opts = default_options_from_session session_name
454
+ opts = default_options session_name: session_name,
455
+ call_options: call_options
380
456
  request = { session: session_name, options: tx_opts }
381
457
  service.begin_transaction request, opts
382
458
  end
383
459
 
384
- def create_pdml session_name
460
+ def create_pdml session_name, call_options: nil
385
461
  tx_opts = V1::TransactionOptions.new(
386
462
  partitioned_dml: V1::TransactionOptions::PartitionedDml.new
387
463
  )
388
- opts = default_options_from_session session_name
464
+ opts = default_options session_name: session_name,
465
+ call_options: call_options
389
466
  request = { session: session_name, options: tx_opts }
390
467
  service.begin_transaction request, opts
391
468
  end
392
469
 
393
- def create_backup instance_id, database_id, backup_id, expire_time
470
+ def create_backup instance_id, database_id, backup_id, expire_time,
471
+ version_time, call_options: nil
472
+ opts = default_options call_options: call_options
394
473
  backup = {
395
474
  database: database_path(instance_id, database_id),
396
- expire_time: expire_time
475
+ expire_time: expire_time,
476
+ version_time: version_time
477
+ }
478
+ request = {
479
+ parent: instance_path(instance_id),
480
+ backup_id: backup_id,
481
+ backup: backup
397
482
  }
398
- databases.create_backup parent: instance_path(instance_id),
399
- backup_id: backup_id,
400
- backup: backup
483
+ databases.create_backup request, opts
401
484
  end
402
485
 
403
- def get_backup instance_id, backup_id
404
- databases.get_backup name: backup_path(instance_id, backup_id)
486
+ def get_backup instance_id, backup_id, call_options: nil
487
+ opts = default_options call_options: call_options
488
+ request = { name: backup_path(instance_id, backup_id) }
489
+ databases.get_backup request, opts
405
490
  end
406
491
 
407
- def update_backup backup, update_mask
408
- databases.update_backup backup: backup, update_mask: update_mask
492
+ def update_backup backup, update_mask, call_options: nil
493
+ opts = default_options call_options: call_options
494
+ request = { backup: backup, update_mask: update_mask }
495
+ databases.update_backup request, opts
409
496
  end
410
497
 
411
- def delete_backup instance_id, backup_id
412
- databases.delete_backup name: backup_path(instance_id, backup_id)
498
+ def delete_backup instance_id, backup_id, call_options: nil
499
+ opts = default_options call_options: call_options
500
+ request = { name: backup_path(instance_id, backup_id) }
501
+ databases.delete_backup request, opts
413
502
  end
414
503
 
415
504
  def list_backups instance_id,
416
- filter: nil, page_size: nil, page_token: nil
417
- databases.list_backups parent: instance_path(instance_id),
418
- filter: filter,
419
- page_size: page_size,
420
- page_token: page_token
505
+ filter: nil, page_size: nil, page_token: nil,
506
+ call_options: nil
507
+ opts = default_options call_options: call_options
508
+ request = {
509
+ parent: instance_path(instance_id),
510
+ filter: filter,
511
+ page_size: page_size,
512
+ page_token: page_token
513
+ }
514
+ databases.list_backups request, opts
421
515
  end
422
516
 
423
517
  def list_database_operations instance_id,
424
518
  filter: nil,
425
519
  page_size: nil,
426
- page_token: nil
427
- databases.list_database_operations(
520
+ page_token: nil,
521
+ call_options: nil
522
+ opts = default_options call_options: call_options
523
+ request = {
428
524
  parent: instance_path(instance_id),
429
525
  filter: filter,
430
526
  page_size: page_size,
431
527
  page_token: page_token
432
- )
528
+ }
529
+ databases.list_database_operations request, opts
433
530
  end
434
531
 
435
532
  def list_backup_operations instance_id,
436
533
  filter: nil, page_size: nil,
437
- page_token: nil
438
- databases.list_backup_operations(
534
+ page_token: nil,
535
+ call_options: nil
536
+ opts = default_options call_options: call_options
537
+ request = {
439
538
  parent: instance_path(instance_id),
440
539
  filter: filter,
441
540
  page_size: page_size,
442
541
  page_token: page_token
443
- )
542
+ }
543
+ databases.list_backup_operations request, opts
444
544
  end
445
545
 
446
546
  def restore_database backup_instance_id, backup_id,
447
- database_instance_id, database_id
448
- databases.restore_database(
547
+ database_instance_id, database_id,
548
+ call_options: nil
549
+ opts = default_options call_options: call_options
550
+ request = {
449
551
  parent: instance_path(database_instance_id),
450
552
  database_id: database_id,
451
553
  backup: backup_path(backup_instance_id, backup_id)
452
- )
554
+ }
555
+ databases.restore_database request, opts
453
556
  end
454
557
 
455
558
  def inspect
@@ -466,9 +569,17 @@ module Google
466
569
  value << " gccl"
467
570
  end
468
571
 
469
- def default_options_from_session session_name
470
- default_prefix = session_name.split("/sessions/").first
471
- { metadata: { "google-cloud-resource-prefix" => default_prefix } }
572
+ def default_options session_name: nil, call_options: nil
573
+ opts = {}
574
+ if session_name
575
+ default_prefix = session_name.split("/sessions/").first
576
+ opts[:metadata] = { "google-cloud-resource-prefix" => default_prefix }
577
+ end
578
+ if call_options
579
+ opts[:timeout] = call_options[:timeout] if call_options[:timeout]
580
+ opts[:retry_policy] = call_options[:retry_policy] if call_options[:retry_policy]
581
+ end
582
+ return opts unless opts.empty?
472
583
  end
473
584
 
474
585
  def partition_options partition_size_bytes, max_partitions