google-cloud-spanner 0.21.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.
- checksums.yaml +7 -0
- data/lib/google-cloud-spanner.rb +106 -0
- data/lib/google/cloud/spanner.rb +382 -0
- data/lib/google/cloud/spanner/admin/database/v1.rb +17 -0
- data/lib/google/cloud/spanner/admin/database/v1/database_admin_client.rb +703 -0
- data/lib/google/cloud/spanner/admin/database/v1/database_admin_client_config.json +73 -0
- data/lib/google/cloud/spanner/admin/database/v1/doc/google/iam/v1/policy.rb +139 -0
- data/lib/google/cloud/spanner/admin/database/v1/doc/google/protobuf/any.rb +114 -0
- data/lib/google/cloud/spanner/admin/database/v1/doc/google/rpc/status.rb +83 -0
- data/lib/google/cloud/spanner/admin/database/v1/doc/google/spanner/admin/database/v1/spanner_database_admin.rb +188 -0
- data/lib/google/cloud/spanner/admin/instance/v1.rb +17 -0
- data/lib/google/cloud/spanner/admin/instance/v1/doc/google/iam/v1/policy.rb +139 -0
- data/lib/google/cloud/spanner/admin/instance/v1/doc/google/protobuf/any.rb +114 -0
- data/lib/google/cloud/spanner/admin/instance/v1/doc/google/protobuf/field_mask.rb +223 -0
- data/lib/google/cloud/spanner/admin/instance/v1/doc/google/rpc/status.rb +83 -0
- data/lib/google/cloud/spanner/admin/instance/v1/doc/google/spanner/admin/instance/v1/spanner_instance_admin.rb +268 -0
- data/lib/google/cloud/spanner/admin/instance/v1/instance_admin_client.rb +868 -0
- data/lib/google/cloud/spanner/admin/instance/v1/instance_admin_client_config.json +78 -0
- data/lib/google/cloud/spanner/client.rb +1034 -0
- data/lib/google/cloud/spanner/commit.rb +351 -0
- data/lib/google/cloud/spanner/convert.rb +311 -0
- data/lib/google/cloud/spanner/credentials.rb +32 -0
- data/lib/google/cloud/spanner/data.rb +199 -0
- data/lib/google/cloud/spanner/database.rb +377 -0
- data/lib/google/cloud/spanner/database/job.rb +179 -0
- data/lib/google/cloud/spanner/database/list.rb +171 -0
- data/lib/google/cloud/spanner/errors.rb +73 -0
- data/lib/google/cloud/spanner/fields.rb +252 -0
- data/lib/google/cloud/spanner/instance.rb +472 -0
- data/lib/google/cloud/spanner/instance/config.rb +99 -0
- data/lib/google/cloud/spanner/instance/config/list.rb +171 -0
- data/lib/google/cloud/spanner/instance/job.rb +197 -0
- data/lib/google/cloud/spanner/instance/list.rb +167 -0
- data/lib/google/cloud/spanner/policy.rb +201 -0
- data/lib/google/cloud/spanner/pool.rb +279 -0
- data/lib/google/cloud/spanner/project.rb +480 -0
- data/lib/google/cloud/spanner/range.rb +99 -0
- data/lib/google/cloud/spanner/results.rb +280 -0
- data/lib/google/cloud/spanner/service.rb +458 -0
- data/lib/google/cloud/spanner/session.rb +565 -0
- data/lib/google/cloud/spanner/snapshot.rb +260 -0
- data/lib/google/cloud/spanner/transaction.rb +533 -0
- data/lib/google/cloud/spanner/v1.rb +17 -0
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/duration.rb +77 -0
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/struct.rb +73 -0
- data/lib/google/cloud/spanner/v1/doc/google/protobuf/timestamp.rb +81 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/keys.rb +148 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/mutation.rb +80 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/query_plan.rb +120 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/result_set.rb +175 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/spanner.rb +206 -0
- data/lib/google/cloud/spanner/v1/doc/google/spanner/v1/transaction.rb +351 -0
- data/lib/google/cloud/spanner/v1/spanner_client.rb +850 -0
- data/lib/google/cloud/spanner/v1/spanner_client_config.json +78 -0
- data/lib/google/cloud/spanner/version.rb +22 -0
- data/lib/google/spanner/admin/database/v1/spanner_database_admin_pb.rb +85 -0
- data/lib/google/spanner/admin/database/v1/spanner_database_admin_services_pb.rb +95 -0
- data/lib/google/spanner/admin/instance/v1/spanner_instance_admin_pb.rb +106 -0
- data/lib/google/spanner/admin/instance/v1/spanner_instance_admin_services_pb.rb +180 -0
- data/lib/google/spanner/v1/keys_pb.rb +33 -0
- data/lib/google/spanner/v1/mutation_pb.rb +38 -0
- data/lib/google/spanner/v1/query_plan_pb.rb +47 -0
- data/lib/google/spanner/v1/result_set_pb.rb +43 -0
- data/lib/google/spanner/v1/spanner_pb.rb +90 -0
- data/lib/google/spanner/v1/spanner_services_pb.rb +131 -0
- data/lib/google/spanner/v1/transaction_pb.rb +51 -0
- data/lib/google/spanner/v1/type_pb.rb +43 -0
- metadata +309 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"interfaces": {
|
|
3
|
+
"google.spanner.admin.instance.v1.InstanceAdmin": {
|
|
4
|
+
"retry_codes": {
|
|
5
|
+
"idempotent": [
|
|
6
|
+
"DEADLINE_EXCEEDED",
|
|
7
|
+
"UNAVAILABLE"
|
|
8
|
+
],
|
|
9
|
+
"non_idempotent": [
|
|
10
|
+
"UNAVAILABLE"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"retry_params": {
|
|
14
|
+
"default": {
|
|
15
|
+
"initial_retry_delay_millis": 1000,
|
|
16
|
+
"retry_delay_multiplier": 1.3,
|
|
17
|
+
"max_retry_delay_millis": 32000,
|
|
18
|
+
"initial_rpc_timeout_millis": 60000,
|
|
19
|
+
"rpc_timeout_multiplier": 1.0,
|
|
20
|
+
"max_rpc_timeout_millis": 60000,
|
|
21
|
+
"total_timeout_millis": 600000
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"methods": {
|
|
25
|
+
"ListInstanceConfigs": {
|
|
26
|
+
"timeout_millis": 30000,
|
|
27
|
+
"retry_codes_name": "idempotent",
|
|
28
|
+
"retry_params_name": "default"
|
|
29
|
+
},
|
|
30
|
+
"GetInstanceConfig": {
|
|
31
|
+
"timeout_millis": 30000,
|
|
32
|
+
"retry_codes_name": "idempotent",
|
|
33
|
+
"retry_params_name": "default"
|
|
34
|
+
},
|
|
35
|
+
"ListInstances": {
|
|
36
|
+
"timeout_millis": 30000,
|
|
37
|
+
"retry_codes_name": "idempotent",
|
|
38
|
+
"retry_params_name": "default"
|
|
39
|
+
},
|
|
40
|
+
"GetInstance": {
|
|
41
|
+
"timeout_millis": 30000,
|
|
42
|
+
"retry_codes_name": "idempotent",
|
|
43
|
+
"retry_params_name": "default"
|
|
44
|
+
},
|
|
45
|
+
"CreateInstance": {
|
|
46
|
+
"timeout_millis": 30000,
|
|
47
|
+
"retry_codes_name": "non_idempotent",
|
|
48
|
+
"retry_params_name": "default"
|
|
49
|
+
},
|
|
50
|
+
"UpdateInstance": {
|
|
51
|
+
"timeout_millis": 30000,
|
|
52
|
+
"retry_codes_name": "non_idempotent",
|
|
53
|
+
"retry_params_name": "default"
|
|
54
|
+
},
|
|
55
|
+
"DeleteInstance": {
|
|
56
|
+
"timeout_millis": 30000,
|
|
57
|
+
"retry_codes_name": "idempotent",
|
|
58
|
+
"retry_params_name": "default"
|
|
59
|
+
},
|
|
60
|
+
"SetIamPolicy": {
|
|
61
|
+
"timeout_millis": 30000,
|
|
62
|
+
"retry_codes_name": "non_idempotent",
|
|
63
|
+
"retry_params_name": "default"
|
|
64
|
+
},
|
|
65
|
+
"GetIamPolicy": {
|
|
66
|
+
"timeout_millis": 30000,
|
|
67
|
+
"retry_codes_name": "idempotent",
|
|
68
|
+
"retry_params_name": "default"
|
|
69
|
+
},
|
|
70
|
+
"TestIamPermissions": {
|
|
71
|
+
"timeout_millis": 30000,
|
|
72
|
+
"retry_codes_name": "non_idempotent",
|
|
73
|
+
"retry_params_name": "default"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,1034 @@
|
|
|
1
|
+
# Copyright 2017 Google Inc. All rights reserved.
|
|
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
|
+
# http://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/errors"
|
|
17
|
+
require "google/cloud/spanner/project"
|
|
18
|
+
require "google/cloud/spanner/data"
|
|
19
|
+
require "google/cloud/spanner/pool"
|
|
20
|
+
require "google/cloud/spanner/session"
|
|
21
|
+
require "google/cloud/spanner/transaction"
|
|
22
|
+
require "google/cloud/spanner/snapshot"
|
|
23
|
+
require "google/cloud/spanner/range"
|
|
24
|
+
require "google/cloud/spanner/convert"
|
|
25
|
+
|
|
26
|
+
module Google
|
|
27
|
+
module Cloud
|
|
28
|
+
module Spanner
|
|
29
|
+
##
|
|
30
|
+
# # Client
|
|
31
|
+
#
|
|
32
|
+
# A client is used to read and/or modify data in a Cloud Spanner database.
|
|
33
|
+
#
|
|
34
|
+
# See {Google::Cloud::Spanner::Project#client}.
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# require "google/cloud"
|
|
38
|
+
#
|
|
39
|
+
# spanner = Google::Cloud::Spanner.new
|
|
40
|
+
#
|
|
41
|
+
# db = spanner.client "my-instance", "my-database"
|
|
42
|
+
#
|
|
43
|
+
# db.transaction do |tx|
|
|
44
|
+
# results = tx.execute "SELECT * FROM users"
|
|
45
|
+
#
|
|
46
|
+
# results.rows.each do |row|
|
|
47
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
class Client
|
|
52
|
+
##
|
|
53
|
+
# @private Creates a new Spanner Client instance.
|
|
54
|
+
def initialize project, instance_id, database_id, min: 10, max: 100,
|
|
55
|
+
keepalive: 1800, write_ratio: 0.3, fail: true
|
|
56
|
+
@project = project
|
|
57
|
+
@instance_id = instance_id
|
|
58
|
+
@database_id = database_id
|
|
59
|
+
@pool = Pool.new self, min: min, max: max, keepalive: keepalive,
|
|
60
|
+
write_ratio: write_ratio, fail: fail
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# The unique identifier for the project.
|
|
64
|
+
# @return [String]
|
|
65
|
+
def project_id
|
|
66
|
+
@project.service.project
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The unique identifier for the instance.
|
|
70
|
+
# @return [String]
|
|
71
|
+
def instance_id
|
|
72
|
+
@instance_id
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# The unique identifier for the database.
|
|
76
|
+
# @return [String]
|
|
77
|
+
def database_id
|
|
78
|
+
@database_id
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The Spanner project connected to.
|
|
82
|
+
# @return [Project]
|
|
83
|
+
def project
|
|
84
|
+
@project
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The Spanner instance connected to.
|
|
88
|
+
# @return [Instance]
|
|
89
|
+
def instance
|
|
90
|
+
@project.instance instance_id
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The Spanner database connected to.
|
|
94
|
+
# @return [Database]
|
|
95
|
+
def database
|
|
96
|
+
@project.database instance_id, database_id
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
##
|
|
100
|
+
# Executes a SQL query.
|
|
101
|
+
#
|
|
102
|
+
# Arguments can be passed using `params`, Ruby types are mapped to
|
|
103
|
+
# Spanner types as follows:
|
|
104
|
+
#
|
|
105
|
+
# | Spanner | Ruby | Notes |
|
|
106
|
+
# |-------------|----------------|---|
|
|
107
|
+
# | `BOOL` | `true`/`false` | |
|
|
108
|
+
# | `INT64` | `Integer` | |
|
|
109
|
+
# | `FLOAT64` | `Float` | |
|
|
110
|
+
# | `STRING` | `String` | |
|
|
111
|
+
# | `DATE` | `Date` | |
|
|
112
|
+
# | `TIMESTAMP` | `Time`, `DateTime` | |
|
|
113
|
+
# | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
|
|
114
|
+
# | `ARRAY` | `Array` | Nested arrays are not supported. |
|
|
115
|
+
#
|
|
116
|
+
# See [Data
|
|
117
|
+
# types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
|
|
118
|
+
#
|
|
119
|
+
# @param [String] sql The SQL query string. See [Query
|
|
120
|
+
# syntax](https://cloud.google.com/spanner/docs/query-syntax).
|
|
121
|
+
#
|
|
122
|
+
# The SQL query string can contain parameter placeholders. A parameter
|
|
123
|
+
# placeholder consists of "@" followed by the parameter name.
|
|
124
|
+
# Parameter names consist of any combination of letters, numbers, and
|
|
125
|
+
# underscores.
|
|
126
|
+
# @param [Hash] params SQL parameters for the query string. The
|
|
127
|
+
# parameter placeholders, minus the "@", are the the hash keys, and
|
|
128
|
+
# the literal values are the hash values. If the query string contains
|
|
129
|
+
# something like "WHERE id > @msg_id", then the params must contain
|
|
130
|
+
# something like `:msg_id => 1`.
|
|
131
|
+
# @param [Hash] types Types of the SQL parameters in `params`. It is not
|
|
132
|
+
# always possible for Cloud Spanner to infer the right SQL type from a
|
|
133
|
+
# value in `params`. In these cases, the `types` hash can be used to
|
|
134
|
+
# specify the exact SQL type for some or all of the SQL query
|
|
135
|
+
# parameters.
|
|
136
|
+
#
|
|
137
|
+
# The keys of the hash should be query string parameter placeholders,
|
|
138
|
+
# minus the "@". The values of the hash should be Cloud Spanner type
|
|
139
|
+
# codes from the following list:
|
|
140
|
+
#
|
|
141
|
+
# * `:BOOL`
|
|
142
|
+
# * `:BYTES`
|
|
143
|
+
# * `:DATE`
|
|
144
|
+
# * `:FLOAT64`
|
|
145
|
+
# * `:INT64`
|
|
146
|
+
# * `:STRING`
|
|
147
|
+
# * `:TIMESTAMP`
|
|
148
|
+
#
|
|
149
|
+
# Arrays are specified by providing the type code in an array. For
|
|
150
|
+
# example, an array of integers are specified as `[:INT64]`.
|
|
151
|
+
#
|
|
152
|
+
# Structs are not yet supported in query parameters.
|
|
153
|
+
#
|
|
154
|
+
# Types are optional.
|
|
155
|
+
# @param [Hash] single_use Perform the read with a single-use snapshot
|
|
156
|
+
# (read-only transaction). (See
|
|
157
|
+
# [TransactionOptions](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#transactionoptions).)
|
|
158
|
+
# The snapshot can be created by providing exactly one of the
|
|
159
|
+
# following options in the hash:
|
|
160
|
+
#
|
|
161
|
+
# * **Strong**
|
|
162
|
+
# * `:strong` (true, false) Read at a timestamp where all previously
|
|
163
|
+
# committed transactions are visible.
|
|
164
|
+
# * **Exact**
|
|
165
|
+
# * `:timestamp`/`:read_timestamp` (Time, DateTime) Executes all
|
|
166
|
+
# reads at the given timestamp. Unlike other modes, reads at a
|
|
167
|
+
# specific timestamp are repeatable; the same read at the same
|
|
168
|
+
# timestamp always returns the same data. If the timestamp is in
|
|
169
|
+
# the future, the read will block until the specified timestamp,
|
|
170
|
+
# modulo the read's deadline.
|
|
171
|
+
#
|
|
172
|
+
# Useful for large scale consistent reads such as mapreduces, or
|
|
173
|
+
# for coordinating many reads against a consistent snapshot of the
|
|
174
|
+
# data.
|
|
175
|
+
# * `:staleness`/`:exact_staleness` (Numeric) Executes all reads at
|
|
176
|
+
# a timestamp that is exactly the number of seconds provided old.
|
|
177
|
+
# The timestamp is chosen soon after the read is started.
|
|
178
|
+
#
|
|
179
|
+
# Guarantees that all writes that have committed more than the
|
|
180
|
+
# specified number of seconds ago are visible. Because Cloud
|
|
181
|
+
# Spanner chooses the exact timestamp, this mode works even if the
|
|
182
|
+
# client's local clock is substantially skewed from Cloud Spanner
|
|
183
|
+
# commit timestamps.
|
|
184
|
+
#
|
|
185
|
+
# Useful for reading at nearby replicas without the distributed
|
|
186
|
+
# timestamp negotiation overhead of single-use
|
|
187
|
+
# `bounded_staleness`.
|
|
188
|
+
# * **Bounded**
|
|
189
|
+
# * `:bounded_timestamp`/`:min_read_timestamp` (Time, DateTime)
|
|
190
|
+
# Executes all reads at a timestamp greater than the value
|
|
191
|
+
# provided.
|
|
192
|
+
#
|
|
193
|
+
# This is useful for requesting fresher data than some previous
|
|
194
|
+
# read, or data that is fresh enough to observe the effects of
|
|
195
|
+
# some previously committed transaction whose timestamp is known.
|
|
196
|
+
# * `:bounded_staleness`/`:max_staleness` (Numeric) Read data at a
|
|
197
|
+
# timestamp greater than or equal to the number of seconds
|
|
198
|
+
# provided. Guarantees that all writes that have committed more
|
|
199
|
+
# than the specified number of seconds ago are visible. Because
|
|
200
|
+
# Cloud Spanner chooses the exact timestamp, this mode works even
|
|
201
|
+
# if the client's local clock is substantially skewed from Cloud
|
|
202
|
+
# Spanner commit timestamps.
|
|
203
|
+
#
|
|
204
|
+
# Useful for reading the freshest data available at a nearby
|
|
205
|
+
# replica, while bounding the possible staleness if the local
|
|
206
|
+
# replica has fallen behind.
|
|
207
|
+
#
|
|
208
|
+
# @return [Google::Cloud::Spanner::Results] The results of the query
|
|
209
|
+
# execution.
|
|
210
|
+
#
|
|
211
|
+
# @example
|
|
212
|
+
# require "google/cloud/spanner"
|
|
213
|
+
#
|
|
214
|
+
# spanner = Google::Cloud::Spanner.new
|
|
215
|
+
#
|
|
216
|
+
# db = spanner.client "my-instance", "my-database"
|
|
217
|
+
#
|
|
218
|
+
# results = db.execute "SELECT * FROM users"
|
|
219
|
+
#
|
|
220
|
+
# results.rows.each do |row|
|
|
221
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
222
|
+
# end
|
|
223
|
+
#
|
|
224
|
+
# @example Query using query parameters:
|
|
225
|
+
# require "google/cloud/spanner"
|
|
226
|
+
#
|
|
227
|
+
# spanner = Google::Cloud::Spanner.new
|
|
228
|
+
#
|
|
229
|
+
# db = spanner.client "my-instance", "my-database"
|
|
230
|
+
#
|
|
231
|
+
# results = db.execute "SELECT * FROM users WHERE active = @active",
|
|
232
|
+
# params: { active: true }
|
|
233
|
+
#
|
|
234
|
+
# results.rows.each do |row|
|
|
235
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
236
|
+
# end
|
|
237
|
+
#
|
|
238
|
+
def execute sql, params: nil, types: nil, single_use: nil
|
|
239
|
+
validate_single_use_args! single_use
|
|
240
|
+
ensure_service!
|
|
241
|
+
|
|
242
|
+
single_use_tx = single_use_transaction single_use
|
|
243
|
+
results = nil
|
|
244
|
+
@pool.with_session do |session|
|
|
245
|
+
results = session.execute \
|
|
246
|
+
sql, params: params, types: types, transaction: single_use_tx
|
|
247
|
+
end
|
|
248
|
+
results
|
|
249
|
+
end
|
|
250
|
+
alias_method :query, :execute
|
|
251
|
+
|
|
252
|
+
##
|
|
253
|
+
# Read rows from a database table, as a simple alternative to
|
|
254
|
+
# {#execute}.
|
|
255
|
+
#
|
|
256
|
+
# @param [String] table The name of the table in the database to be
|
|
257
|
+
# read.
|
|
258
|
+
# @param [Array<String, Symbol>] columns The columns of table to be
|
|
259
|
+
# returned for each row matching this request.
|
|
260
|
+
# @param [Object, Array<Object>] keys A single, or list of keys or key
|
|
261
|
+
# ranges to match returned data to. Values should have exactly as many
|
|
262
|
+
# elements as there are columns in the primary key.
|
|
263
|
+
# @param [String] index The name of an index to use instead of the
|
|
264
|
+
# table's primary key when interpreting `id` and sorting result rows.
|
|
265
|
+
# Optional.
|
|
266
|
+
# @param [Integer] limit If greater than zero, no more than this number
|
|
267
|
+
# of rows will be returned. The default is no limit.
|
|
268
|
+
# @param [Hash] single_use Perform the read with a single-use snapshot
|
|
269
|
+
# (read-only transaction). (See
|
|
270
|
+
# [TransactionOptions](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#transactionoptions).)
|
|
271
|
+
# The snapshot can be created by providing exactly one of the
|
|
272
|
+
# following options in the hash:
|
|
273
|
+
#
|
|
274
|
+
# * **Strong**
|
|
275
|
+
# * `:strong` (true, false) Read at a timestamp where all previously
|
|
276
|
+
# committed transactions are visible.
|
|
277
|
+
# * **Exact**
|
|
278
|
+
# * `:timestamp`/`:read_timestamp` (Time, DateTime) Executes all
|
|
279
|
+
# reads at the given timestamp. Unlike other modes, reads at a
|
|
280
|
+
# specific timestamp are repeatable; the same read at the same
|
|
281
|
+
# timestamp always returns the same data. If the timestamp is in
|
|
282
|
+
# the future, the read will block until the specified timestamp,
|
|
283
|
+
# modulo the read's deadline.
|
|
284
|
+
#
|
|
285
|
+
# Useful for large scale consistent reads such as mapreduces, or
|
|
286
|
+
# for coordinating many reads against a consistent snapshot of the
|
|
287
|
+
# data.
|
|
288
|
+
# * `:staleness`/`:exact_staleness` (Numeric) Executes all reads at
|
|
289
|
+
# a timestamp that is exactly the number of seconds provided old.
|
|
290
|
+
# The timestamp is chosen soon after the read is started.
|
|
291
|
+
#
|
|
292
|
+
# Guarantees that all writes that have committed more than the
|
|
293
|
+
# specified number of seconds ago are visible. Because Cloud
|
|
294
|
+
# Spanner chooses the exact timestamp, this mode works even if the
|
|
295
|
+
# client's local clock is substantially skewed from Cloud Spanner
|
|
296
|
+
# commit timestamps.
|
|
297
|
+
#
|
|
298
|
+
# Useful for reading at nearby replicas without the distributed
|
|
299
|
+
# timestamp negotiation overhead of single-use
|
|
300
|
+
# `bounded_staleness`.
|
|
301
|
+
# * **Bounded**
|
|
302
|
+
# * `:bounded_timestamp`/`:min_read_timestamp` (Time, DateTime)
|
|
303
|
+
# Executes all reads at a timestamp greater than the value
|
|
304
|
+
# provided.
|
|
305
|
+
#
|
|
306
|
+
# This is useful for requesting fresher data than some previous
|
|
307
|
+
# read, or data that is fresh enough to observe the effects of
|
|
308
|
+
# some previously committed transaction whose timestamp is known.
|
|
309
|
+
# * `:bounded_staleness`/`:max_staleness` (Numeric) Read data at a
|
|
310
|
+
# timestamp greater than or equal to the number of seconds
|
|
311
|
+
# provided. Guarantees that all writes that have committed more
|
|
312
|
+
# than the specified number of seconds ago are visible. Because
|
|
313
|
+
# Cloud Spanner chooses the exact timestamp, this mode works even
|
|
314
|
+
# if the client's local clock is substantially skewed from Cloud
|
|
315
|
+
# Spanner commit timestamps.
|
|
316
|
+
#
|
|
317
|
+
# Useful for reading the freshest data available at a nearby
|
|
318
|
+
# replica, while bounding the possible staleness if the local
|
|
319
|
+
# replica has fallen behind.
|
|
320
|
+
#
|
|
321
|
+
# @return [Google::Cloud::Spanner::Results] The results of the read.
|
|
322
|
+
#
|
|
323
|
+
# @example
|
|
324
|
+
# require "google/cloud/spanner"
|
|
325
|
+
#
|
|
326
|
+
# spanner = Google::Cloud::Spanner.new
|
|
327
|
+
#
|
|
328
|
+
# db = spanner.client "my-instance", "my-database"
|
|
329
|
+
#
|
|
330
|
+
# results = db.read "users", [:id, :name]
|
|
331
|
+
#
|
|
332
|
+
# results.rows.each do |row|
|
|
333
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
334
|
+
# end
|
|
335
|
+
#
|
|
336
|
+
# @example Use the `keys` option to pass keys and/or key ranges to read.
|
|
337
|
+
# require "google/cloud/spanner"
|
|
338
|
+
#
|
|
339
|
+
# spanner = Google::Cloud::Spanner.new
|
|
340
|
+
#
|
|
341
|
+
# db = spanner.client "my-instance", "my-database"
|
|
342
|
+
#
|
|
343
|
+
# results = db.read "users", [:id, :name], keys: 1..5
|
|
344
|
+
#
|
|
345
|
+
# results.rows.each do |row|
|
|
346
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
347
|
+
# end
|
|
348
|
+
#
|
|
349
|
+
def read table, columns, keys: nil, index: nil, limit: nil,
|
|
350
|
+
single_use: nil
|
|
351
|
+
validate_single_use_args! single_use
|
|
352
|
+
ensure_service!
|
|
353
|
+
|
|
354
|
+
single_use_tx = single_use_transaction single_use
|
|
355
|
+
results = nil
|
|
356
|
+
@pool.with_session do |session|
|
|
357
|
+
results = session.read \
|
|
358
|
+
table, columns, keys: keys, index: index, limit: limit,
|
|
359
|
+
transaction: single_use_tx
|
|
360
|
+
end
|
|
361
|
+
results
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
##
|
|
365
|
+
# Inserts or updates rows in a table. If any of the rows already exist,
|
|
366
|
+
# then its column values are overwritten with the ones provided. Any
|
|
367
|
+
# column values not explicitly written are preserved.
|
|
368
|
+
#
|
|
369
|
+
# Changes are made immediately upon calling this method using a
|
|
370
|
+
# single-use transaction. To make multiple changes in the same
|
|
371
|
+
# single-use transaction use {#commit}. To make changes in a transaction
|
|
372
|
+
# that supports reads and automatic retry protection use {#transaction}.
|
|
373
|
+
#
|
|
374
|
+
# **Note:** This method does not feature replay protection present in
|
|
375
|
+
# {Transaction#upsert} (See {#transaction}). This method makes a single
|
|
376
|
+
# RPC, whereas {Transaction#upsert} requires two RPCs (one of which may
|
|
377
|
+
# be performed in advance), and so this method may be appropriate for
|
|
378
|
+
# latency sensitive and/or high throughput blind upserts.
|
|
379
|
+
#
|
|
380
|
+
# @param [String] table The name of the table in the database to be
|
|
381
|
+
# modified.
|
|
382
|
+
# @param [Array<Hash>] rows One or more hash objects with the hash keys
|
|
383
|
+
# matching the table's columns, and the hash values matching the
|
|
384
|
+
# table's values.
|
|
385
|
+
#
|
|
386
|
+
# Ruby types are mapped to Spanner types as follows:
|
|
387
|
+
#
|
|
388
|
+
# | Spanner | Ruby | Notes |
|
|
389
|
+
# |-------------|----------------|---|
|
|
390
|
+
# | `BOOL` | `true`/`false` | |
|
|
391
|
+
# | `INT64` | `Integer` | |
|
|
392
|
+
# | `FLOAT64` | `Float` | |
|
|
393
|
+
# | `STRING` | `String` | |
|
|
394
|
+
# | `DATE` | `Date` | |
|
|
395
|
+
# | `TIMESTAMP` | `Time`, `DateTime` | |
|
|
396
|
+
# | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
|
|
397
|
+
# | `ARRAY` | `Array` | Nested arrays are not supported. |
|
|
398
|
+
#
|
|
399
|
+
# See [Data
|
|
400
|
+
# types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
|
|
401
|
+
#
|
|
402
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
403
|
+
#
|
|
404
|
+
# @example
|
|
405
|
+
# require "google/cloud/spanner"
|
|
406
|
+
#
|
|
407
|
+
# spanner = Google::Cloud::Spanner.new
|
|
408
|
+
#
|
|
409
|
+
# db = spanner.client "my-instance", "my-database"
|
|
410
|
+
#
|
|
411
|
+
# db.upsert "users", [{ id: 1, name: "Charlie", active: false },
|
|
412
|
+
# { id: 2, name: "Harvey", active: true }]
|
|
413
|
+
#
|
|
414
|
+
def upsert table, *rows
|
|
415
|
+
@pool.with_session do |session|
|
|
416
|
+
session.upsert table, rows
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
alias_method :save, :upsert
|
|
420
|
+
|
|
421
|
+
##
|
|
422
|
+
# Inserts new rows in a table. If any of the rows already exist, the
|
|
423
|
+
# write or request fails with {Google::Cloud::AlreadyExistsError}.
|
|
424
|
+
#
|
|
425
|
+
# Changes are made immediately upon calling this method using a
|
|
426
|
+
# single-use transaction. To make multiple changes in the same
|
|
427
|
+
# single-use transaction use {#commit}. To make changes in a transaction
|
|
428
|
+
# that supports reads and automatic retry protection use {#transaction}.
|
|
429
|
+
#
|
|
430
|
+
# **Note:** This method does not feature replay protection present in
|
|
431
|
+
# {Transaction#insert} (See {#transaction}). This method makes a single
|
|
432
|
+
# RPC, whereas {Transaction#insert} requires two RPCs (one of which may
|
|
433
|
+
# be performed in advance), and so this method may be appropriate for
|
|
434
|
+
# latency sensitive and/or high throughput blind inserts.
|
|
435
|
+
#
|
|
436
|
+
# @param [String] table The name of the table in the database to be
|
|
437
|
+
# modified.
|
|
438
|
+
# @param [Array<Hash>] rows One or more hash objects with the hash keys
|
|
439
|
+
# matching the table's columns, and the hash values matching the
|
|
440
|
+
# table's values.
|
|
441
|
+
#
|
|
442
|
+
# Ruby types are mapped to Spanner types as follows:
|
|
443
|
+
#
|
|
444
|
+
# | Spanner | Ruby | Notes |
|
|
445
|
+
# |-------------|----------------|---|
|
|
446
|
+
# | `BOOL` | `true`/`false` | |
|
|
447
|
+
# | `INT64` | `Integer` | |
|
|
448
|
+
# | `FLOAT64` | `Float` | |
|
|
449
|
+
# | `STRING` | `String` | |
|
|
450
|
+
# | `DATE` | `Date` | |
|
|
451
|
+
# | `TIMESTAMP` | `Time`, `DateTime` | |
|
|
452
|
+
# | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
|
|
453
|
+
# | `ARRAY` | `Array` | Nested arrays are not supported. |
|
|
454
|
+
#
|
|
455
|
+
# See [Data
|
|
456
|
+
# types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
|
|
457
|
+
#
|
|
458
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
459
|
+
#
|
|
460
|
+
# @example
|
|
461
|
+
# require "google/cloud/spanner"
|
|
462
|
+
#
|
|
463
|
+
# spanner = Google::Cloud::Spanner.new
|
|
464
|
+
#
|
|
465
|
+
# db = spanner.client "my-instance", "my-database"
|
|
466
|
+
#
|
|
467
|
+
# db.insert "users", [{ id: 1, name: "Charlie", active: false },
|
|
468
|
+
# { id: 2, name: "Harvey", active: true }]
|
|
469
|
+
#
|
|
470
|
+
def insert table, *rows
|
|
471
|
+
@pool.with_session do |session|
|
|
472
|
+
session.insert table, rows
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
##
|
|
477
|
+
# Updates existing rows in a table. If any of the rows does not already
|
|
478
|
+
# exist, the request fails with {Google::Cloud::NotFoundError}.
|
|
479
|
+
#
|
|
480
|
+
# Changes are made immediately upon calling this method using a
|
|
481
|
+
# single-use transaction. To make multiple changes in the same
|
|
482
|
+
# single-use transaction use {#commit}. To make changes in a transaction
|
|
483
|
+
# that supports reads and automatic retry protection use {#transaction}.
|
|
484
|
+
#
|
|
485
|
+
# **Note:** This method does not feature replay protection present in
|
|
486
|
+
# {Transaction#update} (See {#transaction}). This method makes a single
|
|
487
|
+
# RPC, whereas {Transaction#update} requires two RPCs (one of which may
|
|
488
|
+
# be performed in advance), and so this method may be appropriate for
|
|
489
|
+
# latency sensitive and/or high throughput blind updates.
|
|
490
|
+
#
|
|
491
|
+
# @param [String] table The name of the table in the database to be
|
|
492
|
+
# modified.
|
|
493
|
+
# @param [Array<Hash>] rows One or more hash objects with the hash keys
|
|
494
|
+
# matching the table's columns, and the hash values matching the
|
|
495
|
+
# table's values.
|
|
496
|
+
#
|
|
497
|
+
# Ruby types are mapped to Spanner types as follows:
|
|
498
|
+
#
|
|
499
|
+
# | Spanner | Ruby | Notes |
|
|
500
|
+
# |-------------|----------------|---|
|
|
501
|
+
# | `BOOL` | `true`/`false` | |
|
|
502
|
+
# | `INT64` | `Integer` | |
|
|
503
|
+
# | `FLOAT64` | `Float` | |
|
|
504
|
+
# | `STRING` | `String` | |
|
|
505
|
+
# | `DATE` | `Date` | |
|
|
506
|
+
# | `TIMESTAMP` | `Time`, `DateTime` | |
|
|
507
|
+
# | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
|
|
508
|
+
# | `ARRAY` | `Array` | Nested arrays are not supported. |
|
|
509
|
+
#
|
|
510
|
+
# See [Data
|
|
511
|
+
# types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
|
|
512
|
+
#
|
|
513
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
514
|
+
#
|
|
515
|
+
# @example
|
|
516
|
+
# require "google/cloud/spanner"
|
|
517
|
+
#
|
|
518
|
+
# spanner = Google::Cloud::Spanner.new
|
|
519
|
+
#
|
|
520
|
+
# db = spanner.client "my-instance", "my-database"
|
|
521
|
+
#
|
|
522
|
+
# db.update "users", [{ id: 1, name: "Charlie", active: false },
|
|
523
|
+
# { id: 2, name: "Harvey", active: true }]
|
|
524
|
+
#
|
|
525
|
+
def update table, *rows
|
|
526
|
+
@pool.with_session do |session|
|
|
527
|
+
session.update table, rows
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
##
|
|
532
|
+
# Inserts or replaces rows in a table. If any of the rows already exist,
|
|
533
|
+
# it is deleted, and the column values provided are inserted instead.
|
|
534
|
+
# Unlike #upsert, this means any values not explicitly written become
|
|
535
|
+
# `NULL`.
|
|
536
|
+
#
|
|
537
|
+
# Changes are made immediately upon calling this method using a
|
|
538
|
+
# single-use transaction. To make multiple changes in the same
|
|
539
|
+
# single-use transaction use {#commit}. To make changes in a transaction
|
|
540
|
+
# that supports reads and automatic retry protection use {#transaction}.
|
|
541
|
+
#
|
|
542
|
+
# **Note:** This method does not feature replay protection present in
|
|
543
|
+
# {Transaction#replace} (See {#transaction}). This method makes a single
|
|
544
|
+
# RPC, whereas {Transaction#replace} requires two RPCs (one of which may
|
|
545
|
+
# be performed in advance), and so this method may be appropriate for
|
|
546
|
+
# latency sensitive and/or high throughput blind replaces.
|
|
547
|
+
#
|
|
548
|
+
# @param [String] table The name of the table in the database to be
|
|
549
|
+
# modified.
|
|
550
|
+
# @param [Array<Hash>] rows One or more hash objects with the hash keys
|
|
551
|
+
# matching the table's columns, and the hash values matching the
|
|
552
|
+
# table's values.
|
|
553
|
+
#
|
|
554
|
+
# Ruby types are mapped to Spanner types as follows:
|
|
555
|
+
#
|
|
556
|
+
# | Spanner | Ruby | Notes |
|
|
557
|
+
# |-------------|----------------|---|
|
|
558
|
+
# | `BOOL` | `true`/`false` | |
|
|
559
|
+
# | `INT64` | `Integer` | |
|
|
560
|
+
# | `FLOAT64` | `Float` | |
|
|
561
|
+
# | `STRING` | `String` | |
|
|
562
|
+
# | `DATE` | `Date` | |
|
|
563
|
+
# | `TIMESTAMP` | `Time`, `DateTime` | |
|
|
564
|
+
# | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
|
|
565
|
+
# | `ARRAY` | `Array` | Nested arrays are not supported. |
|
|
566
|
+
#
|
|
567
|
+
# See [Data
|
|
568
|
+
# types](https://cloud.google.com/spanner/docs/data-definition-language#data_types).
|
|
569
|
+
#
|
|
570
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
571
|
+
#
|
|
572
|
+
# @example
|
|
573
|
+
# require "google/cloud/spanner"
|
|
574
|
+
#
|
|
575
|
+
# spanner = Google::Cloud::Spanner.new
|
|
576
|
+
#
|
|
577
|
+
# db = spanner.client "my-instance", "my-database"
|
|
578
|
+
#
|
|
579
|
+
# db.replace "users", [{ id: 1, name: "Charlie", active: false },
|
|
580
|
+
# { id: 2, name: "Harvey", active: true }]
|
|
581
|
+
#
|
|
582
|
+
def replace table, *rows
|
|
583
|
+
@pool.with_session do |session|
|
|
584
|
+
session.replace table, rows
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
##
|
|
589
|
+
# Deletes rows from a table. Succeeds whether or not the specified rows
|
|
590
|
+
# were present.
|
|
591
|
+
#
|
|
592
|
+
# Changes are made immediately upon calling this method using a
|
|
593
|
+
# single-use transaction. To make multiple changes in the same
|
|
594
|
+
# single-use transaction use {#commit}. To make changes in a transaction
|
|
595
|
+
# that supports reads and automatic retry protection use {#transaction}.
|
|
596
|
+
#
|
|
597
|
+
# **Note:** This method does not feature replay protection present in
|
|
598
|
+
# {Transaction#delete} (See {#transaction}). This method makes a single
|
|
599
|
+
# RPC, whereas {Transaction#delete} requires two RPCs (one of which may
|
|
600
|
+
# be performed in advance), and so this method may be appropriate for
|
|
601
|
+
# latency sensitive and/or high throughput blind deletions.
|
|
602
|
+
#
|
|
603
|
+
# @param [String] table The name of the table in the database to be
|
|
604
|
+
# modified.
|
|
605
|
+
# @param [Object, Array<Object>] keys A single, or list of keys or key
|
|
606
|
+
# ranges to match returned data to. Values should have exactly as many
|
|
607
|
+
# elements as there are columns in the primary key.
|
|
608
|
+
#
|
|
609
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
610
|
+
#
|
|
611
|
+
# @example
|
|
612
|
+
# require "google/cloud/spanner"
|
|
613
|
+
#
|
|
614
|
+
# spanner = Google::Cloud::Spanner.new
|
|
615
|
+
#
|
|
616
|
+
# db = spanner.client "my-instance", "my-database"
|
|
617
|
+
#
|
|
618
|
+
# db.delete "users", [1, 2, 3]
|
|
619
|
+
#
|
|
620
|
+
def delete table, keys = []
|
|
621
|
+
@pool.with_session do |session|
|
|
622
|
+
session.delete table, keys
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
##
|
|
627
|
+
# Creates and commits a transaction for writes that execute atomically
|
|
628
|
+
# at a single logical point in time across columns, rows, and tables in
|
|
629
|
+
# a database.
|
|
630
|
+
#
|
|
631
|
+
# All changes are accumulated in memory until the block completes.
|
|
632
|
+
# Unlike {#transaction}, which can also perform reads, this operation
|
|
633
|
+
# accepts only mutations and makes a single API request.
|
|
634
|
+
#
|
|
635
|
+
# **Note:** This method does not feature replay protection present in
|
|
636
|
+
# {Transaction#commit} (See {#transaction}). This method makes a single
|
|
637
|
+
# RPC, whereas {Transaction#commit} requires two RPCs (one of which may
|
|
638
|
+
# be performed in advance), and so this method may be appropriate for
|
|
639
|
+
# latency sensitive and/or high throughput blind changes.
|
|
640
|
+
#
|
|
641
|
+
# @yield [commit] The block for mutating the data.
|
|
642
|
+
# @yieldparam [Google::Cloud::Spanner::Commit] commit The Commit object.
|
|
643
|
+
#
|
|
644
|
+
# @return [Time] The timestamp at which the operation committed.
|
|
645
|
+
#
|
|
646
|
+
# @example
|
|
647
|
+
# require "google/cloud/spanner"
|
|
648
|
+
#
|
|
649
|
+
# spanner = Google::Cloud::Spanner.new
|
|
650
|
+
#
|
|
651
|
+
# db = spanner.client "my-instance", "my-database"
|
|
652
|
+
#
|
|
653
|
+
# db.commit do |c|
|
|
654
|
+
# c.update "users", [{ id: 1, name: "Charlie", active: false }]
|
|
655
|
+
# c.insert "users", [{ id: 2, name: "Harvey", active: true }]
|
|
656
|
+
# end
|
|
657
|
+
#
|
|
658
|
+
def commit &block
|
|
659
|
+
fail ArgumentError, "Must provide a block" unless block_given?
|
|
660
|
+
|
|
661
|
+
@pool.with_session do |session|
|
|
662
|
+
session.commit(&block)
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
##
|
|
667
|
+
# Creates a transaction for reads and writes that execute atomically at
|
|
668
|
+
# a single logical point in time across columns, rows, and tables in a
|
|
669
|
+
# database.
|
|
670
|
+
#
|
|
671
|
+
# The transaction will always commit unless an error is raised. If the
|
|
672
|
+
# error raised is {Rollback} the transaction method will return without
|
|
673
|
+
# passing on the error. All other errors will be passed on.
|
|
674
|
+
#
|
|
675
|
+
# All changes are accumulated in memory until the block completes.
|
|
676
|
+
# Transactions will be automatically retried when possible, until
|
|
677
|
+
# `deadline` is reached. This operation makes separate API requests to
|
|
678
|
+
# begin and commit the transaction.
|
|
679
|
+
#
|
|
680
|
+
# @param [Numeric] deadline The total amount of time in seconds the
|
|
681
|
+
# transaction has to succeed. The default is `120`.
|
|
682
|
+
#
|
|
683
|
+
# @yield [transaction] The block for reading and writing data.
|
|
684
|
+
# @yieldparam [Google::Cloud::Spanner::Transaction] transaction The
|
|
685
|
+
# Transaction object.
|
|
686
|
+
#
|
|
687
|
+
# @return [Time] The timestamp at which the transaction committed.
|
|
688
|
+
#
|
|
689
|
+
# @example
|
|
690
|
+
# require "google/cloud/spanner"
|
|
691
|
+
#
|
|
692
|
+
# spanner = Google::Cloud::Spanner.new
|
|
693
|
+
# db = spanner.client "my-instance", "my-database"
|
|
694
|
+
#
|
|
695
|
+
# db.transaction do |tx|
|
|
696
|
+
# results = tx.execute "SELECT * FROM users"
|
|
697
|
+
#
|
|
698
|
+
# results.rows.each do |row|
|
|
699
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
700
|
+
# end
|
|
701
|
+
#
|
|
702
|
+
# c.update "users", [{ id: 1, name: "Charlie", active: false }]
|
|
703
|
+
# c.insert "users", [{ id: 2, name: "Harvey", active: true }]
|
|
704
|
+
# end
|
|
705
|
+
#
|
|
706
|
+
# @example Manually rollback the transaction using {Rollback}:
|
|
707
|
+
# require "google/cloud/spanner"
|
|
708
|
+
#
|
|
709
|
+
# spanner = Google::Cloud::Spanner.new
|
|
710
|
+
# db = spanner.client "my-instance", "my-database"
|
|
711
|
+
#
|
|
712
|
+
# db.transaction do |tx|
|
|
713
|
+
# c.update "users", [{ id: 1, name: "Charlie", active: false }]
|
|
714
|
+
# c.insert "users", [{ id: 2, name: "Harvey", active: true }]
|
|
715
|
+
#
|
|
716
|
+
# if something_wrong?
|
|
717
|
+
# # Rollback the transaction without passing on the error
|
|
718
|
+
# # outside of the transaction method.
|
|
719
|
+
# raise Google::Cloud::Spanner::Rollback
|
|
720
|
+
# end
|
|
721
|
+
# end
|
|
722
|
+
#
|
|
723
|
+
def transaction deadline: 120, &block
|
|
724
|
+
ensure_service!
|
|
725
|
+
|
|
726
|
+
deadline = validate_deadline deadline
|
|
727
|
+
backoff = 1.0
|
|
728
|
+
start_time = current_time
|
|
729
|
+
|
|
730
|
+
@pool.with_transaction do |tx|
|
|
731
|
+
begin
|
|
732
|
+
block.call tx
|
|
733
|
+
commit_resp = @project.service.commit \
|
|
734
|
+
tx.session.path, tx.mutations, transaction_id: tx.transaction_id
|
|
735
|
+
return Convert.timestamp_to_time commit_resp.commit_timestamp
|
|
736
|
+
rescue Google::Cloud::AbortedError => err
|
|
737
|
+
# Re-raise if deadline has passed
|
|
738
|
+
raise err if current_time - start_time > deadline
|
|
739
|
+
# Sleep the amount from RetryDelay, or incremental backoff
|
|
740
|
+
sleep(delay_from_aborted(err) || backoff *= 1.3)
|
|
741
|
+
# Create new transaction on the session and retry the block
|
|
742
|
+
tx = tx.session.create_transaction
|
|
743
|
+
retry
|
|
744
|
+
rescue => err
|
|
745
|
+
# Rollback transaction when handling unexpected error
|
|
746
|
+
tx.session.rollback tx.transaction_id
|
|
747
|
+
# Return nil if raised with rollback.
|
|
748
|
+
return nil if err.is_a? Rollback
|
|
749
|
+
# Re-raise error.
|
|
750
|
+
raise err
|
|
751
|
+
end
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
##
|
|
756
|
+
# Creates a snapshot read-only transaction for reads that execute
|
|
757
|
+
# atomically at a single logical point in time across columns, rows, and
|
|
758
|
+
# tables in a database. For transactions that only read, snapshot
|
|
759
|
+
# read-only transactions provide simpler semantics and are almost always
|
|
760
|
+
# faster than read-write transactions.
|
|
761
|
+
#
|
|
762
|
+
# @param [true, false] strong Read at a timestamp where all previously
|
|
763
|
+
# committed transactions are visible.
|
|
764
|
+
# @param [Time, DateTime] timestamp Executes all reads at the given
|
|
765
|
+
# timestamp. Unlike other modes, reads at a specific timestamp are
|
|
766
|
+
# repeatable; the same read at the same timestamp always returns the
|
|
767
|
+
# same data. If the timestamp is in the future, the read will block
|
|
768
|
+
# until the specified timestamp, modulo the read's deadline.
|
|
769
|
+
#
|
|
770
|
+
# Useful for large scale consistent reads such as mapreduces, or for
|
|
771
|
+
# coordinating many reads against a consistent snapshot of the data.
|
|
772
|
+
# (See
|
|
773
|
+
# [TransactionOptions](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#transactionoptions).)
|
|
774
|
+
# @param [Time, DateTime] read_timestamp Same as `timestamp`.
|
|
775
|
+
# @param [Numeric] staleness Executes all reads at a timestamp that is
|
|
776
|
+
# +staleness+ old. The timestamp is chosen soon after the read
|
|
777
|
+
# is started.
|
|
778
|
+
#
|
|
779
|
+
# Guarantees that all writes that have committed more than the
|
|
780
|
+
# specified number of seconds ago are visible. Because Cloud Spanner
|
|
781
|
+
# chooses the exact timestamp, this mode works even if the client's
|
|
782
|
+
# local clock is substantially skewed from Cloud Spanner commit
|
|
783
|
+
# timestamps.
|
|
784
|
+
#
|
|
785
|
+
# Useful for reading at nearby replicas without the distributed
|
|
786
|
+
# timestamp negotiation overhead of single-use +staleness+. (See
|
|
787
|
+
# [TransactionOptions](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#transactionoptions).)
|
|
788
|
+
# @param [Numeric] exact_staleness Same as `staleness`.
|
|
789
|
+
#
|
|
790
|
+
# @yield [snapshot] The block for reading and writing data.
|
|
791
|
+
# @yieldparam [Google::Cloud::Spanner::Snapshot] snapshot The Snapshot
|
|
792
|
+
# object.
|
|
793
|
+
#
|
|
794
|
+
# @example
|
|
795
|
+
# require "google/cloud/spanner"
|
|
796
|
+
#
|
|
797
|
+
# spanner = Google::Cloud::Spanner.new
|
|
798
|
+
# db = spanner.client "my-instance", "my-database"
|
|
799
|
+
#
|
|
800
|
+
# db.snapshot do |snp|
|
|
801
|
+
# results = snp.execute "SELECT * FROM users"
|
|
802
|
+
#
|
|
803
|
+
# results.rows.each do |row|
|
|
804
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
805
|
+
# end
|
|
806
|
+
# end
|
|
807
|
+
#
|
|
808
|
+
def snapshot strong: nil, timestamp: nil, read_timestamp: nil,
|
|
809
|
+
staleness: nil, exact_staleness: nil
|
|
810
|
+
validate_snapshot_args! strong: strong, timestamp: timestamp,
|
|
811
|
+
read_timestamp: read_timestamp,
|
|
812
|
+
staleness: staleness,
|
|
813
|
+
exact_staleness: exact_staleness
|
|
814
|
+
ensure_service!
|
|
815
|
+
@pool.with_session do |session|
|
|
816
|
+
snp_grpc = @project.service.create_snapshot \
|
|
817
|
+
session.path, strong: strong,
|
|
818
|
+
timestamp: (timestamp || read_timestamp),
|
|
819
|
+
staleness: (staleness || exact_staleness)
|
|
820
|
+
snp = Snapshot.from_grpc(snp_grpc, session)
|
|
821
|
+
yield snp if block_given?
|
|
822
|
+
end
|
|
823
|
+
nil
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
##
|
|
827
|
+
# @private
|
|
828
|
+
# Creates fields object from types.
|
|
829
|
+
#
|
|
830
|
+
# @param [Array, Hash] types Accepts an array of types, array of type
|
|
831
|
+
# pairs, hash of positional types, hash of named types.
|
|
832
|
+
#
|
|
833
|
+
# @return [Fields] The fields of the given types.
|
|
834
|
+
#
|
|
835
|
+
# @example
|
|
836
|
+
# require "google/cloud/spanner"
|
|
837
|
+
#
|
|
838
|
+
# spanner = Google::Cloud::Spanner.new
|
|
839
|
+
#
|
|
840
|
+
# db = spanner.client "my-instance", "my-database"
|
|
841
|
+
# user_fields = db.fields id: :INT64, name: :STRING, active: :BOOL
|
|
842
|
+
#
|
|
843
|
+
# db.update "users", [user_fields.data(1, "Charlie", false),
|
|
844
|
+
# user_fields.data(2, "Harvey", true)]
|
|
845
|
+
#
|
|
846
|
+
def fields types
|
|
847
|
+
Fields.new types
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
##
|
|
851
|
+
# @private
|
|
852
|
+
# Executes a query to retrieve the field names and types for a table.
|
|
853
|
+
#
|
|
854
|
+
# @param [String] table The name of the table in the database to
|
|
855
|
+
# retrieve fields for.
|
|
856
|
+
#
|
|
857
|
+
# @return [Fields] The fields of the given table.
|
|
858
|
+
#
|
|
859
|
+
# @example
|
|
860
|
+
# require "google/cloud/spanner"
|
|
861
|
+
#
|
|
862
|
+
# spanner = Google::Cloud::Spanner.new
|
|
863
|
+
#
|
|
864
|
+
# db = spanner.client "my-instance", "my-database"
|
|
865
|
+
#
|
|
866
|
+
# users_types = db.fields_for "users"
|
|
867
|
+
# db.insert "users", [{ id: 1, name: "Charlie", active: false },
|
|
868
|
+
# { id: 2, name: "Harvey", active: true }],
|
|
869
|
+
# types: users_types
|
|
870
|
+
#
|
|
871
|
+
def fields_for table
|
|
872
|
+
execute("SELECT * FROM #{table} WHERE 1 = 0").fields
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
##
|
|
876
|
+
# Creates a Spanner Range. This can be used in place of a Ruby Range
|
|
877
|
+
# when needing to exclude the beginning value.
|
|
878
|
+
#
|
|
879
|
+
# @param [Object] beginning The object that defines the beginning of the
|
|
880
|
+
# range.
|
|
881
|
+
# @param [Object] ending The object that defines the end of the range.
|
|
882
|
+
# @param [Boolean] exclude_begin Determines if the range excludes its
|
|
883
|
+
# beginning value. Default is `false`.
|
|
884
|
+
# @param [Boolean] exclude_end Determines if the range excludes its
|
|
885
|
+
# ending value. Default is `false`.
|
|
886
|
+
#
|
|
887
|
+
# @return [Google::Cloud::Spanner::Range] The new Range instance.
|
|
888
|
+
#
|
|
889
|
+
# @example
|
|
890
|
+
# require "google/cloud/spanner"
|
|
891
|
+
#
|
|
892
|
+
# spanner = Google::Cloud::Spanner.new
|
|
893
|
+
#
|
|
894
|
+
# db = spanner.client "my-instance", "my-database"
|
|
895
|
+
#
|
|
896
|
+
# key_range = db.range 1, 100
|
|
897
|
+
# results = db.read "users", [:id, :name], keys: key_range
|
|
898
|
+
#
|
|
899
|
+
# results.rows.each do |row|
|
|
900
|
+
# puts "User #{row[:id]} is #{row[:name]}"
|
|
901
|
+
# end
|
|
902
|
+
#
|
|
903
|
+
def range beginning, ending, exclude_begin: false, exclude_end: false
|
|
904
|
+
Range.new beginning, ending,
|
|
905
|
+
exclude_begin: exclude_begin,
|
|
906
|
+
exclude_end: exclude_end
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
##
|
|
910
|
+
# Closes the client connection and releases resources.
|
|
911
|
+
#
|
|
912
|
+
def close
|
|
913
|
+
@pool.close
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
##
|
|
917
|
+
# @private
|
|
918
|
+
# Creates a new session object every time.
|
|
919
|
+
def create_new_session
|
|
920
|
+
ensure_service!
|
|
921
|
+
grpc = @project.service.create_session \
|
|
922
|
+
Admin::Database::V1::DatabaseAdminClient.database_path(
|
|
923
|
+
project_id, instance_id, database_id)
|
|
924
|
+
Session.from_grpc(grpc, @project.service)
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
# @private
|
|
928
|
+
def to_s
|
|
929
|
+
"(project_id: #{project_id}, instance_id: #{instance_id}, " \
|
|
930
|
+
"database_id: #{database_id})"
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
# @private
|
|
934
|
+
def inspect
|
|
935
|
+
"#<#{self.class.name} #{self}>"
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
protected
|
|
939
|
+
|
|
940
|
+
##
|
|
941
|
+
# @private Raise an error unless an active connection to the service is
|
|
942
|
+
# available.
|
|
943
|
+
def ensure_service!
|
|
944
|
+
fail "Must have active connection to service" unless @project.service
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
##
|
|
948
|
+
# Check for valid snapshot arguments
|
|
949
|
+
def validate_single_use_args! opts
|
|
950
|
+
return true if opts.nil? || opts.empty?
|
|
951
|
+
valid_keys = [:strong, :timestamp, :read_timestamp, :staleness,
|
|
952
|
+
:exact_staleness, :bounded_timestamp,
|
|
953
|
+
:min_read_timestamp, :bounded_staleness, :max_staleness]
|
|
954
|
+
if opts.keys.count == 1 && valid_keys.include?(opts.keys.first)
|
|
955
|
+
return true
|
|
956
|
+
end
|
|
957
|
+
fail ArgumentError,
|
|
958
|
+
"Must provide only one of the following single_use values: " \
|
|
959
|
+
"#{valid_keys}"
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
##
|
|
963
|
+
# Create a single-use TransactionSelector
|
|
964
|
+
def single_use_transaction opts
|
|
965
|
+
return nil if opts.nil? || opts.empty?
|
|
966
|
+
|
|
967
|
+
exact_timestamp = Convert.time_to_timestamp \
|
|
968
|
+
opts[:timestamp] || opts[:read_timestamp]
|
|
969
|
+
exact_staleness = Convert.number_to_duration \
|
|
970
|
+
opts[:staleness] || opts[:exact_staleness]
|
|
971
|
+
bounded_timestamp = Convert.time_to_timestamp \
|
|
972
|
+
opts[:bounded_timestamp] || opts[:min_read_timestamp]
|
|
973
|
+
bounded_staleness = Convert.number_to_duration \
|
|
974
|
+
opts[:bounded_staleness] || opts[:max_staleness]
|
|
975
|
+
|
|
976
|
+
Google::Spanner::V1::TransactionSelector.new(single_use:
|
|
977
|
+
Google::Spanner::V1::TransactionOptions.new(read_only:
|
|
978
|
+
Google::Spanner::V1::TransactionOptions::ReadOnly.new({
|
|
979
|
+
strong: opts[:strong],
|
|
980
|
+
read_timestamp: exact_timestamp,
|
|
981
|
+
exact_staleness: exact_staleness,
|
|
982
|
+
min_read_timestamp: bounded_timestamp,
|
|
983
|
+
max_staleness: bounded_staleness,
|
|
984
|
+
return_read_timestamp: true
|
|
985
|
+
}.delete_if { |_, v| v.nil? })))
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
##
|
|
989
|
+
# Check for valid snapshot arguments
|
|
990
|
+
def validate_snapshot_args! strong: nil,
|
|
991
|
+
timestamp: nil, read_timestamp: nil,
|
|
992
|
+
staleness: nil, exact_staleness: nil
|
|
993
|
+
valid_args_count = [strong, timestamp, read_timestamp, staleness,
|
|
994
|
+
exact_staleness].compact.count
|
|
995
|
+
return true if valid_args_count <= 1
|
|
996
|
+
fail ArgumentError,
|
|
997
|
+
"Can only provide one of the following arguments: " \
|
|
998
|
+
"(strong, timestamp, read_timestamp, staleness, exact_staleness)"
|
|
999
|
+
end
|
|
1000
|
+
|
|
1001
|
+
def validate_deadline deadline
|
|
1002
|
+
return 120 unless deadline.is_a? Numeric
|
|
1003
|
+
return 120 if deadline < 0
|
|
1004
|
+
deadline
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
##
|
|
1008
|
+
# Defer to this method so we have something to mock for tests
|
|
1009
|
+
def current_time
|
|
1010
|
+
Time.now
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
##
|
|
1014
|
+
# Retrieves the delay value from Google::Cloud::AbortedError
|
|
1015
|
+
def delay_from_aborted err
|
|
1016
|
+
return nil if err.nil?
|
|
1017
|
+
if err.respond_to?(:metadata) && err.metadata["retryDelay"]
|
|
1018
|
+
# a correct metadata will look like this:
|
|
1019
|
+
# "{\"retryDelay\":{\"seconds\":60}}"
|
|
1020
|
+
seconds = err.metadata["retryDelay"]["seconds"].to_i
|
|
1021
|
+
nanos = err.metadata["retryDelay"]["nanos"].to_i
|
|
1022
|
+
return seconds if nanos.zero?
|
|
1023
|
+
return seconds + (nanos / 1000000000.0)
|
|
1024
|
+
end
|
|
1025
|
+
# No metadata? Try the inner error
|
|
1026
|
+
delay_from_aborted(err.cause)
|
|
1027
|
+
rescue
|
|
1028
|
+
# Any error indicates the backoff should be handled elsewhere
|
|
1029
|
+
return nil
|
|
1030
|
+
end
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
end
|
|
1034
|
+
end
|