google-cloud-spanner 2.25.0 → 2.27.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bc284cfdecb9d6261e1a545a6b7868205e21346a27f48e4d86a8051533b1746
4
- data.tar.gz: f4cdc9f44e8723639ab0f8c07aedb4c6e3e6c989db95b8175a24a0ae232c0902
3
+ metadata.gz: 2950745d1ef3cf6be982e2bc64a29ce467e8a15710293265181d41dd138a80ad
4
+ data.tar.gz: 6e96c531e76300e6d77d5d261ec0d09da96157f82aa3f4c32c502b52ce6b6f74
5
5
  SHA512:
6
- metadata.gz: 5f379e7460d19707ed13e73d6caebf00224d1fb97ba26bcba9efd72c00a300a7a81ac510688138143c35437ab5d75057c775a4e8445fe72e7462c66be141c0b3
7
- data.tar.gz: 0d0fe1dbfd3f7bb47502b06f1854ac87233dc86bcd291f1732d4d6a6ba762483adac6883d9c8f534296811772dcb7930b2b4d8d6f39a59dcc27e8049a59ca380
6
+ metadata.gz: 55291fac48fb628c64d4df17266cf1a07babbd918b8411e7116e8ba23b0430c20dbf0f210098f27052bbcd9d97c9e3ed0ec2937a4c342cb5994946df2dcf2ac6
7
+ data.tar.gz: b2e91d7c79a316a69b3657eace1232936a13013236117170b974a9487e0d9fdd5c9de34bba851ffbe310a26c6864954fd94de68df91fdb1a9d64bd06773d5aff
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Release History
2
2
 
