google-cloud-spanner 2.36.1 → 2.37.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dacf40c7c666295fd6990ae06f0c07544bcca11062b61db5e6c4e18a4bb40b1c
4
- data.tar.gz: 25cc74325e202f801b83204fad1630bf49c7af00e86d88948a17938882d93f25
3
+ metadata.gz: 85dbbe5aa02ac93080c438688ca3f120a8435c8816fcd17ce64660e3b6bbc7ae
4
+ data.tar.gz: 741c37bb89f744d42fbd0d081511de90e069c999b6978f66482cca282d154200
5
5
  SHA512:
6
- metadata.gz: d2e5587393eaeace0f6446eea28444bc9dce49f9ffecde69d4dae377b77fd5ad43709d7f0e1b18e1202fcbda448af26c4d22cc6517876ffdb47ffa9d747bbf2b
7
- data.tar.gz: 354a92c99c6c1736c72c5172407ab9ce23d80ddd8be08bee45e26500c92e6aab7e81599ec6c1087533a40d2f77a64e0c8488a0441f9ae4f61a2380b0fc08ee85
6
+ metadata.gz: 49ef3061971e4673bac749c9fe8515db3d59c055261139113d432491a402093f37c27c9e92ed9dfedd85a9b5440b0f84538aa76b9e56fb41c10fb9eab0a05f33
7
+ data.tar.gz: 17d0238b2433dda6e57732d4a081fb1556b68ed2422b7f15cbedd48ca1ebd46705209eca4f28f9af61541a68ea846676e658e9566d11e95b57705e7f4670f7a8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Release History
2
2
 
