google-cloud-spanner 2.0.0 → 2.5.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/CONTRIBUTING.md +2 -2
  4. data/LOGGING.md +1 -1
  5. data/lib/google-cloud-spanner.rb +1 -0
  6. data/lib/google/cloud/spanner.rb +7 -5
  7. data/lib/google/cloud/spanner/backup.rb +10 -2
  8. data/lib/google/cloud/spanner/backup/job.rb +8 -8
  9. data/lib/google/cloud/spanner/backup/job/list.rb +2 -2
  10. data/lib/google/cloud/spanner/backup/list.rb +2 -2
  11. data/lib/google/cloud/spanner/batch_snapshot.rb +114 -15
  12. data/lib/google/cloud/spanner/batch_update.rb +3 -1
  13. data/lib/google/cloud/spanner/client.rb +413 -78
  14. data/lib/google/cloud/spanner/commit_response.rb +87 -0
  15. data/lib/google/cloud/spanner/commit_response/commit_stats.rb +51 -0
  16. data/lib/google/cloud/spanner/convert.rb +9 -0
  17. data/lib/google/cloud/spanner/data.rb +4 -5
  18. data/lib/google/cloud/spanner/database.rb +25 -3
  19. data/lib/google/cloud/spanner/database/backup_info.rb +12 -3
  20. data/lib/google/cloud/spanner/database/job/list.rb +2 -2
  21. data/lib/google/cloud/spanner/database/list.rb +4 -4
  22. data/lib/google/cloud/spanner/fields.rb +3 -2
  23. data/lib/google/cloud/spanner/instance/config/list.rb +4 -4
  24. data/lib/google/cloud/spanner/instance/list.rb +4 -4
  25. data/lib/google/cloud/spanner/partition.rb +4 -2
  26. data/lib/google/cloud/spanner/policy.rb +3 -2
  27. data/lib/google/cloud/spanner/pool.rb +10 -10
  28. data/lib/google/cloud/spanner/results.rb +105 -26
  29. data/lib/google/cloud/spanner/service.rb +218 -107
  30. data/lib/google/cloud/spanner/session.rb +361 -30
  31. data/lib/google/cloud/spanner/snapshot.rb +58 -4
  32. data/lib/google/cloud/spanner/status.rb +4 -1
  33. data/lib/google/cloud/spanner/transaction.rb +114 -8
  34. data/lib/google/cloud/spanner/version.rb +1 -1
  35. metadata +12 -10
@@ -0,0 +1,87 @@
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 "google/cloud/spanner/commit_response/commit_stats"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Spanner
21
+ ##
22
+ # CommitResponse is a timestamp at which the transaction committed
23
+ # with additional attributes of commit stats.
24
+ #
25
+ # @example
26
+ # require "google/cloud/spanner"
27
+ #
28
+ # spanner = Google::Cloud::Spanner.new
29
+ #
30
+ # db = spanner.client "my-instance", "my-database"
31
+ #
32
+ # timestamp = db.commit do |c|
33
+ # c.update "users", [{ id: 1, name: "Charlie", active: false }]
34
+ # c.insert "users", [{ id: 2, name: "Harvey", active: true }]
35
+ # end
36
+ #
37
+ # puts timestamp
38
+ #
39
+ # @example With commit stats.
40
+ # require "google/cloud/spanner"
41
+ #
42
+ # spanner = Google::Cloud::Spanner.new
43
+ #
44
+ # db = spanner.client "my-instance", "my-database"
45
+ #
46
+ # commit_options = { return_commit_stats: true }
47
+ # commit_resp = db.commit commit_options: commit_options do |c|
48
+ # c.update "users", [{ id: 1, name: "Charlie", active: false }]
49
+ # c.insert "users", [{ id: 2, name: "Harvey", active: true }]
50
+ # end
51
+ #
52
+ # puts commit_resp.timestamp
53
+ # puts commit_resp.stats.mutation_count
54
+ #
55
+ class CommitResponse
56
+ ##
57
+ # @private Creates a new CommitResponse instance.
58
+ def initialize grpc
59
+ @grpc = grpc
60
+ end
61
+
62
+ ##
63
+ # The timestamp at which the transaction committed.
64
+ # @return [Time]
65
+ def timestamp
66
+ Convert.timestamp_to_time @grpc.commit_timestamp
67
+ end
68
+
69
+ ##
70
+ # Additional statistics about a commit.
71
+ # @return [CommitStats, nil] Commit stats or nil if not stats not
72
+ # present.
73
+ def stats
74
+ CommitStats.from_grpc @grpc.commit_stats if @grpc.commit_stats
75
+ end
76
+
77
+ ##
78
+ # @private
79
+ # Creates a new Commit responsee instance from a
80
+ # `Google::Cloud::Spanner::V1::CommitResponse`.
81
+ def self.from_grpc grpc
82
+ new grpc
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,51 @@
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 "google/cloud/spanner/convert"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Spanner
21
+ class CommitResponse
22
+ ##
23
+ # # CommitStats
24
+ #
25
+ # Statistical information of a transaction commit.
26
+ #
27
+ class CommitStats
28
+ ##
29
+ # @private Creates a new CommitStats instance.
30
+ def initialize grpc
31
+ @grpc = grpc
32
+ end
33
+
34
+ # The total number of the mutations for the transaction.
35
+ # @return [Integer]
36
+ def mutation_count
37
+ @grpc.mutation_count
38
+ end
39
+
40
+ ##
41
+ # @private
42
+ # Creates a new CommitStats instance from a
43
+ # `Google::Cloud::Spanner::V1::CommitResponse::CommitStats`.
44
+ def self.from_grpc grpc
45
+ new grpc
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -17,6 +17,7 @@ require "time"
17
17
  require "date"