3
+ ### 2.27.0 (2025-05-28)
4
+
5
+ #### Features
6
+
7
+ * Spanner Interval type ([#162](https://github.com/googleapis/ruby-spanner/issues/162))
8
+ * Updated required Ruby version to 3.1 ([#160](https://github.com/googleapis/ruby-spanner/issues/160))
9
+
10
+ ### 2.26.0 (2025-03-24)
11
+
12
+ #### Features
13
+
14
+ * Support setting the universe domain ([#144](https://github.com/googleapis/ruby-spanner/issues/144))
15
+ #### Bug Fixes
16
+
17
+ * Corrected algorithm that releases stale sessions in the pool ([#156](https://github.com/googleapis/ruby-spanner/issues/156))
18
+
3
19
  ### 2.25.0 (2025-01-29)
4
20
 
5
21
  #### Features
@@ -85,6 +85,7 @@ module Google
85
85
  #
86
86
  def self.database_admin project_id: nil,
87
87
  credentials: nil,
88
+ universe_domain: nil,
88
89
  scope: nil,
89
90
  timeout: nil,
90
91
  endpoint: nil,
@@ -93,14 +94,23 @@ module Google
93
94
  emulator_host: nil,
94
95
  lib_name: nil,
95
96
  lib_version: nil
96
- project_id ||= project || default_project_id
97
- scope ||= configure.scope
98
- timeout ||= configure.timeout
97
+ project_id ||= project || default_project_id
98
+ scope ||= configure.scope
99
+ timeout ||= configure.timeout
99
100
  emulator_host ||= configure.emulator_host
100
- endpoint ||= emulator_host || configure.endpoint
101
- credentials ||= keyfile
102
- lib_name ||= configure.lib_name
103
- lib_version ||= configure.lib_version
101
+ # TODO: This logic is part of UniverseDomainConcerns in gapic-common
102
+ # but is being copied here because we need to determine the host up
103
+ # front in order to build a gRPC channel. We should refactor this
104
+ # somehow to allow this logic to live where it is supposed to.
105
+ universe_domain ||= configure.universe_domain || ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com"
106
+ endpoint ||= emulator_host || configure.endpoint
107
+ endpoint ||=
108
+ Google::Cloud::Spanner::Admin::Database::V1::DatabaseAdmin::Client::DEFAULT_ENDPOINT_TEMPLATE.sub(
109
+ Gapic::UniverseDomainConcerns::ENDPOINT_SUBSTITUTION, universe_domain
110
+ )
111
+ credentials ||= keyfile
112
+ lib_name ||= configure.lib_name
113
+ lib_version ||= configure.lib_version
104
114
 
105
115
  if emulator_host
106
116
  credentials = :this_channel_is_insecure
@@ -121,10 +131,11 @@ module Google
121
131
  configure.quota_project ||= credentials.quota_project_id if credentials.respond_to? :quota_project_id
122
132
 
123
133
  Admin::Database::V1::DatabaseAdmin::Client.new do |config|
134
+ config.universe_domain = universe_domain
124
135
  config.credentials = channel endpoint, credentials
125
136
  config.quota_project = configure.quota_project
126
137
  config.timeout = timeout if timeout
127
- config.endpoint = endpoint if endpoint
138
+ config.endpoint = endpoint
128
139
  config.lib_name = lib_name_with_prefix lib_name, lib_version
129
140
  config.lib_version = Google::Cloud::Spanner::VERSION
130
141
  config.metadata = { "google-cloud-resource-prefix" => "projects/#{project_id}" }
@@ -290,7 +301,7 @@ module Google
290
301
  class Configuration
291
302
  extend ::Gapic::Config
292
303
 
293
- config_attr :endpoint, "spanner.googleapis.com", ::String
304
+ config_attr :endpoint, nil, ::String
294
305
  config_attr :credentials, nil do |value|
295
306
  allowed = [::String, ::Hash, ::Google::Auth::Credentials, ::Signet::OAuth2::Client, nil]
296
307
  allowed += [::GRPC::Core::Channel, ::GRPC::Core::ChannelCredentials] if defined? ::GRPC
@@ -307,6 +318,7 @@ module Google
307
318
  config_attr :query_options, nil, ::Hash, nil
308
319
  config_attr :metadata, nil, ::Hash, nil
309
320
  config_attr :retry_policy, nil, ::Hash, nil
321
+ config_attr :universe_domain, nil, ::String, nil
310
322
 
311
323
  # @private
312
324
  def initialize parent_config = nil
@@ -85,6 +85,7 @@ module Google
85
85
  #
86
86
  def self.instance_admin project_id: nil,
87
87
  credentials: nil,
88
+ universe_domain: nil,
88
89
  scope: nil,
89
90
  timeout: nil,
90
91
  endpoint: nil,
@@ -93,14 +94,23 @@ module Google
93
94
  emulator_host: nil,
94
95
  lib_name: nil,
95
96
  lib_version: nil
96
- project_id ||= project || default_project_id
97
- scope ||= configure.scope
98
- timeout ||= configure.timeout
97
+ project_id ||= project || default_project_id
98
+ scope ||= configure.scope
99
+ timeout ||= configure.timeout
99
100
  emulator_host ||= configure.emulator_host
100
- endpoint ||= emulator_host || configure.endpoint
101
- credentials ||= keyfile
102
- lib_name ||= configure.lib_name
103
- lib_version ||= configure.lib_version
101
+ # TODO: This logic is part of UniverseDomainConcerns in gapic-common
102
+ # but is being copied here because we need to determine the host up
103
+ # front in order to build a gRPC channel. We should refactor this
104
+ # somehow to allow this logic to live where it is supposed to.
105
+ universe_domain ||= configure.universe_domain || ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com"
106
+ endpoint ||= emulator_host || configure.endpoint
107
+ endpoint ||=
108
+ Google::Cloud::Spanner::Admin::Instance::V1::InstanceAdmin::Client::DEFAULT_ENDPOINT_TEMPLATE.sub(
109
+ Gapic::UniverseDomainConcerns::ENDPOINT_SUBSTITUTION, universe_domain
110
+ )
111
+ credentials ||= keyfile
112
+ lib_name ||= configure.lib_name
113
+ lib_version ||= configure.lib_version
104
114
 
105
115
  if emulator_host
106
116
  credentials = :this_channel_is_insecure
@@ -121,10 +131,11 @@ module Google
121
131
  configure.quota_project ||= credentials.quota_project_id if credentials.respond_to? :quota_project_id
122
132
 
123
133
  Admin::Instance::V1::InstanceAdmin::Client.new do |config|
134
+ config.universe_domain = universe_domain
124
135
  config.credentials = channel endpoint, credentials
125
136
  config.quota_project = configure.quota_project
126
137
  config.timeout = timeout if timeout
127
- config.endpoint = endpoint if endpoint
138
+ config.endpoint = endpoint
128
139
  config.lib_name = lib_name_with_prefix lib_name, lib_version
129
140
  config.lib_version = Google::Cloud::Spanner::VERSION
130
141
  config.metadata = { "google-cloud-resource-prefix" => "projects/#{project_id}" }
@@ -290,7 +301,7 @@ module Google
290
301
  class Configuration
291
302
  extend ::Gapic::Config
292
303
 
293
- config_attr :endpoint, "spanner.googleapis.com", ::String
304
+ config_attr :endpoint, nil, ::String
294
305
  config_attr :credentials, nil do |value|
295
306
  allowed = [::String, ::Hash, ::Google::Auth::Credentials, ::Signet::OAuth2::Client, nil]
296
307
  allowed += [::GRPC::Core::Channel, ::GRPC::Core::ChannelCredentials] if defined? ::GRPC
@@ -307,6 +318,7 @@ module Google
307
318
  config_attr :query_options, nil, ::Hash, nil
308
319
  config_attr :metadata, nil, ::Hash, nil
309
320
  config_attr :retry_policy, nil, ::Hash, nil
321
+ config_attr :universe_domain, nil, ::String, nil
310
322
 
311
323
  # @private
312
324
  def initialize parent_config = nil
@@ -92,9 +92,9 @@ module Google
92
92
  #
93
93
  # @yield [::Google::Cloud::Spanner::BatchWriteResults::BatchResult]
94
94
  #
95
- def each &block
95
+ def each(&)
96
96
  if defined? @results
97
- @results.each(&block)
97
+ @results.each(&)
98
98
  else
99
99
  results = []
100
100
  @enumerable.each do |grpc|
@@ -19,6 +19,7 @@ require "stringio"
19
19
  require "base64"
20
20
  require "bigdecimal"
21
21
  require "google/cloud/spanner/data"
22
+ require "google/cloud/spanner/interval"
22
23
 
23
24
  module Google
24
25
  module Cloud
@@ -108,6 +109,8 @@ module Google
108
109
  else
109
110
  Google::Protobuf::Value.new string_value: obj.to_json
110
111
  end
112
+ when Interval
113
+ obj.to_s
111
114
  when Google::Protobuf::MessageExts
112
115
  proto_class = obj.class
113
116
  content = proto_class.encode obj
@@ -252,6 +255,8 @@ module Google
252
255
  BigDecimal value.string_value
253
256
  when :JSON
254
257
  JSON.parse value.string_value
258
+ when :INTERVAL
259
+ Interval.parse value.string_value
255
260
  when :PROTO
256
261
  descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(type.proto_type_fqn).msgclass
257
262
  content = Base64.decode64 value.string_value
@@ -0,0 +1,309 @@
1
+ # Copyright 2017 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
+ module Google
16
+ module Cloud
17
+ module Spanner
18
+ ##
19
+ # # Interval
20
+ #
21
+ # Represents an interval of time by storing the time components
22
+ # in months, days and nanoseconds.
23
+ #
24
+ # @example
25
+ # require "google/cloud/spanner"
26
+ #
27
+ # iso_8601_string = "P1Y2M3DT4H5M6S"
28
+ # interval = Google::Cloud::Spanner::Interval::parse iso_8601_string
29
+ #
30
+ # puts interval # "P1Y2M3DT4H5M6S"
31
+ class Interval
32
+ NANOSECONDS_IN_A_SECOND = 1_000_000_000
33
+ NANOSECONDS_IN_A_MINUTE = NANOSECONDS_IN_A_SECOND * 60
34
+ NANOSECONDS_IN_AN_HOUR = NANOSECONDS_IN_A_MINUTE * 60
35
+ NANOSECONDS_IN_A_MILLISECOND = 1_000_000
36
+ NANOSECONDS_IN_A_MICROSECOND = 1_000
37
+ MAX_MONTHS = 120_000
38
+ MIN_MONTHS = -MAX_MONTHS
39
+ MAX_DAYS = 3_660_000
40
+ MIN_DAYS = -MAX_DAYS
41
+ MAX_NANOSECONDS = 316_224_000_000_000_000_000
42
+ MIN_NANOSECONDS = -316_224_000_000_000_000_000
43
+
44
+ private_constant :NANOSECONDS_IN_A_SECOND, :NANOSECONDS_IN_A_MINUTE, :NANOSECONDS_IN_AN_HOUR,
45
+ :NANOSECONDS_IN_A_MILLISECOND, :NANOSECONDS_IN_A_MICROSECOND, :MAX_MONTHS,
46
+ :MIN_MONTHS, :MAX_DAYS, :MIN_DAYS, :MAX_NANOSECONDS, :MIN_NANOSECONDS
47
+
48
+ class << self
49
+ # rubocop:disable Metrics/AbcSize
50
+ # rubocop:disable Metrics/MethodLength
51
+
52
+ # Parses an ISO8601 string and returns an Interval instance.
53
+ #
54
+ # The accepted format for the ISO8601 standard is:
55
+ # `P[n]Y[n]M[n]DT[n]H[n]M[n[.fraction]]S`
56
+ # where `n` represents an integer number.
57
+ #
58
+ # @param interval_string [String] An ISO8601 formatted string.
59
+ # @return [Google::Cloud::Spanner::Interval]
60
+ #
61
+ # @example
62
+ # require "google/cloud/spanner"
63
+ #
64
+ # iso_8601_string = "P1Y2M3DT4H5M6S"
65
+ # interval = Google::Cloud::Spanner::Interval::parse iso_8601_string
66
+ #
67
+ # puts interval # "P1Y2M3DT4H5M6S"
68
+ #
69
+ def parse interval_string
70
+ pattern = /^
71
+ P(?!$)
72
+ (?:(?<years>-?\d+)Y)?
73
+ (?:(?<months>-?\d+)M)?
74
+ (?:(?<days>-?\d+)D)?
75
+ (?:T(?!$)
76
+ (?:(?<hours>-?\d+)H)?
77
+ (?:(?<minutes>-?\d+)M)?
78
+ (?:(?<seconds>-?(?!S)\d*(?:[\.,]\d{1,9})?)S)?)?
79
+ $
80
+ /x
81
+ interval_months = 0
82
+ interval_days = 0
83
+ interval_nanoseconds = 0
84
+
85
+ matches = interval_string.match pattern
86
+
87
+ raise ArgumentError, "The provided string does not follow ISO8601 standard." if matches.nil?
88
+
89
+ raise ArgumentError, "The provided string does not follow ISO8601 standard." if matches.captures.empty?
90
+
91
+ interval_months += matches[:years].to_i * 12 if matches[:years]
92
+
93
+ interval_months += matches[:months].to_i if matches[:months]
94
+
95
+ interval_days = matches[:days].to_i if matches[:days]
96
+
97
+ interval_nanoseconds += matches[:hours].to_i * NANOSECONDS_IN_AN_HOUR if matches[:hours]
98
+
99
+ interval_nanoseconds += matches[:minutes].to_i * NANOSECONDS_IN_A_MINUTE if matches[:minutes]
100
+
101
+ # Only seconds can be fractional. Both period and comma are valid inputs.
102
+ if matches[:seconds]
103
+ interval_nanoseconds += (matches[:seconds].gsub(",", ".").to_f * NANOSECONDS_IN_A_SECOND).to_i
104
+ end
105
+
106
+ Interval.new interval_months, interval_days, interval_nanoseconds
107
+ end
108
+
109
+ # rubocop:enable Metrics/AbcSize
110
+ # rubocop:enable Metrics/MethodLength
111
+
112
+ # Returns an Interval instance with the given months.
113
+ #
114
+ # @param months [Integer]
115
+ # @return [Interval]
116
+ def from_months months
117
+ Interval.new months, 0, 0
118
+ end
119
+
120
+ # Returns an Interval instance with the given days.
121
+ #
122
+ # @param days [Integer]
123
+ # @return [Interval]
124
+ def from_days days
125
+ Interval.new 0, days, 0
126
+ end
127
+
128
+ # Returns an Interval instance with the given seconds.
129
+ #
130
+ # @param seconds [Integer]
131
+ # @return [Interval]
132
+ def from_seconds seconds
133
+ nanoseconds = seconds * NANOSECONDS_IN_A_SECOND
134
+ Interval.new 0, 0, nanoseconds
135
+ end
136
+
137
+ # Returns an Interval instance with the given milliseconds.
138
+ #
139
+ # @param milliseconds [Integer]
140
+ # @return [Interval]
141
+ def from_milliseconds milliseconds
142
+ nanoseconds = milliseconds * NANOSECONDS_IN_A_MILLISECOND
143
+ Interval.new 0, 0, nanoseconds
144
+ end
145
+
146
+ # Returns an Interval instance with the given microseconds.
147
+ #
148
+ # @param microseconds [Integer]
149
+ # @return [Interval]
150
+ def from_microseconds microseconds
151
+ nanoseconds = microseconds * NANOSECONDS_IN_A_MICROSECOND
152
+ Interval.new 0, 0, nanoseconds
153
+ end
154
+
155
+ # Returns an Interval instance with the given nanoseconds.
156
+ #
157
+ # @param nanoseconds [Integer]
158
+ # @return [Interval]
159
+ def from_nanoseconds nanoseconds
160
+ Interval.new 0, 0, nanoseconds
161
+ end
162
+ end
163
+
164
+
165
+ # Converts the [Interval] to an ISO8601 Standard string.
166
+ # @return [String] The interval's ISO8601 string representation.
167
+ def to_s
168
+ # Memoizing it as the logic can be a bit heavy.
169
+ @to_s ||= to_string
170
+ end
171
+
172
+ ##
173
+ # @private Creates a new Google::Cloud::Spanner instance.
174
+ def initialize months, days, nanoseconds
175
+ if months > MAX_MONTHS || months < MIN_MONTHS
176
+ raise ArgumentError, "The Interval class supports months from #{MIN_MONTHS} to #{MAX_MONTHS}."
177
+ end
178
+ @months = months
179
+
180
+ if days > MAX_DAYS || days < MIN_DAYS
181
+ raise ArgumentError, "The Interval class supports days from #{MIN_DAYS} to #{MAX_DAYS}."
182
+ end
183
+ @days = days
184
+
185
+ if nanoseconds > MAX_NANOSECONDS || nanoseconds < MIN_NANOSECONDS
186
+ raise ArgumentError, "The Interval class supports nanoseconds from #{MIN_NANOSECONDS} to #{MAX_NANOSECONDS}"
187
+ end
188
+ @nanoseconds = nanoseconds
189
+ end
190
+
191
+
192
+ # @return [Integer] The numbers of months in the time interval.
193
+ attr_reader :months
194
+
195
+ # @return [Integer] The numbers of days in the time interval.
196
+ attr_reader :days
197
+
198
+ # @return [Integer] The numbers of nanoseconds in the time interval.
199
+ attr_reader :nanoseconds
200
+
201
+
202
+ ##
203
+ # Standard value equality check for this object.
204
+ #
205
+ # @param [Object] other An object to compare with.
206
+ # @return [Boolean]
207
+ def eql? other
208
+ other.is_a?(Interval) &&
209
+ months == other.months &&
210
+ days == other.days &&
211
+ nanoseconds == other.nanoseconds
212
+ end
213
+ alias == eql?
214
+
215
+ ##
216
+ # Generate standard hash code for this object.
217
+ #
218
+ # @return [Integer]
219
+ #
220
+ def hash
221
+ @hash ||= [@months, @days, @nanoseconds].hash
222
+ end
223
+
224
+ private
225
+
226
+ def match_sign value
227
+ value.negative? ? -1 : 1
228
+ end
229
+
230
+ # rubocop:disable Metrics/AbcSize
231
+ # rubocop:disable Metrics/CyclomaticComplexity
232
+ # rubocop:disable Metrics/PerceivedComplexity
233
+
234
+ # Converts [Interval] to an ISO8601 Standard string.
235
+ # @return [String] The interval's ISO8601 string representation.
236
+ def to_string
237
+ # Months should be converted to years and months.
238
+ years = @months.fdiv(12).truncate
239
+ months = @months % (match_sign(@months) * 12)
240
+
241
+ days = @days
242
+
243
+ # Nanoseconds should be converted to hours, minutes and seconds components.
244
+ remaining_nanoseconds = @nanoseconds
245
+
246
+ hours = (remaining_nanoseconds.abs / NANOSECONDS_IN_AN_HOUR) * match_sign(remaining_nanoseconds)
247
+ remaining_nanoseconds %= (match_sign(remaining_nanoseconds) * NANOSECONDS_IN_AN_HOUR)
248
+ minutes = (remaining_nanoseconds.abs / NANOSECONDS_IN_A_MINUTE) * match_sign(remaining_nanoseconds)
249
+ remaining_nanoseconds %= (match_sign(remaining_nanoseconds) * NANOSECONDS_IN_A_MINUTE)
250
+
251
+ # Only seconds can be fractional, and can have a maximum of 9 characters after decimal. Therefore,
252
+ # we convert the remaining nanoseconds to an integer for formatting.
253
+ seconds = (remaining_nanoseconds.abs / NANOSECONDS_IN_A_SECOND) * match_sign(remaining_nanoseconds)
254
+ nanoseconds = remaining_nanoseconds % (match_sign(remaining_nanoseconds) * NANOSECONDS_IN_A_SECOND)
255
+
256
+ interval_string = ["P"]
257
+
258
+ interval_string.append "#{years}Y" if years.nonzero?
259
+
260
+ interval_string.append "#{months}M" if months.nonzero?
261
+
262
+ interval_string.append "#{days}D" if days.nonzero?
263
+
264
+ if hours.nonzero? || minutes.nonzero? || seconds.nonzero? || nanoseconds.nonzero?
265
+ interval_string.append "T"
266
+
267
+ interval_string.append "#{hours}H" if hours.nonzero?
268
+
269
+ interval_string.append "#{minutes}M" if minutes.nonzero?
270
+
271
+ if seconds.nonzero? || nanoseconds.nonzero?
272
+ interval_string.append "#{format_seconds seconds, nanoseconds}S"
273
+ end
274
+ end
275
+
276
+ return "P0Y" if interval_string == ["P"]
277
+
278
+ interval_string.join
279
+ end
280
+
281
+ # rubocop:enable Metrics/AbcSize
282
+ # rubocop:enable Metrics/CyclomaticComplexity
283
+ # rubocop:enable Metrics/PerceivedComplexity
284
+
285
+ # Formats decimal values to be in multiples of 3 length.
286
+ # @return [String]
287
+ def format_seconds seconds, nanoseconds
288
+ return seconds if nanoseconds.zero?
289
+ add_sign = seconds.zero? && nanoseconds.negative?
290
+
291
+ nanoseconds_str = nanoseconds.abs.to_s.rjust 9, "0"
292
+ nanoseconds_str = nanoseconds_str.gsub(/0+$/, "")
293
+
294
+ target_length =
295
+ if nanoseconds_str.length <= 3
296
+ 3
297
+ elsif nanoseconds_str.length <= 6
298
+ 6
299
+ else
300
+ 9
301
+ end
302
+
303
+ nanoseconds_str = (nanoseconds_str + ("0" * target_length))[0...target_length]
304
+ "#{add_sign ? '-' : ''}#{seconds}.#{nanoseconds_str}"
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
@@ -136,10 +136,10 @@ module Google
136
136
 
137
137
  @mutex.synchronize do
138
138
  available_count = sessions_available.count
139
- release_count = @min - available_count
139
+ release_count = available_count - @min
140
140
  release_count = 0 if release_count.negative?
141
141
 
142
- to_keepalive += sessions_available.select do |x|
142
+ to_keepalive = sessions_available.select do |x|
143
143
  x.idle_since? @keepalive
144
144
  end
145
145
 
@@ -221,8 +221,8 @@ module Google
221
221
  @keepalive_task.execute
222
222
  end
223
223
 
224
- def future &block
225
- Concurrent::Future.new(executor: @thread_pool, &block).execute
224
+ def future(&)
225
+ Concurrent::Future.new(executor: @thread_pool, &).execute
226
226
  end
227
227
  end
228
228
  end
@@ -95,6 +95,15 @@ module Google
95
95
  end
96
96
  alias project project_id
97
97
 
98
+ ##
99
+ # The universe domain the client is connected to
100
+ #
101
+ # @return [String]
102
+ #
103
+ def universe_domain
104
+ service.universe_domain
105
+ end
106
+
98
107
  ##
99
108
  # Retrieves the list of Cloud Spanner instances for the project.
100
109
  #
@@ -38,6 +38,8 @@ module Google
38
38
  attr_accessor :quota_project
39
39
  attr_accessor :enable_leader_aware_routing
40
40
 
41
+ attr_reader :universe_domain
42
+
41
43
  RST_STREAM_INTERNAL_ERROR = "Received RST_STREAM".freeze
42
44
  EOS_INTERNAL_ERROR = "Received unexpected EOS on DATA frame from server".freeze
43
45
 
@@ -45,11 +47,19 @@ module Google
45
47
  # Creates a new Service instance.
46
48
  def initialize project, credentials, quota_project: nil,
47
49
  host: nil, timeout: nil, lib_name: nil, lib_version: nil,
48
- enable_leader_aware_routing: nil
50
+ enable_leader_aware_routing: nil, universe_domain: nil
49
51
  @project = project
50
52
  @credentials = credentials
51
53
  @quota_project = quota_project || (credentials.quota_project_id if credentials.respond_to? :quota_project_id)
52
- @host = host
54
+ # TODO: This logic is part of UniverseDomainConcerns in gapic-common
55
+ # but is being copied here because we need to determine the host up
56
+ # front in order to build a gRPC channel. We should refactor this
57
+ # somehow to allow this logic to live where it is supposed to.
58
+ @universe_domain = universe_domain || ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com"
59
+ @host = host ||
60
+ Google::Cloud::Spanner::V1::Spanner::Client::DEFAULT_ENDPOINT_TEMPLATE.sub(
61
+ Gapic::UniverseDomainConcerns::ENDPOINT_SUBSTITUTION, @universe_domain
62
+ )
53
63
  @timeout = timeout
54
64
  @lib_name = lib_name
55
65
  @lib_version = lib_version
@@ -80,6 +90,7 @@ module Google
80
90
  config.quota_project = @quota_project
81
91
  config.timeout = timeout if timeout
82
92
  config.endpoint = host if host
93
+ config.universe_domain = @universe_domain
83
94
  config.lib_name = lib_name_with_prefix
84
95
  config.lib_version = Google::Cloud::Spanner::VERSION
85
96
  config.metadata = { "google-cloud-resource-prefix" => "projects/#{@project}" }
@@ -95,6 +106,7 @@ module Google
95
106
  config.quota_project = @quota_project
96
107
  config.timeout = timeout if timeout
97
108
  config.endpoint = host if host
109
+ config.universe_domain = @universe_domain
98
110
  config.lib_name = lib_name_with_prefix
99
111
  config.lib_version = Google::Cloud::Spanner::VERSION
100
112
  config.metadata = { "google-cloud-resource-prefix" => "projects/#{@project}" }
@@ -110,6 +122,7 @@ module Google
110
122
  config.quota_project = @quota_project
111
123
  config.timeout = timeout if timeout
112
124
  config.endpoint = host if host
125
+ config.universe_domain = @universe_domain
113
126
  config.lib_name = lib_name_with_prefix
114
127
  config.lib_version = Google::Cloud::Spanner::VERSION
115
128
  config.metadata = { "google-cloud-resource-prefix" => "projects/#{@project}" }
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Spanner
19
- VERSION = "2.25.0".freeze
19
+ VERSION = "2.27.0".freeze
20
20
  end
21
21
  end
22
22
  end
@@ -84,6 +84,7 @@ module Google
84
84
  # with version.
85
85
  # @param enable_leader_aware_routing [Boolean] Specifies whether Leader
86
86
  # Aware Routing should be enabled. Defaults to true.
87
+ # @param universe_domain [String] A custom universe domain. Optional.
87
88
  #
88
89
  # @return [Google::Cloud::Spanner::Project]
89
90
  #
@@ -95,7 +96,7 @@ module Google
95
96
  def self.new project_id: nil, credentials: nil, scope: nil, timeout: nil,
96
97
  endpoint: nil, project: nil, keyfile: nil,
97
98
  emulator_host: nil, lib_name: nil, lib_version: nil,
98
- enable_leader_aware_routing: true
99
+ enable_leader_aware_routing: true, universe_domain: nil
99
100
  project_id ||= project || default_project_id
100
101
  scope ||= configure.scope
101
102
  timeout ||= configure.timeout
@@ -104,6 +105,7 @@ module Google
104
105
  credentials ||= keyfile
105
106
  lib_name ||= configure.lib_name
106
107
  lib_version ||= configure.lib_version
108
+ universe_domain ||= configure.universe_domain
107
109
 
108
110
  if emulator_host
109
111
  credentials = :this_channel_is_insecure
@@ -125,7 +127,7 @@ module Google
125
127
  Spanner::Service.new(
126
128
  project_id, credentials, quota_project: configure.quota_project,
127
129
  host: endpoint, timeout: timeout, lib_name: lib_name,
128
- lib_version: lib_version,
130
+ lib_version: lib_version, universe_domain: universe_domain,
129
131
  enable_leader_aware_routing: enable_leader_aware_routing
130
132
  ),
131
133
  query_options: configure.query_options
@@ -139,10 +139,8 @@ module Google
139
139
  end
140
140
  end
141
141
 
142
- # rubocop:disable Metrics/BlockLength
143
-
144
142
  # Set the default spanner configuration
145
- Google::Cloud.configure.add_config! :spanner do |config|
143
+ Google::Cloud.configure.add_config! :spanner do |config| # rubocop:disable Metrics/BlockLength
146
144
  default_project = Google::Cloud::Config.deferred do
147
145
  ENV["SPANNER_PROJECT"]
148
146
  end
@@ -181,11 +179,10 @@ Google::Cloud.configure.add_config! :spanner do |config|
181
179
  config.add_field! :scope, default_scopes, match: [String, Array]
182
180
  config.add_field! :quota_project, nil, match: String
183
181
  config.add_field! :timeout, nil, match: Integer
184
- config.add_field! :endpoint, "spanner.googleapis.com", match: String
182
+ config.add_field! :endpoint, nil, match: String
185
183
  config.add_field! :emulator_host, default_emulator, match: String, allow_nil: true
186
184
  config.add_field! :lib_name, nil, match: String, allow_nil: true
187
185
  config.add_field! :lib_version, nil, match: String, allow_nil: true
188
186
  config.add_field! :query_options, default_query_options, match: Hash, allow_nil: true
187
+ config.add_field! :universe_domain, nil, match: String, allow_nil: true
189
188
  end
190
-
191
- # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-spanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.25.0
4
+ version: 2.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
8
8
  - Chris Smith
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-29 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -150,6 +150,7 @@ files:
150
150
  - lib/google/cloud/spanner/instance/config/list.rb
151
151
  - lib/google/cloud/spanner/instance/job.rb
152
152
  - lib/google/cloud/spanner/instance/list.rb
153
+ - lib/google/cloud/spanner/interval.rb
153
154
  - lib/google/cloud/spanner/lar_headers.rb
154
155
  - lib/google/cloud/spanner/mutation_group.rb
155
156
  - lib/google/cloud/spanner/partition.rb
@@ -175,14 +176,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
176
  requirements:
176
177
  - - ">="
177
178
  - !ruby/object:Gem::Version
178
- version: '3.0'
179
+ version: '3.1'
179
180
  required_rubygems_version: !ruby/object:Gem::Requirement
180
181
  requirements:
181
182
  - - ">="
182
183
  - !ruby/object:Gem::Version
183
184
  version: '0'
184
185
  requirements: []
185
- rubygems_version: 3.6.2
186
+ rubygems_version: 3.6.9
186
187
  specification_version: 4
187
188
  summary: API Client library for Google Cloud Spanner API
188
189
  test_files: []