3
+ ### 2.37.1 (2026-11-02)
4
+
5
+ #### Documentation
6
+
7
+ * document queues in OVERVIEW.md and Client ([#265](https://github.com/googleapis/ruby-spanner/issues/265))
8
+
9
+ ### 2.37.0 (2026-10-28)
10
+
11
+ #### Features
12
+
13
+ * add send_message and ack_message to Commit ([#262](https://github.com/googleapis/ruby-spanner/issues/262))
14
+ * add send_message and ack_message to Transaction ([#263](https://github.com/googleapis/ruby-spanner/issues/263))
15
+ #### Documentation
16
+
17
+ * link to the published Ruby version support policy ([#272](https://github.com/googleapis/ruby-spanner/issues/272))
18
+
3
19
  ### 2.36.1 (2026-10-13)
4
20
 
5
21
  #### Documentation
data/OVERVIEW.md CHANGED
@@ -298,6 +298,77 @@ db.snapshot do |snp|
298
298
  end
299
299
  ```
300
300
 
301
+ ## Using queues
302
+
303
+ A queue holds messages for consumers to receive. You create queues with the
304
+ `CREATE QUEUE` statement (see the [DDL
305
+ reference](https://cloud.google.com/spanner/docs/reference/standard-sql/data-definition-language)).
306
+ The examples in this section use this queue:
307
+
308
+ ```sql
309
+ CREATE QUEUE OrderQueue (
310
+ Id INT64 NOT NULL,
311
+ Payload STRING(MAX) NOT NULL
312
+ ) PRIMARY KEY (Id)
313
+ ```
314
+
315
+ Use {Google::Cloud::Spanner::Commit#send_message Commit#send_message} to send a
316
+ message. The payload is converted the same way as column values, so pass a
317
+ `String` for a `STRING` payload column:
318
+
319
+ ```ruby
320
+ require "google/cloud/spanner"
321
+
322
+ spanner = Google::Cloud::Spanner.new
323
+
324
+ db = spanner.client "my-instance", "my-database"
325
+
326
+ db.commit do |c|
327
+ c.send_message "OrderQueue", 101, "Order payload"
328
+ end
329
+ ```
330
+
331
+ If a queue's payload column is `BYTES`, wrap the binary data in a `StringIO`,
332
+ as you would for a `BYTES` column in a table:
333
+
334
+ ```ruby
335
+ db.commit do |c|
336
+ c.send_message "LabelQueue", 101, StringIO.new(File.binread("label.png"))
337
+ end
338
+ ```
339
+
340
+ Receive messages with the `RECEIVE_<queue>` table-valued function, and use
341
+ {Google::Cloud::Spanner::Transaction#ack_message Transaction#ack_message} to
342
+ acknowledge each one in the same transaction as the write it caused:
343
+
344
+ ```ruby
345
+ require "google/cloud/spanner"
346
+
347
+ spanner = Google::Cloud::Spanner.new
348
+
349
+ db = spanner.client "my-instance", "my-database"
350
+
351
+ results = db.execute_query "SELECT Id, Payload FROM RECEIVE_OrderQueue()"
352
+
353
+ results.rows.each do |row|
354
+ db.transaction do |tx|
355
+ tx.update "orders", [{ id: row[:Id], status: "PROCESSED" }]
356
+ tx.ack_message "OrderQueue", row[:Id]
357
+ end
358
+ end
359
+ ```
360
+
361
+ To delay delivery, pass `deliver_time:`. To ack a message that might not
362
+ exist, pass `ignore_not_found: true`:
363
+
364
+ ```ruby
365
+ db.commit do |c|
366
+ c.send_message "OrderQueue", 102, "Order payload",
367
+ deliver_time: Time.now + 300
368
+ c.ack_message "OrderQueue", 101, ignore_not_found: true
369
+ end
370
+ ```
371
+
301
372
  ## Deleting databases
302
373
 
303
374
  Use {Google::Cloud::Spanner::Admin::Database#database_admin
@@ -35,6 +35,12 @@ module Google
35
35
  #
36
36
  # A client is used to read and/or modify data in a Cloud Spanner database.
37
37
  #
38
+ # A client also works with queues. Send and acknowledge messages with
39
+ # {Commit#send_message} and {Commit#ack_message} inside {#commit}, or with
40
+ # {Transaction#send_message} and {Transaction#ack_message} inside
41
+ # {#transaction}. Receive messages by querying the queue's `RECEIVE_`
42
+ # function with {#execute_query}.
43
+ #
38
44
  # See {Google::Cloud::Spanner::Project#client}.
39
45
  #
40
46
  # @example
@@ -506,6 +512,20 @@ module Google
506
512
  # puts "User #{row[:id]} is #{row[:name]}"
507
513
  # end
508
514
  #
515
+ # @example Receive messages from a queue with the RECEIVE_ function:
516
+ # require "google/cloud/spanner"
517
+ #
518
+ # spanner = Google::Cloud::Spanner.new
519
+ #
520
+ # db = spanner.client "my-instance", "my-database"
521
+ #
522
+ # # RECEIVE_ needs a strong read, which is the default here.
523
+ # results = db.execute_query "SELECT Id, Payload FROM RECEIVE_OrderQueue()"
524
+ #
525
+ # results.rows.each do |row|
526
+ # puts "Received message #{row[:Id]}"
527
+ # end
528
+ #
509
529
  def execute_query sql, params: nil, types: nil, single_use: nil,
510
530
  query_options: nil, request_options: nil,
511
531
  call_options: nil, directed_read_options: nil
@@ -280,6 +280,124 @@ module Google
280
280
  keys
281
281
  end
282
282
 
283
+ ##
284
+ # Sends a message to a queue.
285
+ #
286
+ # All changes are accumulated in memory until the block passed to
287
+ # {Client#commit} completes.
288
+ #
289
+ # @param [String] queue The name of the queue.
290
+ # @param [Object, Array<Object>] key A single key or array of composite key parts for the message.
291
+ # @param [String, IO, StringIO, Hash, Google::Protobuf::MessageExts] payload
292
+ # The message payload. It is converted the same way as column values
293
+ # (see {#upsert}), so its type must match the queue's payload column,
294
+ # such as a `String` for `STRING` or a `StringIO` for `BYTES`:
295
+ # * `String` - Sent as text.
296
+ # * `IO`, `StringIO`, `File` - Sent as bytes (Base64-encoded). Ruby has
297
+ # no bytes type, so wrap binary data in a `StringIO`.
298
+ # * `Hash` - Serialized to a JSON string.
299
+ # * `Google::Protobuf::MessageExts` - Serialized and Base64-encoded.
300
+ # @param [Time, nil] deliver_time The time at which Spanner begins
301
+ # trying to deliver the message. Optional. If not set, the message is
302
+ # delivered immediately. A time in the past is replaced with a time
303
+ # closer to the current time.
304
+ #
305
+ # @return [Object, Array<Object>] The key of the message.
306
+ #
307
+ # @raise [ArgumentError] If the payload type is unsupported.
308
+ #
309
+ # @example
310
+ # require "google/cloud/spanner"
311
+ #
312
+ # spanner = Google::Cloud::Spanner.new
313
+ #
314
+ # db = spanner.client "my-instance", "my-database"
315
+ #
316
+ # # OrderQueue has a STRING(MAX) payload column.
317
+ # db.commit do |c|
318
+ # c.send_message "OrderQueue", 101, "Order payload"
319
+ # end
320
+ #
321
+ # @example Send binary data to a queue with a BYTES payload column
322
+ # require "google/cloud/spanner"
323
+ #
324
+ # spanner = Google::Cloud::Spanner.new
325
+ #
326
+ # db = spanner.client "my-instance", "my-database"
327
+ #
328
+ # db.commit do |c|
329
+ # c.send_message "LabelQueue", 101, StringIO.new(File.binread("label.png"))
330
+ # end
331
+ #
332
+ # @example Deliver the message in five minutes
333
+ # require "google/cloud/spanner"
334
+ #
335
+ # spanner = Google::Cloud::Spanner.new
336
+ #
337
+ # db = spanner.client "my-instance", "my-database"
338
+ #
339
+ # db.commit do |c|
340
+ # c.send_message "OrderQueue", 101, "Order payload",
341
+ # deliver_time: Time.now + 300
342
+ # end
343
+ #
344
+ def send_message queue, key, payload, deliver_time: nil
345
+ send_mutation = V1::Mutation::Send.new(
346
+ queue: queue,
347
+ key: key_list_value(key),
348
+ payload: Convert.object_to_grpc_value(payload),
349
+ deliver_time: Convert.time_to_timestamp(deliver_time)
350
+ )
351
+ @mutations += [V1::Mutation.new(send: send_mutation)]
352
+ key
353
+ end
354
+
355
+ ##
356
+ # Acknowledges a message in a queue, which removes it from the queue.
357
+ #
358
+ # All changes are accumulated in memory until the block passed to
359
+ # {Client#commit} completes.
360
+ #
361
+ # @param [String] queue The name of the queue.
362
+ # @param [Object, Array<Object>] key A single key or array of composite key parts to match.
363
+ # @param [Boolean] ignore_not_found If `true`, the ack succeeds even if
364
+ # the message doesn't exist. Optional. The default is `false`, which
365
+ # fails the commit with `NOT_FOUND` when the message doesn't exist.
366
+ #
367
+ # @return [Object, Array<Object>] The key of the message.
368
+ #
369
+ # @example
370
+ # require "google/cloud/spanner"
371
+ #
372
+ # spanner = Google::Cloud::Spanner.new
373
+ #
374
+ # db = spanner.client "my-instance", "my-database"
375
+ #
376
+ # db.commit do |c|
377
+ # c.ack_message "OrderQueue", 101
378
+ # end
379
+ #
380
+ # @example Ack a message whether or not it exists
381
+ # require "google/cloud/spanner"
382
+ #
383
+ # spanner = Google::Cloud::Spanner.new
384
+ #
385
+ # db = spanner.client "my-instance", "my-database"
386
+ #
387
+ # db.commit do |c|
388
+ # c.ack_message "OrderQueue", 101, ignore_not_found: true
389
+ # end
390
+ #
391
+ def ack_message queue, key, ignore_not_found: false
392
+ ack_mutation = V1::Mutation::Ack.new(
393
+ queue: queue,
394
+ key: key_list_value(key),
395
+ ignore_not_found: ignore_not_found
396
+ )
397
+ @mutations += [V1::Mutation.new(ack: ack_mutation)]
398
+ key
399
+ end
400
+
283
401
  # Return the current mutations added to this `Spanner::Commit` object.
284
402
  # @private
285
403
  # @return [Array<Google::Cloud::Spanner::V1::Mutation>]
@@ -325,6 +443,21 @@ module Google
325
443
  rows
326
444
  end
327
445
 
446
+ ##
447
+ # @private
448
+ # Generates a `ListValue` protobuf containing gRPC values for the given primary key.
449
+ #
450
+ # @param [Object, Array<Object>] key A scalar key, or an array of a composite key's parts.
451
+ # @return [Google::Protobuf::ListValue]
452
+ #
453
+ def key_list_value key
454
+ key = [key] unless key.is_a? Array
455
+ key_list = key.map do |k|
456
+ Convert.object_to_grpc_value k
457
+ end
458
+ Google::Protobuf::ListValue.new values: key_list
459
+ end
460
+
328
461
  def key_set keys
329
462
  return V1::KeySet.new all: true if keys.nil?
330
463
  keys = [keys] unless keys.is_a? Array
@@ -1075,6 +1075,79 @@ module Google
1075
1075
  @commit.delete table, keys
1076
1076
  end
1077
1077
 
1078
+ ##
1079
+ # Sends a message to a queue.
1080
+ #
1081
+ # All changes are accumulated in memory until the block passed to
1082
+ # {Client#transaction} completes.
1083
+ #
1084
+ # @param [String] queue The name of the queue.
1085
+ # @param [Object, Array<Object>] key A single key or array of composite key parts for the message.
1086
+ # @param [String, IO, StringIO, Hash, Google::Protobuf::MessageExts] payload
1087
+ # The message payload. It is converted the same way as column values
1088
+ # (see {#upsert}), so its type must match the queue's payload column,
1089
+ # such as a `String` for `STRING` or a `StringIO` for `BYTES`:
1090
+ # * `String` - Sent as text.
1091
+ # * `IO`, `StringIO`, `File` - Sent as bytes (Base64-encoded). Ruby has
1092
+ # no bytes type, so wrap binary data in a `StringIO`.
1093
+ # * `Hash` - Serialized to a JSON string.
1094
+ # * `Google::Protobuf::MessageExts` - Serialized and Base64-encoded.
1095
+ # @param [Time, nil] deliver_time The time at which Spanner begins
1096
+ # trying to deliver the message. Optional. If not set, the message is
1097
+ # delivered immediately. A time in the past is replaced with a time
1098
+ # closer to the current time.
1099
+ #
1100
+ # @return [Object, Array<Object>] The key of the message.
1101
+ #
1102
+ # @raise [ArgumentError] If the payload type is unsupported.
1103
+ #
1104
+ # @example Send a message in the same transaction as the row it describes
1105
+ # require "google/cloud/spanner"
1106
+ #
1107
+ # spanner = Google::Cloud::Spanner.new
1108
+ # db = spanner.client "my-instance", "my-database"
1109
+ #
1110
+ # # OrderQueue has a STRING(MAX) payload column.
1111
+ # db.transaction do |tx|
1112
+ # tx.insert "orders", [{ id: 101, status: "NEW" }]
1113
+ # tx.send_message "OrderQueue", 101, "Order payload"
1114
+ # end
1115
+ #
1116
+ def send_message queue, key, payload, deliver_time: nil
1117
+ ensure_session!
1118
+ @commit.send_message queue, key, payload, deliver_time: deliver_time
1119
+ end
1120
+
1121
+ ##
1122
+ # Acknowledges a message in a queue, which removes it from the queue.
1123
+ #
1124
+ # All changes are accumulated in memory until the block passed to
1125
+ # {Client#transaction} completes.
1126
+ #
1127
+ # @param [String] queue The name of the queue.
1128
+ # @param [Object, Array<Object>] key A single key or array of composite key parts to match.
1129
+ # @param [Boolean] ignore_not_found If `true`, the ack succeeds even if
1130
+ # the message doesn't exist. Optional. The default is `false`, which
1131
+ # fails the commit with `NOT_FOUND` when the message doesn't exist.
1132
+ #
1133
+ # @return [Object, Array<Object>] The key of the message.
1134
+ #
1135
+ # @example Ack a message in the same transaction as the write it caused
1136
+ # require "google/cloud/spanner"
1137
+ #
1138
+ # spanner = Google::Cloud::Spanner.new
1139
+ # db = spanner.client "my-instance", "my-database"
1140
+ #
1141
+ # db.transaction do |tx|
1142
+ # tx.update "orders", [{ id: 101, status: "PROCESSED" }]
1143
+ # tx.ack_message "OrderQueue", 101
1144
+ # end
1145
+ #
1146
+ def ack_message queue, key, ignore_not_found: false
1147
+ ensure_session!
1148
+ @commit.ack_message queue, key, ignore_not_found: ignore_not_found
1149
+ end
1150
+
1078
1151
  ##
1079
1152
  # @private
1080
1153
  # Returns the field names and types for a table.
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Spanner
19
- VERSION = "2.36.1".freeze
19
+ VERSION = "2.37.1".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-spanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.36.1
4
+ version: 2.37.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.6'
89
+ version: '1.12'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '1.6'
96
+ version: '1.12'
97
97
  description: google-cloud-spanner is the official library for Google Cloud Spanner
98
98
  API.
99
99
  email: