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
@@ -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