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
@@ -0,0 +1,588 @@
1
+ # Copyright 2018 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
+ # https://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
+
16
+ require "google/cloud/spanner/convert"
17
+ require "google/cloud/spanner/session"
18
+ require "google/cloud/spanner/partition"
19
+ require "google/cloud/spanner/results"
20
+ require "json"
21
+ require "base64"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Spanner
26
+ ##
27
+ # # BatchSnapshot
28
+ #
29
+ # Represents a read-only transaction that can be configured to read at
30
+ # timestamps in the past and allows for exporting arbitrarily large
31
+ # amounts of data from Cloud Spanner databases. This is a snapshot which
32
+ # additionally allows to partition a read or query request. The read/query
33
+ # request can then be executed independently over each partition while
34
+ # observing the same snapshot of the database. A BatchSnapshot can also be
35
+ # shared across multiple processes/machines by passing around its
36
+ # serialized value and then recreating the transaction using
37
+ # {BatchClient#dump}.
38
+ #
39
+ # Unlike locking read-write transactions, BatchSnapshot will never abort.
40
+ # They can fail if the chosen read timestamp is garbage collected; however
41
+ # any read or query activity within an hour on the transaction avoids
42
+ # garbage collection and most applications do not need to worry about this
43
+ # in practice.
44
+ #
45
+ # See {BatchClient#batch_snapshot} and {BatchClient#load_batch_snapshot}.
46
+ #
47
+ # @example
48
+ # require "google/cloud/spanner"
49
+ #
50
+ # spanner = Google::Cloud::Spanner.new
51
+ #
52
+ # batch_client = spanner.batch_client "my-instance", "my-database"
53
+ # batch_snapshot = batch_client.batch_snapshot
54
+ #
55
+ # partitions = batch_snapshot.partition_read "users", [:id, :name]
56
+ #
57
+ # partition = partitions.first
58
+ # results = batch_snapshot.execute_partition partition
59
+ #
60
+ # batch_snapshot.close
61
+ #
62
+ class BatchSnapshot
63
+ # @private The transaction grpc object.
64
+ attr_reader :grpc
65
+
66
+ # @private The Session object.
67
+ attr_reader :session
68
+
69
+ ##
70
+ # @private Creates a BatchSnapshot object.
71
+ def initialize grpc, session
72
+ @grpc = grpc
73
+ @session = session
74
+ end
75
+
76
+ ##
77
+ # Identifier of the batch snapshot transaction.
78
+ # @return [String] The transaction id.
79
+ def transaction_id
80
+ return nil if grpc.nil?
81
+ grpc.id
82
+ end
83
+
84
+ ##
85
+ # The read timestamp chosen for batch snapshot.
86
+ # @return [Time] The chosen timestamp.
87
+ def timestamp
88
+ return nil if grpc.nil?
89
+ Convert.timestamp_to_time grpc.read_timestamp
90
+ end
91
+
92
+ ##
93
+ # Returns a list of {Partition} objects to execute a batch query against
94
+ # a database.
95
+ #
96
+ # These partitions can be executed across multiple processes, even
97
+ # across different machines. The partition size and count can be
98
+ # configured, although the values given may not necessarily be honored
99
+ # depending on the query and options in the request.
100
+ #
101
+ # The query must have a single [distributed
102
+ # union](https://cloud.google.com/spanner/docs/query-execution-operators#distributed_union)
103
+ # operator at the root of the query plan. Such queries are
104
+ # root-partitionable. If a query cannot be partitioned at the root,
105
+ # Cloud Spanner cannot achieve the parallelism and in this case
106
+ # partition generation will fail.
107
+ #
108
+ # @param [String] sql The SQL query string. See [Query
109
+ # syntax](https://cloud.google.com/spanner/docs/query-syntax).
110
+ #
111
+ # The SQL query string can contain parameter placeholders. A parameter
112
+ # placeholder consists of "@" followed by the parameter name.
113
+ # Parameter names consist of any combination of letters, numbers, and
114
+ # underscores.
115
+ # @param [Integer] partition_size_bytes The desired data size for each
116
+ # partition generated. This is only a hint. The actual size of each
117
+ # partition may be smaller or larger than this size request.
118
+ # @param [Integer] max_partitions The desired maximum number of
119
+ # partitions to return. For example, this may be set to the number of
120
+ # workers available. This is only a hint and may provide different
121
+ # results based on the request.
122
+ # @param [Hash] params SQL parameters for the query string. The
123
+ # parameter placeholders, minus the "@", are the the hash keys, and
124
+ # the literal values are the hash values. If the query string contains
125
+ # something like "WHERE id > @msg_id", then the params must contain
126
+ # something like `:msg_id => 1`.
127
+ # @param [Hash] types Types of the SQL parameters in `params`. It is not
128
+ # always possible for Cloud Spanner to infer the right SQL type from a
129
+ # value in `params`. In these cases, the `types` hash can be used to
130
+ # specify the exact SQL type for some or all of the SQL query
131
+ # parameters.
132
+ #
133
+ # The keys of the hash should be query string parameter placeholders,
134
+ # minus the "@". The values of the hash should be Cloud Spanner type
135
+ # codes from the following list:
136
+ #
137
+ # * `:BOOL`
138
+ # * `:BYTES`
139
+ # * `:DATE`
140
+ # * `:FLOAT64`
141
+ # * `:INT64`
142
+ # * `:STRING`
143
+ # * `:TIMESTAMP`
144
+ #
145
+ # Arrays are specified by providing the type code in an array. For
146
+ # example, an array of integers are specified as `[:INT64]`.
147
+ #
148
+ # Structs are not yet supported in query parameters.
149
+ #
150
+ # Types are optional.
151
+ #
152
+ # @return [Array<Google::Cloud::Spanner::Partition>] The partitions
153
+ # created by the query partition.
154
+ #
155
+ # @example
156
+ # require "google/cloud/spanner"
157
+ #
158
+ # spanner = Google::Cloud::Spanner.new
159
+ #
160
+ # batch_client = spanner.batch_client "my-instance", "my-database"
161
+ # batch_snapshot = batch_client.batch_snapshot
162
+ #
163
+ # sql = "SELECT u.id, u.active FROM users AS u \
164
+ # WHERE u.id < 2000 AND u.active = false"
165
+ # partitions = batch_snapshot.partition_query sql
166
+ #
167
+ # partition = partitions.first
168
+ # results = batch_snapshot.execute_partition partition
169
+ #
170
+ # batch_snapshot.close
171
+ #
172
+ def partition_query sql, params: nil, types: nil,
173
+ partition_size_bytes: nil, max_partitions: nil
174
+ ensure_session!
175
+
176
+ params, types = Convert.to_input_params_and_types params, types
177
+
178
+ results = session.partition_query \
179
+ sql, tx_selector, params: params, types: types,
180
+ partition_size_bytes: partition_size_bytes,
181
+ max_partitions: max_partitions
182
+
183
+ results.partitions.map do |grpc|
184
+ # Convert partition protos to execute sql request protos
185
+ execute_grpc = Google::Spanner::V1::ExecuteSqlRequest.new(
186
+ {
187
+ session: session.path,
188
+ sql: sql,
189
+ params: params,
190
+ param_types: types,
191
+ transaction: tx_selector,
192
+ partition_token: grpc.partition_token
193
+ }.delete_if { |_, v| v.nil? }
194
+ )
195
+ Partition.from_execute_grpc execute_grpc
196
+ end
197
+ end
198
+
199
+ ##
200
+ # Returns a list of {Partition} objects to read zero or more rows from a
201
+ # database.
202
+ #
203
+ # These partitions can be executed across multiple processes, even
204
+ # across different machines. The partition size and count can be
205
+ # configured, although the values given may not necessarily be honored
206
+ # depending on the query and options in the request.
207
+ #
208
+ # @param [String] table The name of the table in the database to be
209
+ # read.
210
+ # @param [Array<String, Symbol>] columns The columns of table to be
211
+ # returned for each row matching this request.
212
+ # @param [Object, Array<Object>] keys A single, or list of keys or key
213
+ # ranges to match returned data to. Values should have exactly as many
214
+ # elements as there are columns in the primary key.
215
+ # @param [String] index The name of an index to use instead of the
216
+ # table's primary key when interpreting `id` and sorting result rows.
217
+ # Optional.
218
+ # @param [Integer] partition_size_bytes The desired data size for each
219
+ # partition generated. This is only a hint. The actual size of each
220
+ # partition may be smaller or larger than this size request.
221
+ # @param [Integer] max_partitions The desired maximum number of
222
+ # partitions to return. For example, this may be set to the number of
223
+ # workers available. This is only a hint and may provide different
224
+ # results based on the request.
225
+ #
226
+ # @return [Array<Google::Cloud::Spanner::Partition>] The partitions
227
+ # created by the read partition.
228
+ #
229
+ # @example
230
+ # require "google/cloud/spanner"
231
+ #
232
+ # spanner = Google::Cloud::Spanner.new
233
+ #
234
+ # batch_client = spanner.batch_client "my-instance", "my-database"
235
+ # batch_snapshot = batch_client.batch_snapshot
236
+ #
237
+ # partitions = batch_snapshot.partition_read "users", [:id, :name]
238
+ #
239
+ # partition = partitions.first
240
+ # results = batch_snapshot.execute_partition partition
241
+ #
242
+ # batch_snapshot.close
243
+ #
244
+ def partition_read table, columns, keys: nil, index: nil,
245
+ partition_size_bytes: nil, max_partitions: nil
246
+ ensure_session!
247
+
248
+ columns = Array(columns).map(&:to_s)
249
+ keys = Convert.to_key_set keys
250
+
251
+ results = session.partition_read \
252
+ table, columns, tx_selector,
253
+ keys: keys, index: index,
254
+ partition_size_bytes: partition_size_bytes,
255
+ max_partitions: max_partitions
256
+
257
+ results.partitions.map do |grpc|
258
+ # Convert partition protos to read request protos
259
+ read_grpc = Google::Spanner::V1::ReadRequest.new(
260
+ {
261
+ session: session.path,
262
+ table: table,
263
+ columns: columns,
264
+ key_set: keys,
265
+ index: index,
266
+ transaction: tx_selector,
267
+ partition_token: grpc.partition_token
268
+ }.delete_if { |_, v| v.nil? }
269
+ )
270
+ Partition.from_read_grpc read_grpc
271
+ end
272
+ end
273
+
274
+ ##
275
+ # Execute the partition to return a {ResultSet}. The result returned
276
+ # could be zero or more rows. The row metadata may be absent if no rows
277
+ # are returned.
278
+ #
279
+ # @param [Google::Cloud::Spanner::Partition] partition The partition to
280
+ # be executed.
281
+ #
282
+ # @example
283
+ # require "google/cloud/spanner"
284
+ #
285
+ # spanner = Google::Cloud::Spanner.new
286
+ #
287
+ # batch_client = spanner.batch_client "my-instance", "my-database"
288
+ # batch_snapshot = batch_client.batch_snapshot
289
+ #
290
+ # partitions = batch_snapshot.partition_read "users", [:id, :name]
291
+ #
292
+ # partition = partitions.first
293
+ # results = batch_snapshot.execute_partition partition
294
+ #
295
+ # batch_snapshot.close
296
+ #
297
+ def execute_partition partition
298
+ ensure_session!
299
+
300
+ partition = Partition.load partition unless partition.is_a? Partition
301
+ # TODO: raise if partition.empty?
302
+
303
+ # TODO: raise if session.path != partition.session
304
+ # TODO: raise if grpc.transaction != partition.transaction
305
+
306
+ if partition.execute?
307
+ execute_partition_query partition
308
+ elsif partition.read?
309
+ execute_partition_read partition
310
+ end
311
+ end
312
+
313
+ ##
314
+ # Closes the batch snapshot and releases the underlying resources.
315
+ #
316
+ # This should only be called once the batch snapshot is no longer needed
317
+ # anywhere. In particular if this batch snapshot is being used across
318
+ # multiple machines, calling this method on any of the machines will
319
+ # render the batch snapshot invalid everywhere.
320
+ #
321
+ # @example
322
+ # require "google/cloud/spanner"
323
+ #
324
+ # spanner = Google::Cloud::Spanner.new
325
+ #
326
+ # batch_client = spanner.batch_client "my-instance", "my-database"
327
+ # batch_snapshot = batch_client.batch_snapshot
328
+ #
329
+ # partitions = batch_snapshot.partition_read "users", [:id, :name]
330
+ #
331
+ # partition = partitions.first
332
+ # results = batch_snapshot.execute_partition partition
333
+ #
334
+ # batch_snapshot.close
335
+ #
336
+ def close
337
+ ensure_session!
338
+
339
+ session.release!
340
+ end
341
+
342
+ ##
343
+ # Executes a SQL query.
344
+ #
345
+ # Arguments can be passed using `params`, Ruby types are mapped to
346
+ # Spanner types as follows:
347
+ #
348
+ # | Spanner | Ruby | Notes |
349
+ # |-------------|----------------|---|
350
+ # | `BOOL` | `true`/`false` | |
351
+ # | `INT64` | `Integer` | |
352
+ # | `FLOAT64` | `Float` | |
353
+ # | `STRING` | `String` | |
354
+ # | `DATE` | `Date` | |
355
+ # | `TIMESTAMP` | `Time`, `DateTime` | |
356
+ # | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
357
+ # | `ARRAY` | `Array` | Nested arrays are not supported. |
358
+ #
359
+ # See [Data
360
+ # types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
361
+ #
362
+ # @param [String] sql The SQL query string. See [Query
363
+ # syntax](https://cloud.google.com/spanner/docs/query-syntax).
364
+ #
365
+ # The SQL query string can contain parameter placeholders. A parameter
366
+ # placeholder consists of "@" followed by the parameter name.
367
+ # Parameter names consist of any combination of letters, numbers, and
368
+ # underscores.
369
+ # @param [Hash] params SQL parameters for the query string. The
370
+ # parameter placeholders, minus the "@", are the the hash keys, and
371
+ # the literal values are the hash values. If the query string contains
372
+ # something like "WHERE id > @msg_id", then the params must contain
373
+ # something like `:msg_id => 1`.
374
+ # @param [Hash] types Types of the SQL parameters in `params`. It is not
375
+ # always possible for Cloud Spanner to infer the right SQL type from a
376
+ # value in `params`. In these cases, the `types` hash can be used to
377
+ # specify the exact SQL type for some or all of the SQL query
378
+ # parameters.
379
+ #
380
+ # The keys of the hash should be query string parameter placeholders,
381
+ # minus the "@". The values of the hash should be Cloud Spanner type
382
+ # codes from the following list:
383
+ #
384
+ # * `:BOOL`
385
+ # * `:BYTES`
386
+ # * `:DATE`
387
+ # * `:FLOAT64`
388
+ # * `:INT64`
389
+ # * `:STRING`
390
+ # * `:TIMESTAMP`
391
+ #
392
+ # Arrays are specified by providing the type code in an array. For
393
+ # example, an array of integers are specified as `[:INT64]`.
394
+ #
395
+ # Structs are not yet supported in query parameters.
396
+ #
397
+ # Types are optional.
398
+ # @return [Google::Cloud::Spanner::Results] The results of the query
399
+ # execution.
400
+ #
401
+ # @example
402
+ # require "google/cloud/spanner"
403
+ #
404
+ # spanner = Google::Cloud::Spanner.new
405
+ # batch_client = spanner.batch_client "my-instance", "my-database"
406
+ # batch_snapshot = batch_client.batch_snapshot
407
+ #
408
+ # results = batch_snapshot.execute "SELECT * FROM users"
409
+ #
410
+ # results.rows.each do |row|
411
+ # puts "User #{row[:id]} is #{row[:name]}"
412
+ # end
413
+ #
414
+ # @example Query using query parameters:
415
+ # require "google/cloud/spanner"
416
+ #
417
+ # spanner = Google::Cloud::Spanner.new
418
+ # batch_client = spanner.batch_client "my-instance", "my-database"
419
+ # batch_snapshot = batch_client.batch_snapshot
420
+ #
421
+ # results = batch_snapshot.execute "SELECT * FROM users " \
422
+ # "WHERE active = @active",
423
+ # params: { active: true }
424
+ #
425
+ # results.rows.each do |row|
426
+ # puts "User #{row[:id]} is #{row[:name]}"
427
+ # end
428
+ #
429
+ def execute sql, params: nil, types: nil
430
+ ensure_session!
431
+
432
+ params, types = Convert.to_input_params_and_types params, types
433
+
434
+ session.execute sql, params: params, types: types,
435
+ transaction: tx_selector
436
+ end
437
+ alias query execute
438
+
439
+ ##
440
+ # Read rows from a database table, as a simple alternative to
441
+ # {#execute}.
442
+ #
443
+ # @param [String] table The name of the table in the database to be
444
+ # read.
445
+ # @param [Array<String, Symbol>] columns The columns of table to be
446
+ # returned for each row matching this request.
447
+ # @param [Object, Array<Object>] keys A single, or list of keys or key
448
+ # ranges to match returned data to. Values should have exactly as many
449
+ # elements as there are columns in the primary key.
450
+ # @param [String] index The name of an index to use instead of the
451
+ # table's primary key when interpreting `id` and sorting result rows.
452
+ # Optional.
453
+ # @param [Integer] limit If greater than zero, no more than this number
454
+ # of rows will be returned. The default is no limit.
455
+ #
456
+ # @return [Google::Cloud::Spanner::Results] The results of the read
457
+ # operation.
458
+ #
459
+ # @example
460
+ # require "google/cloud/spanner"
461
+ #
462
+ # spanner = Google::Cloud::Spanner.new
463
+ # batch_client = spanner.batch_client "my-instance", "my-database"
464
+ # batch_snapshot = batch_client.batch_snapshot
465
+ #
466
+ # results = batch_snapshot.read "users", [:id, :name]
467
+ #
468
+ # results.rows.each do |row|
469
+ # puts "User #{row[:id]} is #{row[:name]}"
470
+ # end
471
+ #
472
+ def read table, columns, keys: nil, index: nil, limit: nil
473
+ ensure_session!
474
+
475
+ columns = Array(columns).map(&:to_s)
476
+ keys = Convert.to_key_set keys
477
+
478
+ session.read table, columns, keys: keys, index: index, limit: limit,
479
+ transaction: tx_selector
480
+ end
481
+
482
+ ##
483
+ # @private
484
+ # Converts the the batch snapshot object to a Hash ready for
485
+ # serialization.
486
+ #
487
+ # @return [Hash] A hash containing a representation of the batch
488
+ # snapshot object.
489
+ #
490
+ def to_h
491
+ {
492
+ session: Base64.strict_encode64(@session.grpc.to_proto),
493
+ transaction: Base64.strict_encode64(@grpc.to_proto)
494
+ }
495
+ end
496
+
497
+ ##
498
+ # Serializes the batch snapshot object so it can be recreated on another
499
+ # process. See {BatchClient#load_batch_snapshot}.
500
+ #
501
+ # @return [String] The serialized representation of the batch snapshot.
502
+ #
503
+ # @example
504
+ # require "google/cloud/spanner"
505
+ #
506
+ # spanner = Google::Cloud::Spanner.new
507
+ #
508
+ # batch_client = spanner.batch_client "my-instance", "my-database"
509
+ #
510
+ # batch_snapshot = batch_client.batch_snapshot
511
+ #
512
+ # partitions = batch_snapshot.partition_read "users", [:id, :name]
513
+ #
514
+ # partition = partitions.first
515
+ #
516
+ # serialized_snapshot = batch_snapshot.dump
517
+ # serialized_partition = partition.dump
518
+ #
519
+ # # In a separate process
520
+ # new_batch_snapshot = batch_client.load_batch_snapshot \
521
+ # serialized_snapshot
522
+ #
523
+ # new_partition = batch_client.load_partition \
524
+ # serialized_partition
525
+ #
526
+ # results = new_batch_snapshot.execute_partition \
527
+ # new_partition
528
+ #
529
+ def dump
530
+ JSON.dump to_h
531
+ end
532
+ alias serialize dump
533
+
534
+ ##
535
+ # @private Loads the serialized batch snapshot. See
536
+ # {BatchClient#load_batch_snapshot}.
537
+ def self.load data, service: nil
538
+ data = JSON.parse data, symbolize_names: true unless data.is_a? Hash
539
+
540
+ session_grpc = Google::Spanner::V1::Session.decode \
541
+ Base64.decode64(data[:session])
542
+ transaction_grpc = Google::Spanner::V1::Transaction.decode \
543
+ Base64.decode64(data[:transaction])
544
+
545
+ from_grpc transaction_grpc, Session.from_grpc(session_grpc, service)
546
+ end
547
+
548
+ ##
549
+ # @private Creates a new BatchSnapshot instance from a
550
+ # Google::Spanner::V1::Transaction.
551
+ def self.from_grpc grpc, session
552
+ new grpc, session
553
+ end
554
+
555
+ protected
556
+
557
+ # The TransactionSelector to be used for queries
558
+ def tx_selector
559
+ Google::Spanner::V1::TransactionSelector.new id: transaction_id
560
+ end
561
+
562
+ ##
563
+ # @private Raise an error unless an active connection to the service is
564
+ # available.
565
+ def ensure_session!
566
+ raise "Must have active connection to service" unless session
567
+ end
568
+
569
+ def execute_partition_query partition
570
+ session.execute partition.execute.sql,
571
+ params: partition.execute.params,
572
+ types: partition.execute.param_types.to_h,
573
+ transaction: partition.execute.transaction,
574
+ partition_token: partition.execute.partition_token
575
+ end
576
+
577
+ def execute_partition_read partition
578
+ session.read partition.read.table,
579
+ partition.read.columns.to_a,
580
+ keys: partition.read.key_set,
581
+ index: partition.read.index,
582
+ transaction: partition.read.transaction,
583
+ partition_token: partition.read.partition_token
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end