18
18
  require "stringio"
19
19
  require "base64"
20
+ require "bigdecimal"
20
21
  require "google/cloud/spanner/data"
21
22
 
22
23
  module Google
@@ -67,6 +68,9 @@ module Google
67
68
  Google::Protobuf::Value.new bool_value: false
68
69
  when Integer
69
70
  Google::Protobuf::Value.new string_value: obj.to_s
71
+ # BigDecimal must be put before Numeric.
72
+ when BigDecimal
73
+ Google::Protobuf::Value.new string_value: obj.to_s("F")
70
74
  when Numeric
71
75
  if obj == Float::INFINITY
72
76
  Google::Protobuf::Value.new string_value: "Infinity"
@@ -125,6 +129,9 @@ module Google
125
129
  :BOOL
126
130
  when Integer
127
131
  :INT64
132
+ # BigDecimal must be put before Numeric.
133
+ when BigDecimal
134
+ :NUMERIC
128
135
  when Numeric
129
136
  :FLOAT64
130
137
  when Time
@@ -214,6 +221,8 @@ module Google
214
221
  end
215
222
  when :STRUCT
216
223
  Data.from_grpc value.list_value.values, type.struct_type.fields
224
+ when :NUMERIC
225
+ BigDecimal value.string_value
217
226
  end
218
227
  end
219
228
 
@@ -139,9 +139,10 @@ module Google
139
139
  #
140
140
  def to_a skip_dup_check: nil
141
141
  values.map do |value|
142
- if value.is_a? Data
142
+ case value
143
+ when Data
143
144
  value.to_h skip_dup_check: skip_dup_check
144
- elsif value.is_a? Array
145
+ when Array
145
146
  value.map do |v|
146
147
  v.is_a?(Data) ? v.to_h(skip_dup_check: skip_dup_check) : v
147
148
  end
@@ -169,9 +170,7 @@ module Google
169
170
  # or indexes and corresponding values.
170
171
  #
171
172
  def to_h skip_dup_check: nil
172
- unless skip_dup_check
173
- raise DuplicateNameError if fields.duplicate_names?
174
- end
173
+ raise DuplicateNameError if !skip_dup_check && fields.duplicate_names?
175
174
 
176
175
  Hash[keys.zip to_a(skip_dup_check: skip_dup_check)]
177
176
  end
@@ -85,6 +85,18 @@ module Google
85
85
  @grpc.name.split("/")[5]
86
86
  end
87
87
 
88
+ # The version retention period for a database.
89
+ # @return [String]
90
+ def version_retention_period
91
+ @grpc.version_retention_period
92
+ end
93
+
94
+ # The earliest available version time for a database.
95
+ # @return [Time]
96
+ def earliest_version_time
97
+ Convert.timestamp_to_time @grpc.earliest_version_time
98
+ end
99
+
88
100
  ##
