google-cloud-spanner 1.15.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,8 @@
15
15
 
16
16
  require "google/cloud/spanner/database/job"
17
17
  require "google/cloud/spanner/database/list"
18
+ require "google/cloud/spanner/database/restore_info"
19
+ require "google/cloud/spanner/backup"
18
20
  require "google/cloud/spanner/policy"
19
21
 
20
22
  module Google
@@ -114,6 +116,13 @@ module Google
114
116
  state == :READY
115
117
  end
116
118
 
119
+ ##
120
+ # The database is fully created from backup and optimizing.
121
+ # @return [Boolean]
122
+ def ready_optimizing?
123
+ state == :READY_OPTIMIZING
124
+ end
125
+
117
126
  ##
118
127
  # Retrieve the Data Definition Language (DDL) statements that define
119
128
  # database structures. DDL statements are used to create, update,
@@ -220,6 +229,257 @@ module Google
220
229
  true
221
230
  end
222
231
 
232
+
233
+ # @private
234
+ DATBASE_OPERATION_METADAT_FILTER_TEMPLATE = [
235
+ "(metadata.@type:CreateDatabaseMetadata AND " \
236
+ "metadata.database:%<database_id>s)",
237
+ "(metadata.@type:RestoreDatabaseMetadata AND "\
238
+ "metadata.name:%<database_id>s)",
239
+ "(metadata.@type:UpdateDatabaseDdl AND "\
240
+ "metadata.database:%<database_id>s)"
241
+ ].join(" OR ")
242
+
243
+ ##
244
+ # Retrieves the list of database operations for the given database.
245
+ #
246
+ # @param filter [String]
247
+ # A filter expression that filters what operations are returned in the
248
+ # response.
249
+ #
250
+ # The response returns a list of
251
+ # {Google::Longrunning::Operation long-running operations} whose names
252
+ # are prefixed by a database name within the specified instance.
253
+ # The long-running operation
254
+ # {Google::Longrunning::Operation#metadata metadata} field type
255
+ # `metadata.type_url` describes the type of the metadata.
256
+ #
257
+ # The filter expression must specify the field name,
258
+ # a comparison operator, and the value that you want to use for
259
+ # filtering. The value must be a string, a number, or a boolean.
260
+ # The comparison operator must be
261
+ # <, >, <=, >=, !=, =, or :. Colon ':' represents a HAS operator
262
+ # which is roughly synonymous with equality. Filter rules are case
263
+ # insensitive.
264
+ #
265
+ # The long-running operation fields eligible for filtering are:
266
+ # * `name` --> The name of the long-running operation
267
+ # * `done` --> False if the operation is in progress, else true.
268
+ # * `metadata.type_url` (using filter string `metadata.@type`) and
269
+ # fields in `metadata.value` (using filter string
270
+ # `metadata.<field_name>`, where <field_name> is a field in
271
+ # metadata.value) are eligible for filtering.
272
+ # * `error` --> Error associated with the long-running operation.
273
+ # * `response.type_url` (using filter string `response.@type`) and
274
+ # fields in `response.value` (using filter string
275
+ # `response.<field_name>`, where <field_name> is a field in
276
+ # response.value)are eligible for filtering.
277
+ #
278
+ # To filter on multiple expressions, provide each separate
279
+ # expression within parentheses. By default, each expression
280
+ # is an AND expression. However, you can include AND, OR, and NOT
281
+ # expressions explicitly.
282
+ #
283
+ # Some examples of using filters are:
284
+ #
285
+ # * `done:true` --> The operation is complete.
286
+ # * `(metadata.@type:type.googleapis.com/google.spanner.admin.\
287
+ # database.v1.RestoreDatabaseMetadata)
288
+ # AND (metadata.source_type:BACKUP)
289
+ # AND (metadata.backup_info.backup:backup_howl)
290
+ # AND (metadata.name:restored_howl)
291
+ # AND (metadata.progress.start_time < \"2018-03-28T14:50:00Z\")
292
+ # AND (error:*)`
293
+ # --> Return RestoreDatabase operations from backups whose name
294
+ # contains "backup_howl", where the created database name
295
+ # contains the string "restored_howl", the start_time of the
296
+ # restore operation is before 2018-03-28T14:50:00Z,
297
+ # and the operation returned an error.
298
+ # @param page_size [Integer]
299
+ # The maximum number of resources contained in the underlying API
300
+ # response. If page streaming is performed per-resource, this
301
+ # parameter does not affect the return value. If page streaming is
302
+ # performed per-page, this determines the maximum number of
303
+ # resources in a page.
304
+ #
305
+ # @return [Array<Google::Cloud::Spanner::Database::Job>] List
306
+ # representing the long-running, asynchronous processing
307
+ # of a database operations.
308
+ # (See {Google::Cloud::Spanner::Database::Job::List})
309
+ #
310
+ # @example
311
+ # require "google/cloud/spanner"
312
+ #
313
+ # spanner = Google::Cloud::Spanner.new
314
+ #
315
+ # database = spanner.database "my-instance", "my-database"
316
+ #
317
+ # jobs = database.database_operations
318
+ # jobs.each do |job|
319
+ # if job.error?
320
+ # p job.error
321
+ # else
322
+ # p job.database.database_id
323
+ # end
324
+ # end
325
+ #
326
+ # @example Retrieve all
327
+ # require "google/cloud/spanner"
328
+ #
329
+ # spanner = Google::Cloud::Spanner.new
330
+ #
331
+ # database = spanner.database "my-instance", "my-database"
332
+ #
333
+ # jobs = database.database_operations
334
+ # jobs.all do |job|
335
+ # if job.error?
336
+ # p job.error
337
+ # else
338
+ # puts job.database.database_id
339
+ # end
340
+ # end
341
+ #
342
+ # @example List by page size
343
+ # require "google/cloud/spanner"
344
+ #
345
+ # spanner = Google::Cloud::Spanner.new
346
+ #
347
+ # database = spanner.database "my-instance", "my-database"
348
+ #
349
+ # jobs = database.database_operations page_size: 10
350
+ # jobs.each do |job|
351
+ # if job.error?
352
+ # p job.error
353
+ # else
354
+ # puts job.database.database_id
355
+ # end
356
+ # end
357
+ #
358
+ # @example Filter and list
359
+ # require "google/cloud/spanner"
360
+ #
361
+ # spanner = Google::Cloud::Spanner.new
362
+ #
363
+ # database = spanner.database "my-instance", "my-database"
364
+ #
365
+ # jobs = database.database_operations filter: "done:true"
366
+ # jobs.each do |job|
367
+ # if job.error?
368
+ # p job.error
369
+ # else
370
+ # puts job.database.database_id
371
+ # end
372
+ # end
373
+ #
374
+ def database_operations filter: nil, page_size: nil
375
+ database_filter = format(
376
+ DATBASE_OPERATION_METADAT_FILTER_TEMPLATE,
377
+ database_id: database_id
378
+ )
379
+
380
+ if filter
381
+ database_filter = format(
382
+ "(%<filter>s) AND (%<database_filter>s)",
383
+ filter: filter, database_filter: database_filter
384
+ )
385
+ end
386
+
387
+ grpc = service.list_database_operations \
388
+ instance_id,
389
+ filter: database_filter,
390
+ page_size: page_size
391
+ Database::Job::List.from_grpc grpc, service
392
+ end
393
+
394
+ ##
395
+ # Creates a database backup.
396
+ #
397
+ # @param [String] backup_id The unique identifier for the backup.
398
+ # Values are of the form `[a-z][a-z0-9_\-]*[a-z0-9]` and must be
399
+ # between 2 and 60 characters in length. Required.
400
+ # @param [Time] expire_time The expiration time of the backup, with
401
+ # microseconds granularity that must be at least 6 hours and at most
402
+ # 366 days from the time the request is received. Required.
403
+ # Once the `expire_time` has passed, Cloud Spanner will delete the
404
+ # backup and free the resources used by the backup. Required.
405
+ # @return [Google::Cloud::Spanner::Backup::Job] The job representing
406
+ # the long-running, asynchronous processing of a backup create
407
+ # operation.
408
+ #
409
+ # @example Create backup with expiration time
410
+ # require "google/cloud/spanner"
411
+ #
412
+ # spanner = Google::Cloud::Spanner.new
413
+ # database = spanner.database "my-instance", "my-database"
414
+ #
415
+ # job = database.create_backup "my-backup", Time.now + 36000
416
+ #
417
+ # job.done? #=> false
418
+ # job.reload! # API call
419
+ # job.done? #=> true
420
+ #
421
+ # if job.error?
422
+ # status = job.error
423
+ # else
424
+ # backup = job.backup
425
+ # end
426
+ #
427
+ def create_backup backup_id, expire_time
428
+ ensure_service!
429
+ grpc = service.create_backup \
430
+ instance_id,
431
+ database_id,
432
+ backup_id,
433
+ expire_time
434
+ Backup::Job.from_grpc grpc, service
435
+ end
436
+
437
+ ##
438
+ # Retrieves backups belonging to the database.
439
+ #
440
+ # @param [Integer] page_size Optional. Number of backups to be returned
441
+ # in the response. If 0 or less, defaults to the server's maximum
442
+ # allowed page size.
443
+ # @return [Array<Google::Cloud::Spanner::Backup>] Enumerable list of
444
+ # backups. (See {Google::Cloud::Spanner::Backup::List})
445
+ #
446
+ # @example
447
+ # require "google/cloud/spanner"
448
+ #
449
+ # spanner = Google::Cloud::Spanner.new
450
+ # database = spanner.database "my-instance", "my-database"
451
+ #
452
+ # database.backups.all.each do |backup|
453
+ # puts backup.backup_id
454
+ # end
455
+ #
456
+ # @example List backups by page size
457
+ # require "google/cloud/spanner"
458
+ #
459
+ # spanner = Google::Cloud::Spanner.new
460
+ # database = spanner.database "my-instance", "my-database"
461
+ #
462
+ # database.backups(page_size: 5).all.each do |backup|
463
+ # puts backup.backup_id
464
+ # end
465
+ #
466
+ def backups page_size: nil
467
+ ensure_service!
468
+ grpc = service.list_backups \
469
+ instance_id,
470
+ filter: "database:#{database_id}",
471
+ page_size: page_size
472
+ Backup::List.from_grpc grpc, service
473
+ end
474
+
475
+ # Information about the source used to restore the database.
476
+ #
477
+ # @return [Google::Cloud::Spanner::Database::RestoreInfo, nil]
478
+ def restore_info
479
+ return nil unless @grpc.restore_info
480
+ RestoreInfo.from_grpc @grpc.restore_info
481
+ end
482
+
223
483
  ##
