activerecord-spanner-adapter 2.1.0 → 2.3.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 +4 -4
- data/.github/workflows/acceptance-tests-on-emulator.yaml +8 -2
- data/.github/workflows/ci.yaml +8 -2
- data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +7 -1
- data/.github/workflows/nightly-unit-tests.yaml +7 -1
- data/.github/workflows/samples.yaml +7 -1
- data/.kokoro/trampoline_v2.sh +0 -0
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +1 -1
- data/acceptance/cases/tasks/database_tasks_test.rb +1 -1
- data/acceptance/test_helper.rb +12 -0
- data/activerecord-spanner-adapter.gemspec +3 -4
- data/examples/snippets/isolation-level/README.md +39 -0
- data/examples/snippets/isolation-level/Rakefile +13 -0
- data/examples/snippets/isolation-level/application.rb +36 -0
- data/examples/snippets/isolation-level/config/database.yml +10 -0
- data/examples/snippets/isolation-level/db/migrate/01_create_tables.rb +22 -0
- data/examples/snippets/isolation-level/db/seeds.rb +25 -0
- data/examples/snippets/isolation-level/models/album.rb +9 -0
- data/examples/snippets/isolation-level/models/singer.rb +9 -0
- data/lib/active_record/connection_adapters/spanner/database_statements.rb +4 -2
- data/lib/active_record/connection_adapters/spanner_adapter.rb +6 -1
- data/lib/activerecord_spanner_adapter/base.rb +2 -2
- data/lib/activerecord_spanner_adapter/connection.rb +6 -1
- data/lib/activerecord_spanner_adapter/transaction.rb +12 -2
- data/lib/activerecord_spanner_adapter/version.rb +1 -1
- data/lib/arel/visitors/spanner.rb +11 -4
- metadata +20 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35016d190d27c935b9a004570e326d7cdc75af064f877bd619334ea967cf4d7a
|
4
|
+
data.tar.gz: 1cf91b818edc4d594fcf623f0a3218927406b47523931641fb6e844c88b578ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96dfb48e59b278093e118006e393e03b8981fd370605664830a73ad09873ead412a726a838407595fb903194e64f7b368dc940a443d774847679c316742eefc3
|
7
|
+
data.tar.gz: 5aa61e971ad3b21f9a9dee3476e7ce9fe5b52f080c2bd507e39cd2aa90719802d0ba5bcd024c3fa521feabc1e8756a249757dda5d3d432c67111ea3479d50e17
|
@@ -18,12 +18,18 @@ jobs:
|
|
18
18
|
strategy:
|
19
19
|
max-parallel: 4
|
20
20
|
matrix:
|
21
|
-
ruby: ["3.1", "3.2", "3.3"]
|
21
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
22
22
|
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
|
23
23
|
# Exclude combinations that are not supported.
|
24
24
|
exclude:
|
25
25
|
- ruby: "3.1"
|
26
26
|
ar: "~> 8.0.0"
|
27
|
+
- ruby: "3.4"
|
28
|
+
ar: "~> 7.0.0"
|
29
|
+
- ruby: "3.4"
|
30
|
+
ar: "~> 7.1.0"
|
31
|
+
- ruby: "3.4"
|
32
|
+
ar: "~> 7.2.0"
|
27
33
|
env:
|
28
34
|
AR_VERSION: ${{ matrix.ar }}
|
29
35
|
steps:
|
@@ -38,7 +44,7 @@ jobs:
|
|
38
44
|
- name: Install dependencies
|
39
45
|
run: bundle install
|
40
46
|
- name: Run acceptance tests on emulator
|
41
|
-
run: bundle exec rake acceptance
|
47
|
+
run: bundle exec rake acceptance TESTOPTS="-v"
|
42
48
|
env:
|
43
49
|
SPANNER_EMULATOR_HOST: localhost:9010
|
44
50
|
SPANNER_TEST_PROJECT: test-project
|
data/.github/workflows/ci.yaml
CHANGED
@@ -10,12 +10,18 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
max-parallel: 4
|
12
12
|
matrix:
|
13
|
-
ruby: ["3.1", "3.2", "3.3"]
|
13
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
14
14
|
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
|
15
15
|
# Exclude combinations that are not supported.
|
16
16
|
exclude:
|
17
17
|
- ruby: "3.1"
|
18
18
|
ar: "~> 8.0.0"
|
19
|
+
- ruby: "3.4"
|
20
|
+
ar: "~> 7.0.0"
|
21
|
+
- ruby: "3.4"
|
22
|
+
ar: "~> 7.1.0"
|
23
|
+
- ruby: "3.4"
|
24
|
+
ar: "~> 7.2.0"
|
19
25
|
env:
|
20
26
|
AR_VERSION: ${{ matrix.ar }}
|
21
27
|
steps:
|
@@ -30,4 +36,4 @@ jobs:
|
|
30
36
|
- name: Install dependencies
|
31
37
|
run: bundle install
|
32
38
|
- name: Run tests
|
33
|
-
run: bundle exec rake test
|
39
|
+
run: bundle exec rake test --trace TESTOPTS="-v"
|
@@ -18,12 +18,18 @@ jobs:
|
|
18
18
|
strategy:
|
19
19
|
max-parallel: 4
|
20
20
|
matrix:
|
21
|
-
ruby: ["3.1", "3.2", "3.3"]
|
21
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
22
22
|
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
|
23
23
|
# Exclude combinations that are not supported.
|
24
24
|
exclude:
|
25
25
|
- ruby: "3.1"
|
26
26
|
ar: "~> 8.0.0"
|
27
|
+
- ruby: "3.4"
|
28
|
+
ar: "~> 7.0.0"
|
29
|
+
- ruby: "3.4"
|
30
|
+
ar: "~> 7.1.0"
|
31
|
+
- ruby: "3.4"
|
32
|
+
ar: "~> 7.2.0"
|
27
33
|
env:
|
28
34
|
AR_VERSION: ${{ matrix.ar }}
|
29
35
|
steps:
|
@@ -11,12 +11,18 @@ jobs:
|
|
11
11
|
max-parallel: 4
|
12
12
|
matrix:
|
13
13
|
# Run acceptance tests all supported combinations of Ruby and ActiveRecord.
|
14
|
-
ruby: ["3.1", "3.2", "3.3"]
|
14
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
15
15
|
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
|
16
16
|
# Exclude combinations that are not supported.
|
17
17
|
exclude:
|
18
18
|
- ruby: "3.1"
|
19
19
|
ar: "~> 8.0.0"
|
20
|
+
- ruby: "3.4"
|
21
|
+
ar: "~> 7.0.0"
|
22
|
+
- ruby: "3.4"
|
23
|
+
ar: "~> 7.1.0"
|
24
|
+
- ruby: "3.4"
|
25
|
+
ar: "~> 7.2.0"
|
20
26
|
env:
|
21
27
|
AR_VERSION: ${{ matrix.ar }}
|
22
28
|
steps:
|
@@ -8,12 +8,18 @@ jobs:
|
|
8
8
|
strategy:
|
9
9
|
max-parallel: 4
|
10
10
|
matrix:
|
11
|
-
ruby: ["3.1", "3.2", "3.3"]
|
11
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
12
12
|
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
|
13
13
|
# Exclude combinations that are not supported.
|
14
14
|
exclude:
|
15
15
|
- ruby: "3.1"
|
16
16
|
ar: "~> 8.0.0"
|
17
|
+
- ruby: "3.4"
|
18
|
+
ar: "~> 7.0.0"
|
19
|
+
- ruby: "3.4"
|
20
|
+
ar: "~> 7.1.0"
|
21
|
+
- ruby: "3.4"
|
22
|
+
ar: "~> 7.2.0"
|
17
23
|
env:
|
18
24
|
AR_VERSION: ${{ matrix.ar }}
|
19
25
|
steps:
|
data/.kokoro/trampoline_v2.sh
CHANGED
File without changes
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 2.3.0 (2025-05-30)
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* Add optimizer hint syntax to set a priority in request options ([#363](https://github.com/googleapis/ruby-spanner-activerecord/issues/363))
|
8
|
+
* support ruby 3.4 ([#359](https://github.com/googleapis/ruby-spanner-activerecord/issues/359))
|
9
|
+
|
10
|
+
### 2.2.0 (2025-04-03)
|
11
|
+
|
12
|
+
#### Features
|
13
|
+
|
14
|
+
* transaction isolation level ([#355](https://github.com/googleapis/ruby-spanner-activerecord/issues/355))
|
15
|
+
|
3
16
|
### 2.1.0 (2025-03-17)
|
4
17
|
|
5
18
|
#### Features
|
data/Gemfile
CHANGED
@@ -65,9 +65,9 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def drop_database
|
68
|
+
spanner_instance.database(@database_id)&.drop
|
68
69
|
ActiveRecord::Base.connection_pool.disconnect!
|
69
70
|
ActiveRecordSpannerAdapter::Connection.reset_information_schemas!
|
70
|
-
spanner_instance.database(@database_id)&.drop
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_structure_dump_and_load
|
data/acceptance/test_helper.rb
CHANGED
@@ -188,6 +188,7 @@ module SpannerAdapter
|
|
188
188
|
unless @skip_test_table_create
|
189
189
|
connection.drop_table :test_models, if_exists: true
|
190
190
|
end
|
191
|
+
ActiveRecord::Base.connection_pool.disconnect!
|
191
192
|
|
192
193
|
super
|
193
194
|
end
|
@@ -273,8 +274,19 @@ module SpannerAdapter
|
|
273
274
|
ActiveSupport::Notifications.subscribe("sql.active_record", SQLCounter.new)
|
274
275
|
end
|
275
276
|
|
277
|
+
module Kernel
|
278
|
+
# Monkey-patch Kernel.exit to call exit! instead.
|
279
|
+
# This prevents the tests from getting stuck after running (probably) due to
|
280
|
+
# gRPC connections that have not been closed yet.
|
281
|
+
def exit status = true
|
282
|
+
exit! status
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
276
286
|
Minitest.after_run do
|
277
287
|
drop_test_database
|
288
|
+
ActiveRecord::Base.connection_pool.disconnect!
|
289
|
+
ActiveRecordSpannerAdapter::Connection.reset_information_schemas!
|
278
290
|
end
|
279
291
|
|
280
292
|
create_test_database
|
@@ -24,14 +24,13 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.required_ruby_version = ">= 3.1"
|
26
26
|
|
27
|
-
spec.add_dependency "google-cloud-spanner", "~> 2.
|
28
|
-
|
29
|
-
spec.add_dependency "grpc", "1.64.3"
|
27
|
+
spec.add_dependency "google-cloud-spanner", "~> 2.25"
|
28
|
+
spec.add_dependency "google-cloud-spanner-v1", "~> 1.7"
|
30
29
|
spec.add_runtime_dependency "activerecord", [">= 7.0", "< 9"]
|
31
30
|
|
32
31
|
spec.add_development_dependency "autotest-suffix", "~> 1.1"
|
33
32
|
spec.add_development_dependency "bundler", "~> 2.0"
|
34
|
-
spec.add_development_dependency "google-style", "~> 1.
|
33
|
+
spec.add_development_dependency "google-style", "~> 1.31.0"
|
35
34
|
spec.add_development_dependency "minitest", "~> 5.10"
|
36
35
|
spec.add_development_dependency "minitest-autotest", "~> 1.0"
|
37
36
|
spec.add_development_dependency "minitest-focus", "~> 1.1"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Sample - Isolation Level
|
2
|
+
|
3
|
+
This example shows how to use a specific isolation level for read/write transactions
|
4
|
+
using the Spanner ActiveRecord adapter.
|
5
|
+
|
6
|
+
You can specify the isolation level in two ways:
|
7
|
+
|
8
|
+
1. Set a default in the database configuration:
|
9
|
+
|
10
|
+
```yaml
|
11
|
+
development:
|
12
|
+
adapter: spanner
|
13
|
+
emulator_host: localhost:9010
|
14
|
+
project: test-project
|
15
|
+
instance: test-instance
|
16
|
+
database: testdb
|
17
|
+
isolation_level: :serializable,
|
18
|
+
pool: 5
|
19
|
+
timeout: 5000
|
20
|
+
schema_dump: false
|
21
|
+
```
|
22
|
+
|
23
|
+
2. Specify the isolation level for a specific transaction. This will override any
|
24
|
+
default that is set in the database configuration.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
ActiveRecord::Base.transaction isolation: :repeatable_read do
|
28
|
+
# Execute transaction code...
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
The sample will automatically start a Spanner Emulator in a Docker container and execute the sample
|
33
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
34
|
+
|
35
|
+
Run the application with the command
|
36
|
+
|
37
|
+
```bash
|
38
|
+
bundle exec rake run
|
39
|
+
```
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Copyright 2025 Google LLC
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
|
7
|
+
require_relative "../config/environment"
|
8
|
+
require "sinatra/activerecord/rake"
|
9
|
+
|
10
|
+
desc "Sample showing how to specify a transaction isolation level for Spanner with ActiveRecord."
|
11
|
+
task :run do
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[isolation-level]" }
|
13
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright 2025 Google LLC
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
|
7
|
+
require "io/console"
|
8
|
+
require_relative "../config/environment"
|
9
|
+
require_relative "models/singer"
|
10
|
+
require_relative "models/album"
|
11
|
+
|
12
|
+
class Application
|
13
|
+
def self.run # rubocop:disable Metrics/AbcSize
|
14
|
+
from_album = nil
|
15
|
+
to_album = nil
|
16
|
+
# Execute a read/write transaction using isolation level repeatable read.
|
17
|
+
puts "Executing a read/write transaction using isolation level repeatable read"
|
18
|
+
ActiveRecord::Base.transaction isolation: :repeatable_read do
|
19
|
+
# Transfer a marketing budget of 10,000 from one album to another.
|
20
|
+
from_album = Album.all.sample
|
21
|
+
to_album = Album.where.not(id: from_album.id).sample
|
22
|
+
|
23
|
+
puts ""
|
24
|
+
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) " \
|
25
|
+
"to #{to_album.title} (#{to_album.marketing_budget})"
|
26
|
+
from_album.update marketing_budget: from_album.marketing_budget - 10000
|
27
|
+
to_album.update marketing_budget: to_album.marketing_budget + 10000
|
28
|
+
end
|
29
|
+
puts ""
|
30
|
+
puts "Budgets after update:"
|
31
|
+
puts "Marketing budget #{from_album.title}: #{from_album.reload.marketing_budget}"
|
32
|
+
puts "Marketing budget #{to_album.title}: #{to_album.reload.marketing_budget}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Application.run
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2021 Google LLC
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
|
7
|
+
class CreateTables < ActiveRecord::Migration[6.0]
|
8
|
+
def change
|
9
|
+
connection.ddl_batch do
|
10
|
+
create_table :singers do |t|
|
11
|
+
t.string :first_name
|
12
|
+
t.string :last_name
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :albums do |t|
|
16
|
+
t.string :title
|
17
|
+
t.numeric :marketing_budget
|
18
|
+
t.references :singer, index: false, foreign_key: true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright 2021 Google LLC
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
|
7
|
+
require_relative "../../config/environment"
|
8
|
+
require_relative "../models/singer"
|
9
|
+
require_relative "../models/album"
|
10
|
+
|
11
|
+
first_names = ["Pete", "Alice", "John", "Ethel", "Trudy", "Naomi", "Wendy", "Ruben", "Thomas", "Elly"]
|
12
|
+
last_names = ["Wendelson", "Allison", "Peterson", "Johnson", "Henderson", "Ericsson", "Aronson", "Tennet", "Courtou"]
|
13
|
+
|
14
|
+
adjectives = ["daily", "happy", "blue", "generous", "cooked", "bad", "open"]
|
15
|
+
nouns = ["windows", "potatoes", "bank", "street", "tree", "glass", "bottle"]
|
16
|
+
budgets = [15000, 25000, 10000, 20000, 30000, 12000, 13000]
|
17
|
+
|
18
|
+
5.times do
|
19
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample
|
20
|
+
end
|
21
|
+
|
22
|
+
20.times do
|
23
|
+
singer_id = Singer.all.sample.id
|
24
|
+
Album.create title: "#{adjectives.sample} #{nouns.sample}", marketing_budget: budgets.sample, singer_id: singer_id
|
25
|
+
end
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def internal_execute sql, name = "SQL", binds = [],
|
32
|
-
prepare: false, async: false, allow_retry: false # rubocop:disable Lint/UnusedMethodArgument
|
32
|
+
prepare: false, async: false, allow_retry: false # rubocop:disable Lint/UnusedMethodArgument
|
33
33
|
statement_type = sql_statement_type sql
|
34
34
|
# Call `transform` to invoke any query transformers that might have been registered.
|
35
35
|
sql = transform sql
|
@@ -292,7 +292,7 @@ module ActiveRecord
|
|
292
292
|
if isolation.count != 1
|
293
293
|
else
|
294
294
|
raise "Unsupported isolation level: #{isolation}" unless
|
295
|
-
[:serializable, :read_only, :buffered_mutations, :pdml].include? isolation
|
295
|
+
[:serializable, :repeatable_read, :read_only, :buffered_mutations, :pdml].include? isolation
|
296
296
|
end
|
297
297
|
|
298
298
|
log "BEGIN #{isolation}" do
|
@@ -406,8 +406,10 @@ module ActiveRecord
|
|
406
406
|
end
|
407
407
|
|
408
408
|
DDL_REGX = build_sql_statement_regexp(:create, :alter, :drop).freeze
|
409
|
+
private_constant :DDL_REGX
|
409
410
|
|
410
411
|
DML_REGX = build_sql_statement_regexp(:insert, :delete, :update).freeze
|
412
|
+
private_constant :DML_REGX
|
411
413
|
|
412
414
|
def sql_statement_type sql
|
413
415
|
case sql
|
@@ -150,7 +150,8 @@ module ActiveRecord
|
|
150
150
|
end
|
151
151
|
|
152
152
|
# Spanner Connection API
|
153
|
-
delegate :ddl_batch, :ddl_batch?, :start_batch_ddl, :abort_batch, :run_batch,
|
153
|
+
delegate :ddl_batch, :ddl_batch?, :start_batch_ddl, :abort_batch, :run_batch,
|
154
|
+
:isolation_level, :isolation_level=, to: :@connection
|
154
155
|
|
155
156
|
def current_spanner_transaction
|
156
157
|
@connection.current_transaction
|
@@ -170,6 +171,10 @@ module ActiveRecord
|
|
170
171
|
false
|
171
172
|
end
|
172
173
|
|
174
|
+
def supports_transaction_isolation?
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
173
178
|
def supports_foreign_keys?
|
174
179
|
true
|
175
180
|
end
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
# Creates an object (or multiple objects) and saves it to the database. This method will use mutations instead
|
22
22
|
# of DML if there is no active transaction, or if the active transaction has been created with the option
|
23
23
|
# isolation: :buffered_mutations.
|
24
|
-
def self.create!
|
24
|
+
def self.create!(attributes = nil, &)
|
25
25
|
return super unless spanner_adapter?
|
26
26
|
return super if active_transaction?
|
27
27
|
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def self.create
|
33
|
+
def self.create(attributes = nil, &)
|
34
34
|
return super unless spanner_adapter?
|
35
35
|
return super if active_transaction?
|
36
36
|
|
@@ -14,10 +14,12 @@ module ActiveRecordSpannerAdapter
|
|
14
14
|
attr_reader :database_id
|
15
15
|
attr_reader :spanner
|
16
16
|
attr_accessor :current_transaction
|
17
|
+
attr_accessor :isolation_level
|
17
18
|
|
18
19
|
def initialize config
|
19
20
|
@instance_id = config[:instance]
|
20
21
|
@database_id = config[:database]
|
22
|
+
@isolation_level = config[:isolation_level]
|
21
23
|
@spanner = self.class.spanners config
|
22
24
|
end
|
23
25
|
|
@@ -42,6 +44,9 @@ module ActiveRecordSpannerAdapter
|
|
42
44
|
# Call this method if you drop and recreate a database with the same name
|
43
45
|
# to prevent the cached information to be used for the new database.
|
44
46
|
def self.reset_information_schemas!
|
47
|
+
@information_schemas.each_value do |info_schema|
|
48
|
+
info_schema.connection.disconnect!
|
49
|
+
end
|
45
50
|
@information_schemas = {}
|
46
51
|
end
|
47
52
|
|
@@ -271,7 +276,7 @@ module ActiveRecordSpannerAdapter
|
|
271
276
|
|
272
277
|
def begin_transaction isolation = nil
|
273
278
|
raise "Nested transactions are not allowed" if current_transaction&.active?
|
274
|
-
self.current_transaction = Transaction.new self, isolation
|
279
|
+
self.current_transaction = Transaction.new self, isolation || @isolation_level
|
275
280
|
current_transaction.begin
|
276
281
|
current_transaction
|
277
282
|
end
|
@@ -55,11 +55,12 @@ module ActiveRecordSpannerAdapter
|
|
55
55
|
when :pdml
|
56
56
|
@grpc_transaction = @connection.session.create_pdml
|
57
57
|
else
|
58
|
+
grpc_isolation = _transaction_isolation_level_to_grpc @isolation
|
58
59
|
@begin_transaction_selector = Google::Cloud::Spanner::V1::TransactionSelector.new \
|
59
60
|
begin: Google::Cloud::Spanner::V1::TransactionOptions.new(
|
60
|
-
read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new
|
61
|
+
read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new,
|
62
|
+
isolation_level: grpc_isolation
|
61
63
|
)
|
62
|
-
|
63
64
|
end
|
64
65
|
@state = :STARTED
|
65
66
|
rescue Google::Cloud::NotFoundError => e
|
@@ -75,6 +76,15 @@ module ActiveRecordSpannerAdapter
|
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
79
|
+
def _transaction_isolation_level_to_grpc isolation
|
80
|
+
case isolation
|
81
|
+
when :serializable
|
82
|
+
Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::SERIALIZABLE
|
83
|
+
when :repeatable_read
|
84
|
+
Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::REPEATABLE_READ
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
78
88
|
# Forces a BeginTransaction RPC for a read/write transaction. This is used by a
|
79
89
|
# connection if the first statement of a transaction failed.
|
80
90
|
def force_begin_read_write
|
@@ -91,10 +91,17 @@ module Arel # :nodoc: all
|
|
91
91
|
StalenessHint.new min_read_timestamp: time
|
92
92
|
next
|
93
93
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
if v.start_with? "read_timestamp:"
|
95
|
+
time = Time.xmlschema v.delete_prefix("read_timestamp:")
|
96
|
+
collector.hints[:staleness] =
|
97
|
+
StalenessHint.new read_timestamp: time
|
98
|
+
next
|
99
|
+
end
|
100
|
+
next unless v.start_with? "priority:"
|
101
|
+
priority = v.delete_prefix("priority:").strip.to_sym
|
102
|
+
collector.hints[:request_options] ||=
|
103
|
+
Google::Cloud::Spanner::V1::RequestOptions.new
|
104
|
+
collector.hints[:request_options].priority = priority
|
98
105
|
end
|
99
106
|
collector
|
100
107
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-spanner-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Google LLC
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: google-cloud-spanner
|
@@ -15,28 +15,28 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '2.
|
18
|
+
version: '2.25'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '2.
|
25
|
+
version: '2.25'
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
|
-
name:
|
27
|
+
name: google-cloud-spanner-v1
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.
|
32
|
+
version: '1.7'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- -
|
37
|
+
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 1.
|
39
|
+
version: '1.7'
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: activerecord
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,14 +91,14 @@ dependencies:
|
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: 1.
|
94
|
+
version: 1.31.0
|
95
95
|
type: :development
|
96
96
|
prerelease: false
|
97
97
|
version_requirements: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
99
|
- - "~>"
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 1.
|
101
|
+
version: 1.31.0
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: minitest
|
104
104
|
requirement: !ruby/object:Gem::Requirement
|
@@ -439,6 +439,14 @@ files:
|
|
439
439
|
- examples/snippets/interleaved-tables/models/album.rb
|
440
440
|
- examples/snippets/interleaved-tables/models/singer.rb
|
441
441
|
- examples/snippets/interleaved-tables/models/track.rb
|
442
|
+
- examples/snippets/isolation-level/README.md
|
443
|
+
- examples/snippets/isolation-level/Rakefile
|
444
|
+
- examples/snippets/isolation-level/application.rb
|
445
|
+
- examples/snippets/isolation-level/config/database.yml
|
446
|
+
- examples/snippets/isolation-level/db/migrate/01_create_tables.rb
|
447
|
+
- examples/snippets/isolation-level/db/seeds.rb
|
448
|
+
- examples/snippets/isolation-level/models/album.rb
|
449
|
+
- examples/snippets/isolation-level/models/singer.rb
|
442
450
|
- examples/snippets/migrations/README.md
|
443
451
|
- examples/snippets/migrations/Rakefile
|
444
452
|
- examples/snippets/migrations/application.rb
|
@@ -579,7 +587,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
579
587
|
- !ruby/object:Gem::Version
|
580
588
|
version: '0'
|
581
589
|
requirements: []
|
582
|
-
rubygems_version: 3.6.
|
590
|
+
rubygems_version: 3.6.9
|
583
591
|
specification_version: 4
|
584
592
|
summary: Rails ActiveRecord connector for Google Spanner Database
|
585
593
|
test_files: []
|