89
101
  # The full path for the database resource. Values are of the form
90
102
  # `projects/<project_id>/instances/<instance_id>/databases/<database_id>`.
@@ -400,6 +412,11 @@ module Google
400
412
  # 366 days from the time the request is received. Required.
401
413
  # Once the `expire_time` has passed, Cloud Spanner will delete the
402
414
  # backup and free the resources used by the backup. Required.
415
+ # @param [Time] version_time Specifies the time to have an externally
416
+ # consistent copy of the database. If no version time is specified,
417
+ # it will be automatically set to the backup create time. The version
418
+ # time can be as far in the past as specified by the database earliest
419
+ # version time. Optional.
403
420
  # @return [Google::Cloud::Spanner::Backup::Job] The job representing
404
421
  # the long-running, asynchronous processing of a backup create
405
422
  # operation.
@@ -410,7 +427,11 @@ module Google
410
427
  # spanner = Google::Cloud::Spanner.new
411
428
  # database = spanner.database "my-instance", "my-database"
412
429
  #
413
- # job = database.create_backup "my-backup", Time.now + 36000
430
+ # backup_id = "my-backup"
431
+ # expire_time = Time.now + (24 * 60 * 60) # 1 day from now
432
+ # version_time = Time.now - (24 * 60 * 60) # 1 day ago (optional)
433
+ #
434
+ # job = database.create_backup backup_id, expire_time, version_time: version_time
414
435
  #
415
436
  # job.done? #=> false
416
437
  # job.reload! # API call
@@ -422,13 +443,14 @@ module Google
422
443
  # backup = job.backup
423
444
  # end
424
445
  #
425
- def create_backup backup_id, expire_time
446
+ def create_backup backup_id, expire_time, version_time: nil
426
447
  ensure_service!
427
448
  grpc = service.create_backup \
428
449
  instance_id,
429
450
  database_id,
430
451
  backup_id,
431
- expire_time
452
+ expire_time,
453
+ version_time
432
454
  Backup::Job.from_grpc grpc, service
433
455
  end
434
456
 
@@ -84,14 +84,23 @@ module Google
84
84
  end
85
85
 
86
86
  ##
87
- # The backup contains an externally consistent copy of
88
- # `source_database` at the timestamp specified by `create_time`.
89
- # received.
87
+ # The timestamp indicating the creation of the backup.
90
88
  # @return [Time]
91
89
  def create_time
92
90
  Convert.timestamp_to_time @grpc.create_time
93
91
  end
94
92
 
93
+ ##
94
+ # The backup contains an externally consistent copy of
95
+ # `source_database` at the timestamp specified by
96
+ # the `version_time` received. If no `version_time` was
97
+ # given during the creation of the backup, the `version_time`
98
+ # will be the same as the `create_time`.
99
+ # @return [Time]
100
+ def version_time
101
+ Convert.timestamp_to_time @grpc.version_time
102
+ end
103
+
95
104
  ##
96
105
  # @private Creates a new Database::BackupInfo instance from a
97
106
  # `Google::Cloud::Spanner::Admin::Database::V1::BackupInfo`.
@@ -130,12 +130,12 @@ module Google
130
130
  # job.database.database_id
131
131
  # end
132
132
  #
133
- def all
133
+ def all &block
134
134
  return enum_for :all unless block_given?
135
135
 
136
136
  results = self
137
137
  loop do
138
- results.each { |r| yield r }
138
+ results.each(&block)
139
139
  break unless next?
140
140
  grpc.next_page
141
141
  results = self.class.from_grpc grpc, service
@@ -71,7 +71,7 @@ module Google
71
71
  return nil unless next?
72
72
  ensure_service!
73
73
  options = { token: token, max: @max }
74
- grpc = @service.list_databases @instance_id, options
74
+ grpc = @service.list_databases @instance_id, **options
75
75
  self.class.from_grpc grpc, @service, @max
76
76
  end
77
77
 
@@ -123,17 +123,17 @@ module Google
123
123
  # puts database.database_id
124
124
  # end
125
125
  #