224
484
  # Gets the [Cloud IAM](https://cloud.google.com/iam/) access control
225
485
  # policy for this database.
@@ -0,0 +1,105 @@
1
+ # Copyright 2020 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
+ module Google
17
+ module Cloud
18
+ module Spanner
19
+ class Database
20
+ class BackupInfo
21
+ ##
22
+ # @private Creates a new Database::BackupInfo instance.
23
+ def initialize grpc
24
+ @grpc = grpc
25
+ end
26
+
27
+ ##
28
+ # The unique identifier for the project.
29
+ # @return [String]
30
+ def project_id
31
+ @grpc.backup.split("/")[1]
32
+ end
33
+
34
+ ##
35
+ # The unique identifier for the instance.
36
+ # @return [String]
37
+ def instance_id
38
+ @grpc.backup.split("/")[3]
39
+ end
40
+
41
+ ##
42
+ # The unique identifier for the backup.
43
+ # @return [String]
44
+ def backup_id
45
+ @grpc.backup.split("/")[5]
46
+ end
47
+
48
+ ##
49
+ # The full path for the backup. Values are of the form
50
+ # `projects/<project>/instances/<instance>/backups/<backup_id>`.
51
+ # @return [String]
52
+ def path
53
+ @grpc.backup
54
+ end
55
+
56
+ ##
57
+ # Name of the database the backup was created from.
58
+ # @return [String]
59
+ def source_database_id
60
+ @grpc.source_database.split("/")[5]
61
+ end
62
+
63
+ ##
64
+ # The unique identifier for the source database project.
65
+ # @return [String]
66
+ def source_database_project_id
67
+ @grpc.backup.split("/")[1]
68
+ end
69
+
70
+ ##
71
+ # The unique identifier for the source database instance.
72
+ # @return [String]
73
+ def source_database_instance_id
74
+ @grpc.backup.split("/")[3]
75
+ end
76
+
77
+ ##
78
+ # The full path for the source database the backup was created from.
79
+ # Values are of the form
80
+ # `projects/<project>/instances/<instance>/database/<database_id>`.
81
+ # @return [String]
82
+ def source_database_path
83
+ @grpc.source_database
84
+ end
85
+
86
+ ##
87
+ # The backup contains an externally consistent copy of
88
+ # `source_database` at the timestamp specified by `create_time`.
89
+ # received.
90
+ # @return [Time]
91
+ def create_time
92
+ Convert.timestamp_to_time @grpc.create_time
93
+ end
94
+
95
+ ##
96
+ # @private Creates a new Database::BackupInfo instance from a
97
+ # Google::Spanner::Admin::Database::V1::BackupInfo.
98
+ def self.from_grpc grpc
99
+ new grpc
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -14,6 +14,7 @@
14
14
 
15
15
 
16
16
  require "google/cloud/spanner/status"
17
+ require "google/cloud/spanner/database/job/list"
17
18
 
18
19
  module Google
19
20
  module Cloud
@@ -87,6 +88,8 @@ module Google
87
88
  def database
88
89
  return nil unless done?
89
90
  return nil unless @grpc.grpc_op.result == :response
91
+ return nil unless @grpc.results.instance_of? \
92
+ Google::Spanner::Admin::Database::V1::Database
90
93
  Database.from_grpc @grpc.results, service
91
94
  end
92
95
 
@@ -0,0 +1,177 @@
1
+ # Copyright 2020 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 "delegate"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Spanner
21
+ class Database
22
+ class Job
23
+ ##
24
+ # # List
25
+ #
26
+ # List is a special case Array with additional values for database
27
+ # operations.
28
+ #
29
+ class List < DelegateClass(::Array)
30
+ # @private
31
+ # The gRPC Service object.
32
+ attr_accessor :service
33
+
34
+ # @private
35
+ # The gRPC page enumerable object.
36
+ attr_accessor :grpc
37
+
38
+ ##
39
+ # @private Create a new Database::Job::List with an array of
40
+ # Google::Lognrunning::Operation instances.
41
+ def initialize arr = []
42
+ super arr
43
+ end
44
+
45
+ ##
46
+ # Whether there is a next page of database jobs.
47
+ #
48
+ # @return [Boolean]
49
+ #
50
+ # @example
51
+ # require "google/cloud/spanner"
52
+ #
53
+ # spanner = Google::Cloud::Spanner.new
54
+ #
55
+ # instance = spanner.instance "my-instance"
56
+ #
57
+ # jobs = instance.database_operations
58
+ # if jobs.next?
59
+ # next_jobs = jobs.next
60
+ # end
61
+ #
62
+ def next?
63
+ grpc.next_page?
64
+ end
65
+
66
+ ##
67
+ # Retrieve the next page of database jobs.
68
+ #
69
+ # @return [Google::Cloud::Spanner::Database::Job::List]
70
+ #
71
+ # @example
72
+ # require "google/cloud/spanner"
73
+ #
74
+ # spanner = Google::Cloud::Spanner.new
75
+ #
76
+ # instance = spanner.instance "my-instance"
77
+ #
78
+ # jobs = instance.database_operations
79
+ # if jobs.next?
80
+ # next_jobs = jobs.next
81
+ # end
82
+ #
83
+ def next
84
+ ensure_service!
85
+
86
+ return nil unless next?
87
+ grpc.next_page
88
+ self.class.from_grpc grpc, service
89
+ end
90
+
91
+ ##
92
+ # Retrieves remaining results by repeatedly invoking {#next} until
93
+ # {#next?} returns `false`. Calls the given block once for each
94
+ # result, which is passed as the argument to the block.
95
+ #
96
+ # An Enumerator is returned if no block is given.
97
+ #
98
+ # This method will make repeated API calls until all remaining
99
+ # results are retrieved. (Unlike `#each`, for example, which merely
100
+ # iterates over the results returned by a single API call.) Use with
101
+ # caution.
102
+ #
103
+ # @yield [job] The block for accessing each database job.
104
+ # @yieldparam [Google::Cloud::Spanner::Database::Job] job The
105
+ # database job object.
106
+ #
107
+ # @return [Enumerator]
108
+ #
109
+ # @example Iterating each database job by passing a block:
110
+ # require "google/cloud/spanner"
111
+ #
112
+ # spanner = Google::Cloud::Spanner.new
113
+ #
114
+ # instance = spanner.instance "my-instance"
115
+ #
116
+ # jobs = instance.database_operations
117
+ # jobs.all do |job|
118
+ # puts job.database.database_id
119
+ # end
120
+ #
121
+ # @example Using the enumerator by not passing a block:
122
+ # require "google/cloud/spanner"
123
+ #
124
+ # spanner = Google::Cloud::Spanner.new
125
+ #
126
+ # instance = spanner.instance "my-instance"
127
+ #
128
+ # jobs = instance.database_operations
129
+ # all_database_ids = jobs.all.map do |job|
130
+ # job.database.database_id
131
+ # end
132
+ #
133
+ def all
134
+ return enum_for :all unless block_given?
135
+
136
+ results = self
137
+ loop do
138
+ results.each { |r| yield r }
139
+ break unless next?
140
+ grpc.next_page
141
+ results = self.class.from_grpc grpc, service
142
+ end
143
+ end
144
+
145
+ ##
146
+ # @private
147
+ #
148
+ # New Database::Job::List from a
149
+ # Google::Gax::PagedEnumerable<Google::Longrunning::Operation>
150
+ # object. Operation object is a database operation.
151
+ #
152
+ def self.from_grpc grpc, service
153
+ operations_client = \
154
+ service.databases.instance_variable_get "@operations_client"
155
+ jobs = new(Array(grpc.response.operations).map do |job_grpc|
156
+ Job.from_grpc \
157
+ Google::Gax::Operation.new(job_grpc, operations_client),
158
+ service
159
+ end)
160
+ jobs.grpc = grpc
161
+ jobs.service = service
162
+ jobs
163
+ end
164
+
165
+ protected
166
+
167
+ ##
168
+ # Raise an error unless an active service is available.
169
+ def ensure_service!
170
+ raise "Must have active connection" unless @service
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end