126
- def all request_limit: nil
126
+ def all request_limit: nil, &block
127
127
  request_limit = request_limit.to_i if request_limit
128
128
  unless block_given?
129
129
  return enum_for :all, request_limit: request_limit
130
130
  end
131
131
  results = self
132
132
  loop do
133
- results.each { |r| yield r }
133
+ results.each(&block)
134
134
  if request_limit
135
135
  request_limit -= 1
136
- break if request_limit < 0
136
+ break if request_limit.negative?
137
137
  end
138
138
  break unless results.next?
139
139
  results = results.next
@@ -133,13 +133,14 @@ module Google
133
133
  #
134
134
  def types
135
135
  @grpc_fields.map(&:type).map do |type|
136
- if type.code == :ARRAY
136
+ case type.code
137
+ when :ARRAY
137
138
  if type.array_element_type.code == :STRUCT
138
139
  [Fields.from_grpc(type.array_element_type.struct_type.fields)]
139
140
  else
140
141
  [type.array_element_type.code]
141
142
  end
142
- elsif type.code == :STRUCT
143
+ when :STRUCT
143
144
  Fields.from_grpc type.struct_type.fields
144
145
  else
145
146
  type.code
@@ -73,7 +73,7 @@ module Google
73
73
  return nil unless next?
74
74
  ensure_service!
75
75
  options = { token: token, max: @max }
76
- grpc = @service.list_instance_configs options
76
+ grpc = @service.list_instance_configs(**options)
77
77
  self.class.from_grpc grpc, @service, @max
78
78
  end
79
79
 
@@ -123,17 +123,17 @@ module Google
123
123
  # puts config.instance_config_id
124
124
  # end
125
125
  #
126
- def all request_limit: nil
126
+ def all request_limit: nil, &block
127
127
  request_limit = request_limit.to_i if request_limit
128
128
  unless block_given?
129
129
  return enum_for :all, request_limit: request_limit
130
130
  end
131
131
  results = self
132
132
  loop do
133
- results.each { |r| yield r }
133
+ results.each(&block)
134
134
  if request_limit
135
135
  request_limit -= 1
136
- break if request_limit < 0
136
+ break if request_limit.negative?
137
137
  end
138
138
  break unless results.next?
139
139
  results = results.next
@@ -71,7 +71,7 @@ module Google
71
71
  return nil unless next?
72
72
  ensure_service!
73
73
  options = { token: token, max: @max }
74
- grpc = @service.list_instances options
74
+ grpc = @service.list_instances(**options)
75
75
  self.class.from_grpc grpc, @service, @max
76
76
  end
77
77
 
@@ -120,17 +120,17 @@ module Google
120
120
  # puts instance.instance_id
121
121
  # end
122
122
  #
123
- def all request_limit: nil
123
+ def all request_limit: nil, &block
124
124
  request_limit = request_limit.to_i if request_limit
125
125
  unless block_given?
126
126
  return enum_for :all, request_limit: request_limit
127
127
  end
128
128
  results = self
129
129
  loop do
130
- results.each { |r| yield r }
130
+ results.each(&block)
131
131
  if request_limit
132
132
  request_limit -= 1
133
- break if request_limit < 0
133
+ break if request_limit.negative?
134
134
  end
135
135
  break unless results.next?
136
136
  results = results.next
@@ -45,11 +45,13 @@ module Google
45
45
  #
46
46
  class Partition
47
47
  # @ private
48
- attr_reader :execute, :read
48
+ attr_reader :execute
49
+ attr_reader :read
49
50
 
50
51
  ##
51
52
  # @private Creates a Partition object.
52
- def initialize; end
53
+ def initialize
54
+ end
53
55
 
54
56
  ##
55
57
  # Whether the partition was created for an execute_query/query
@@ -70,7 +70,8 @@ module Google
70
70
  # end
71
71
  #
72
72
  class Policy
73
- attr_reader :etag, :roles
73
+ attr_reader :etag
74
+ attr_reader :roles
74
75
 
75
76
  ##
76
77
  # @private Creates a Policy object.
@@ -169,7 +170,7 @@ module Google
169
170
  role: role_name,
170
171
  members: roles[role_name]
171
172
  )
172
- end
173
+ end.compact
173
174
  )
174
175
  end
175
176