activerecord-spanner-adapter 1.0.1 → 1.2.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/.github/sync-repo-settings.yaml +2 -2
  4. data/.github/workflows/acceptance-tests-on-emulator.yaml +10 -6
  5. data/.github/workflows/acceptance-tests-on-production.yaml +1 -1
  6. data/.github/workflows/ci.yaml +10 -8
  7. data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +14 -5
  8. data/.github/workflows/nightly-acceptance-tests-on-production.yaml +2 -2
  9. data/.github/workflows/nightly-unit-tests.yaml +14 -5
  10. data/.github/workflows/release-please.yml +2 -2
  11. data/.github/workflows/rubocop.yaml +3 -3
  12. data/.kokoro/release.sh +1 -3
  13. data/.release-please-manifest.json +1 -1
  14. data/.toys/release.rb +8 -2
  15. data/CHANGELOG.md +18 -0
  16. data/Gemfile +5 -1
  17. data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb +12 -8
  18. data/acceptance/cases/models/insert_all_test.rb +150 -0
  19. data/acceptance/cases/transactions/optimistic_locking_test.rb +5 -0
  20. data/acceptance/cases/type/all_types_test.rb +10 -13
  21. data/acceptance/cases/type/json_test.rb +0 -2
  22. data/acceptance/models/album.rb +7 -2
  23. data/acceptance/models/singer.rb +2 -2
  24. data/acceptance/models/track.rb +5 -2
  25. data/acceptance/schema/schema.rb +2 -4
  26. data/acceptance/test_helper.rb +1 -1
  27. data/activerecord-spanner-adapter.gemspec +1 -1
  28. data/examples/snippets/interleaved-tables/README.md +164 -0
  29. data/examples/snippets/interleaved-tables/Rakefile +13 -0
  30. data/examples/snippets/interleaved-tables/application.rb +126 -0
  31. data/examples/snippets/interleaved-tables/config/database.yml +8 -0
  32. data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +44 -0
  33. data/examples/snippets/interleaved-tables/db/schema.rb +32 -0
  34. data/examples/snippets/interleaved-tables/db/seeds.rb +40 -0
  35. data/examples/snippets/interleaved-tables/models/album.rb +20 -0
  36. data/examples/snippets/interleaved-tables/models/singer.rb +18 -0
  37. data/examples/snippets/interleaved-tables/models/track.rb +28 -0
  38. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +10 -4
  39. data/lib/active_record/connection_adapters/spanner_adapter.rb +64 -31
  40. data/lib/activerecord_spanner_adapter/base.rb +150 -17
  41. data/lib/activerecord_spanner_adapter/connection.rb +1 -1
  42. data/lib/activerecord_spanner_adapter/relation.rb +21 -0
  43. data/lib/activerecord_spanner_adapter/transaction.rb +4 -4
  44. data/lib/activerecord_spanner_adapter/version.rb +1 -1
  45. data/lib/arel/visitors/spanner.rb +10 -0
  46. metadata +25 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcc2624f18893422bf8ac9c23d07fff039e79cee5f51b975054314f49820b694
4
- data.tar.gz: 7145b48f67236eb7ee9aac20bd1dfa907268419f262abf82cd6973acba25ab64
3
+ metadata.gz: 5f8199e1af804baf47d382e53404f88329478d35958f71fcaec34f73921de987
4
+ data.tar.gz: b2bc3919e5cc4d675d539806c27e0dda7b16d676ca349aa95a11370c4ec145b7
5
5
  SHA512:
6
- metadata.gz: 49aed5257b191aee1e9271c1d04e91c2ff1663c78e9b1e70e89acda430587324991a10cb1b2aabdfd9b1e9d70ab862b3a1579fda5c032023175303fa260deeed
7
- data.tar.gz: 1764369d2a370d4c8d35cbbcd3b9c45130514cc6e76bac67e5a9dafbf2bf020734b973be44f354b13da9acaaffdebaba78e31046da56c6e62efe0546aca30611
6
+ metadata.gz: 22ed1bd5840aa615681a7af2a4f87ceb31a5ec5a772d3260740ed520f99269b1ecdc0022aa1bcbf703afe01d99a04bb6181d546c5d6690bef20c17142281eb47
7
+ data.tar.gz: b9d65faf249175397de04b003a612ed10f89302ba545ffe09208b43414e9e8291feb9240aae3850f5f97d6f6b0bfd9c6134176316ebf6cc520d487e8d9700447
data/.github/CODEOWNERS CHANGED
@@ -4,4 +4,4 @@
4
4
  # For syntax help see:
5
5
  # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
6
6
 
7
- * @jiren @skuruppu @dazuma @hengfengli @olavloite @xiangshen-dk
7
+ * @googleapis/ruby-team @skuruppu @hengfengli @olavloite @xiangshen-dk
@@ -10,7 +10,7 @@ branchProtectionRules:
10
10
  requiresCodeOwnerReviews: true
11
11
  requiresStrictStatusChecks: true
12
12
  permissionRules:
13
- - team: yoshi-ruby
13
+ - team: ruby-team
14
14
  permission: push
15
- - team: yoshi-ruby-admins
15
+ - team: ruby-admins
16
16
  permission: admin
@@ -19,13 +19,19 @@ jobs:
19
19
  max-parallel: 4
20
20
  matrix:
21
21
  ruby: [2.6, 2.7, 3.0]
22
- ar: [6.0.4, 6.1.4]
23
- # Exclude Ruby 3.0 and ActiveRecord 6.0.x as that combination is not supported.
22
+ ar: [6.0.5.1, 6.1.6.1, 7.0.2.4, 7.0.3.1]
23
+ # Exclude combinations that are not supported.
24
24
  exclude:
25
25
  - ruby: 3.0
26
- ar: 6.0.4
26
+ ar: 6.0.5.1
27
+ - ruby: 2.6
28
+ ar: 7.0.2.4
29
+ - ruby: 2.6
30
+ ar: 7.0.3.1
31
+ env:
32
+ AR_VERSION: ${{ matrix.ar }}
27
33
  steps:
28
- - uses: actions/checkout@v2
34
+ - uses: actions/checkout@v3
29
35
  - name: Set up Ruby
30
36
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby
31
37
  # (see https://github.com/ruby/setup-ruby#versioning):
@@ -33,8 +39,6 @@ jobs:
33
39
  with:
34
40
  bundler-cache: false
35
41
  ruby-version: ${{ matrix.ruby }}
36
- - name: Set ActiveRecord version
37
- run: sed -i "s/\"activerecord\", \"~> 6.1.4\"/\"activerecord\", \"${{ matrix.ar }}\"/" activerecord-spanner-adapter.gemspec
38
42
  - name: Install dependencies
39
43
  run: bundle install
40
44
  - name: Run acceptance tests on emulator
@@ -26,7 +26,7 @@ jobs:
26
26
  matrix:
27
27
  ruby: [3.0]
28
28
  steps:
29
- - uses: actions/checkout@v2
29
+ - uses: actions/checkout@v3
30
30
  - name: Set up Ruby
31
31
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby
32
32
  # (see https://github.com/ruby/setup-ruby#versioning):
@@ -10,14 +10,18 @@ jobs:
10
10
  strategy:
11
11
  max-parallel: 4
12
12
  matrix:
13
- ruby: [2.6, 2.7, 3.0]
14
- ar: [6.0.4, 6.1.4]
15
- # Exclude Ruby 3.0 and ActiveRecord 6.0.x as that combination is not supported.
13
+ ruby: ["2.6", "2.7", "3.0"]
14
+ ar: ["6.0.4", "6.1.4", "7.0.2.4"]
15
+ # Exclude combinations that are not supported.
16
16
  exclude:
17
- - ruby: 3.0
18
- ar: 6.0.4
17
+ - ruby: "3.0"
18
+ ar: "6.0.4"
19
+ - ruby: "2.6"
20
+ ar: "7.0.2.4"
21
+ env:
22
+ AR_VERSION: ${{ matrix.ar }}
19
23
  steps:
20
- - uses: actions/checkout@v2
24
+ - uses: actions/checkout@v3
21
25
  - name: Set up Ruby
22
26
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby
23
27
  # (see https://github.com/ruby/setup-ruby#versioning):
@@ -25,8 +29,6 @@ jobs:
25
29
  with:
26
30
  bundler-cache: false
27
31
  ruby-version: ${{ matrix.ruby }}
28
- - name: Set ActiveRecord version
29
- run: sed -i "s/\"activerecord\", \"~> 6.1.4\"/\"activerecord\", \"${{ matrix.ar }}\"/" activerecord-spanner-adapter.gemspec
30
32
  - name: Install dependencies
31
33
  run: bundle install
32
34
  - name: Run tests
@@ -2,6 +2,7 @@ on:
2
2
  schedule:
3
3
  # 06:00 UTC
4
4
  - cron: '0 6 * * *'
5
+ workflow_dispatch:
5
6
  name: nightly acceptance tests on emulator
6
7
  jobs:
7
8
  test:
@@ -19,8 +20,8 @@ jobs:
19
20
  matrix:
20
21
  # Run acceptance tests all supported combinations of Ruby and ActiveRecord.
21
22
  ruby: [2.5, 2.6, 2.7, 3.0]
22
- ar: [6.0.0, 6.0.1, 6.0.2.2, 6.0.3.7, 6.0.4, 6.1.0, 6.1.1, 6.1.2.1, 6.1.3.2, 6.1.4]
23
- # Exclude Ruby 3.0 and ActiveRecord 6.0.x as that combination is not supported.
23
+ ar: [6.0.0, 6.0.1, 6.0.2.2, 6.0.3.7, 6.0.4, 6.1.3.2, 6.1.4.7, 6.1.5.1, 6.1.6.1, 7.0.2.4, 7.0.3.1]
24
+ # Exclude combinations that are not supported.
24
25
  exclude:
25
26
  - ruby: 3.0
26
27
  ar: 6.0.0
@@ -32,16 +33,24 @@ jobs:
32
33
  ar: 6.0.3.7
33
34
  - ruby: 3.0
34
35
  ar: 6.0.4
36
+ - ruby: 2.5
37
+ ar: 7.0.2.4
38
+ - ruby: 2.6
39
+ ar: 7.0.2.4
40
+ - ruby: 2.5
41
+ ar: 7.0.3.1
42
+ - ruby: 2.6
43
+ ar: 7.0.3.1
44
+ env:
45
+ AR_VERSION: ${{ matrix.ar }}
35
46
  steps:
36
- - uses: actions/checkout@v2
47
+ - uses: actions/checkout@v3
37
48
  - name: Set up Ruby
38
49
  uses: ruby/setup-ruby@v1
39
50
  with:
40
51
  # Disable caching as we are overriding the ActiveRecord below.
41
52
  bundler-cache: false
42
53
  ruby-version: ${{ matrix.ruby }}
43
- - name: Set ActiveRecord version
44
- run: sed -i "s/\"activerecord\", \"~> 6.1.4\"/\"activerecord\", \"${{ matrix.ar }}\"/" activerecord-spanner-adapter.gemspec
45
54
  - name: Install dependencies
46
55
  run: bundle install
47
56
  - name: Run acceptance tests on emulator
@@ -12,7 +12,7 @@ jobs:
12
12
  matrix:
13
13
  ruby: [3.0]
14
14
  steps:
15
- - uses: actions/checkout@v2
15
+ - uses: actions/checkout@v3
16
16
  - name: Set up Ruby
17
17
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby
18
18
  # (see https://github.com/ruby/setup-ruby#versioning):
@@ -21,7 +21,7 @@ jobs:
21
21
  bundler-cache: true
22
22
  ruby-version: ${{ matrix.ruby }}
23
23
  - name: Setup GCloud
24
- uses: google-github-actions/setup-gcloud@master
24
+ uses: google-github-actions/setup-gcloud@v0
25
25
  with:
26
26
  project_id: ${{ secrets.GCP_PROJECT_ID }}
27
27
  service_account_key: ${{ secrets.GCP_SA_KEY }}
@@ -2,6 +2,7 @@ on:
2
2
  schedule:
3
3
  # 05:30 UTC
4
4
  - cron: '30 5 * * *'
5
+ workflow_dispatch:
5
6
  name: nightly-unit-tests
6
7
  jobs:
7
8
  test:
@@ -11,8 +12,8 @@ jobs:
11
12
  matrix:
12
13
  # Run unit tests all supported combinations of Ruby and ActiveRecord.
13
14
  ruby: [2.5, 2.6, 2.7, 3.0]
14
- ar: [6.0.0, 6.0.1, 6.0.2.2, 6.0.3.7, 6.0.4, 6.1.0, 6.1.1, 6.1.2.1, 6.1.3.2, 6.1.4]
15
- # Exclude Ruby 3.0 and ActiveRecord 6.0.x as that combination is not supported.
15
+ ar: [6.0.0, 6.0.1, 6.0.2.2, 6.0.3.7, 6.0.4, 6.1.3.2, 6.1.4.7, 6.1.5.1, 6.1.6.1, 7.0.2.4, 7.0.3.1]
16
+ # Exclude combinations that are not supported.
16
17
  exclude:
17
18
  - ruby: 3.0
18
19
  ar: 6.0.0
@@ -24,16 +25,24 @@ jobs:
24
25
  ar: 6.0.3.7
25
26
  - ruby: 3.0
26
27
  ar: 6.0.4
28
+ - ruby: 2.5
29
+ ar: 7.0.2.4
30
+ - ruby: 2.6
31
+ ar: 7.0.2.4
32
+ - ruby: 2.5
33
+ ar: 7.0.3.1
34
+ - ruby: 2.6
35
+ ar: 7.0.3.1
36
+ env:
37
+ AR_VERSION: ${{ matrix.ar }}
27
38
  steps:
28
- - uses: actions/checkout@v2
39
+ - uses: actions/checkout@v3
29
40
  - name: Set up Ruby
30
41
  uses: ruby/setup-ruby@v1
31
42
  with:
32
43
  # Disable caching as we are overriding the ActiveRecord below.
33
44
  bundler-cache: false
34
45
  ruby-version: ${{ matrix.ruby }}
35
- - name: Set ActiveRecord version
36
- run: sed -i "s/\"activerecord\", \"~> 6.1.4\"/\"activerecord\", \"${{ matrix.ar }}\"/" activerecord-spanner-adapter.gemspec
37
46
  - name: Install dependencies
38
47
  run: bundle install
39
48
  - name: Run tests
@@ -20,13 +20,13 @@ jobs:
20
20
  RELEASE_PLEASE_DISABLE: ${{ secrets.RELEASE_PLEASE_DISABLE }}
21
21
  steps:
22
22
  - name: Checkout repo
23
- uses: actions/checkout@v2
23
+ uses: actions/checkout@v3
24
24
  - name: Install Ruby 3.0
25
25
  uses: ruby/setup-ruby@v1
26
26
  with:
27
27
  ruby-version: "3.0"
28
28
  - name: Install NodeJS 16.x
29
- uses: actions/setup-node@v2
29
+ uses: actions/setup-node@v3
30
30
  with:
31
31
  node-version: "16.x"
32
32
  - name: Install tools
@@ -12,13 +12,13 @@ jobs:
12
12
  timeout-minutes: 10
13
13
 
14
14
  steps:
15
- - uses: actions/checkout@v2
15
+ - uses: actions/checkout@v3
16
16
  - name: setup ruby
17
17
  uses: ruby/setup-ruby@v1
18
18
  with:
19
- ruby-version: '2.5'
19
+ ruby-version: '2.7'
20
20
  - name: cache gems
21
- uses: actions/cache@v2
21
+ uses: actions/cache@v3
22
22
  with:
23
23
  path: vendor/bundle
24
24
  key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
data/.kokoro/release.sh CHANGED
@@ -7,9 +7,7 @@ set -eo pipefail
7
7
  export GEM_HOME=$HOME/.gem
8
8
  export PATH=$GEM_HOME/bin:$PATH
9
9
 
10
- python3 -m pip install git+https://github.com/googleapis/releasetool
11
- python3 -m pip install gcp-docuploader
12
10
  gem install --no-document toys
13
-
11
+ toys release install-python-tools -v
14
12
  python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script
15
13
  toys release perform -v --enable-docs < /dev/null
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.0.1"
2
+ ".": "1.2.1"
3
3
  }
data/.toys/release.rb CHANGED
@@ -14,5 +14,11 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- load_git remote: "https://github.com/googleapis/ruby-common-tools.git",
18
- path: "toys/release"
17
+ if ENV["RUBY_COMMON_TOOLS"]
18
+ common_tools_dir = File.expand_path ENV["RUBY_COMMON_TOOLS"]
19
+ load File.join(common_tools_dir, "toys", "release")
20
+ else
21
+ load_git remote: "https://github.com/googleapis/ruby-common-tools.git",
22
+ path: "toys/release",
23
+ update: true
24
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ### 1.2.1 (2022-08-28)
4
+
5
+ #### Bug Fixes
6
+
7
+ * Corrected the namespace for the transaction selector class ([#187](https://github.com/googleapis/ruby-spanner-activerecord/issues/187))
8
+
9
+ ### 1.2.0 (2022-08-03)
10
+
11
+ #### Features
12
+
13
+ * support composite primary keys for interleaved tables ([#175](https://github.com/googleapis/ruby-spanner-activerecord/issues/175))
14
+
15
+ ### 1.1.0 (2022-06-24)
16
+
17
+ #### Features
18
+
19
+ * Support insert_all and upsert_all with DML and mutations
20
+
3
21
  ### 1.0.1 (2022-04-21)
4
22
 
5
23
  #### Bug Fixes
data/Gemfile CHANGED
@@ -3,10 +3,14 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in activerecord-spanner.gemspec
4
4
  gemspec
5
5
 
6
+ gem "activerecord", ENV.fetch("AR_VERSION", "~> 6.1.6.1")
6
7
  gem "minitest", "~> 5.15.0"
7
8
  gem "pry", "~> 0.13.0"
8
9
  gem "pry-byebug", "~> 3.9.0"
9
10
 
11
+ # Required for samples and testing.
12
+ gem "composite_primary_keys"
13
+
10
14
  # Required for samples
11
- gem 'docker-api'
15
+ gem "docker-api"
12
16
  gem "sinatra-activerecord"
@@ -20,6 +20,8 @@ module ActiveRecord
20
20
 
21
21
  def setup
22
22
  super
23
+ @original_verbosity = $VERBOSE
24
+ $VERBOSE = nil
23
25
 
24
26
  @singer = Singer.create first_name: "FirstName1", last_name: "LastName1"
25
27
 
@@ -35,6 +37,8 @@ module ActiveRecord
35
37
  def teardown
36
38
  Album.destroy_all
37
39
  Singer.destroy_all
40
+
41
+ $VERBOSE = @original_verbosity
38
42
  end
39
43
 
40
44
  def test_has_many
@@ -73,8 +77,8 @@ module ActiveRecord
73
77
 
74
78
  def test_create_and_destroy_associated_records
75
79
  singer2 = Singer.new first_name: "First", last_name: "Last"
76
- singer2.albums.build title: "New Title 1"
77
- singer2.albums.build title: "New Title 2"
80
+ singer2.albums.build title: "New Title 1", albumid: Album.next_sequence_value
81
+ singer2.albums.build title: "New Title 2", albumid: Album.next_sequence_value
78
82
  singer2.save!
79
83
 
80
84
  singer2.reload
@@ -91,8 +95,8 @@ module ActiveRecord
91
95
 
92
96
  def test_create_and_destroy_nested_associated_records
93
97
  album3 = Album.new singer: singer, title: "Title 3"
94
- album3.tracks.build title: "Title3_1", duration: 2.5, singer: singer
95
- album3.tracks.build title: "Title3_2", singer: singer
98
+ album3.tracks.build title: "Title3_1", duration: 2.5, singer: singer, trackid: Track.next_sequence_value
99
+ album3.tracks.build title: "Title3_2", singer: singer, trackid: Track.next_sequence_value
96
100
  album3.save!
97
101
 
98
102
  album3.reload
@@ -110,8 +114,8 @@ module ActiveRecord
110
114
 
111
115
  def test_create_and_delete_associated_records
112
116
  singer2 = Singer.new first_name: "First", last_name: "Last"
113
- singer2.albums.build title: "Album - 11"
114
- singer2.albums.build title: "Album - 12"
117
+ singer2.albums.build title: "Album - 11", albumid: Album.next_sequence_value
118
+ singer2.albums.build title: "Album - 12", albumid: Album.next_sequence_value
115
119
  singer2.save!
116
120
 
117
121
  singer2.reload
@@ -128,8 +132,8 @@ module ActiveRecord
128
132
 
129
133
  def test_create_and_delete_nested_associated_records
130
134
  album3 = Album.new title: "Album 3", singer: singer
131
- album3.tracks.build title: "Track - 31", singer: singer
132
- album3.tracks.build title: "Track - 32", singer: singer
135
+ album3.tracks.build title: "Track - 31", singer: singer, trackid: Track.next_sequence_value
136
+ album3.tracks.build title: "Track - 32", singer: singer, trackid: Track.next_sequence_value
133
137
  album3.save!
134
138
 
135
139
  album3.reload
@@ -0,0 +1,150 @@
1
+ # Copyright 2022 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
+ # frozen_string_literal: true
8
+
9
+ require "test_helper"
10
+ require "models/author"
11
+
12
+ module ActiveRecord
13
+ module Model
14
+ class InsertAllTest < SpannerAdapter::TestCase
15
+ include SpannerAdapter::Associations::TestHelper
16
+
17
+ def setup
18
+ super
19
+ end
20
+
21
+ def teardown
22
+ super
23
+ Author.destroy_all
24
+ end
25
+
26
+ def test_insert_all
27
+ values = [
28
+ { id: Author.next_sequence_value, name: "Alice" },
29
+ { id: Author.next_sequence_value, name: "Bob" },
30
+ { id: Author.next_sequence_value, name: "Carol" },
31
+ ]
32
+
33
+ assert_raise(NotImplementedError) { Author.insert_all(values) }
34
+ end
35
+
36
+ def test_insert_all!
37
+ values = [
38
+ { id: Author.next_sequence_value, name: "Alice" },
39
+ { id: Author.next_sequence_value, name: "Bob" },
40
+ { id: Author.next_sequence_value, name: "Carol" },
41
+ ]
42
+
43
+ Author.insert_all!(values)
44
+
45
+ authors = Author.all.order(:name)
46
+
47
+ assert_equal "Alice", authors[0].name
48
+ assert_equal "Bob", authors[1].name
49
+ assert_equal "Carol", authors[2].name
50
+ end
51
+
52
+ def test_insert_all_with_transaction
53
+ values = [
54
+ { id: Author.next_sequence_value, name: "Alice" },
55
+ { id: Author.next_sequence_value, name: "Bob" },
56
+ { id: Author.next_sequence_value, name: "Carol" },
57
+ ]
58
+
59
+ ActiveRecord::Base.transaction do
60
+ Author.insert_all!(values)
61
+ end
62
+
63
+ authors = Author.all.order(:name)
64
+
65
+ assert_equal "Alice", authors[0].name
66
+ assert_equal "Bob", authors[1].name
67
+ assert_equal "Carol", authors[2].name
68
+ end
69
+
70
+ def test_insert_all_with_buffered_mutation_transaction
71
+ values = [
72
+ { id: Author.next_sequence_value, name: "Alice" },
73
+ { id: Author.next_sequence_value, name: "Bob" },
74
+ { id: Author.next_sequence_value, name: "Carol" },
75
+ ]
76
+
77
+ ActiveRecord::Base.transaction isolation: :buffered_mutations do
78
+ Author.insert_all!(values)
79
+ end
80
+
81
+ authors = Author.all.order(:name)
82
+
83
+ assert_equal "Alice", authors[0].name
84
+ assert_equal "Bob", authors[1].name
85
+ assert_equal "Carol", authors[2].name
86
+ end
87
+
88
+ def test_upsert_all
89
+ Author.create id: 1, name: "David"
90
+ authors = Author.all.order(:name)
91
+ assert_equal 1, authors.length
92
+ assert_equal "David", authors[0].name
93
+
94
+ values = [
95
+ { id: 1, name: "Alice" },
96
+ { id: 2, name: "Bob" },
97
+ { id: 3, name: "Carol" },
98
+ ]
99
+
100
+ Author.upsert_all(values)
101
+
102
+ authors = Author.all.order(:name)
103
+
104
+ assert_equal 3, authors.length
105
+ assert_equal "Alice", authors[0].name
106
+ assert_equal "Bob", authors[1].name
107
+ assert_equal "Carol", authors[2].name
108
+ end
109
+
110
+ def test_upsert_all_with_transaction
111
+ values = [
112
+ { id: Author.next_sequence_value, name: "Alice" },
113
+ { id: Author.next_sequence_value, name: "Bob" },
114
+ { id: Author.next_sequence_value, name: "Carol" },
115
+ ]
116
+
117
+ err = assert_raise(NotImplementedError) do
118
+ ActiveRecord::Base.transaction do
119
+ Author.upsert_all(values)
120
+ end
121
+ end
122
+ assert_match "Use upsert outside a transaction block", err.message
123
+ end
124
+
125
+ def test_upsert_all_with_buffered_mutation_transaction
126
+ Author.create id: 1, name: "David"
127
+ authors = Author.all.order(:name)
128
+ assert_equal 1, authors.length
129
+ assert_equal "David", authors[0].name
130
+
131
+ values = [
132
+ { id: 1, name: "Alice" },
133
+ { id: 2, name: "Bob" },
134
+ { id: 3, name: "Carol" },
135
+ ]
136
+
137
+ ActiveRecord::Base.transaction isolation: :buffered_mutations do
138
+ Author.upsert_all(values)
139
+ end
140
+
141
+ authors = Author.all.order(:name)
142
+
143
+ assert_equal 3, authors.length
144
+ assert_equal "Alice", authors[0].name
145
+ assert_equal "Bob", authors[1].name
146
+ assert_equal "Carol", authors[2].name
147
+ end
148
+ end
149
+ end
150
+ end
@@ -19,6 +19,9 @@ module ActiveRecord
19
19
  def setup
20
20
  super
21
21
 
22
+ @original_verbosity = $VERBOSE
23
+ $VERBOSE = nil
24
+
22
25
  singer = Singer.create first_name: "Pete", last_name: "Allison"
23
26
  album = Album.create title: "Musical Jeans", singer: singer
24
27
  Track.create title: "Increased Headline", album: album, singer: singer
@@ -30,6 +33,8 @@ module ActiveRecord
30
33
  Track.delete_all
31
34
  Album.delete_all
32
35
  Singer.delete_all
36
+
37
+ $VERBOSE = @original_verbosity
33
38
  end
34
39
 
35
40
  # Runs the given block in a transaction with the given isolation level, or without a transaction if isolation is
@@ -30,7 +30,7 @@ module ActiveRecord
30
30
  AllTypes.create col_string: "string", col_int64: 100, col_float64: 3.14, col_numeric: 6.626, col_bool: true,
31
31
  col_bytes: StringIO.new("bytes"), col_date: ::Date.new(2021, 6, 23),
32
32
  col_timestamp: ::Time.new(2021, 6, 23, 17, 8, 21, "+02:00"),
33
- col_json: ENV["SPANNER_EMULATOR_HOST"] ? "" : { kind: "user_renamed", change: %w[jack john]},
33
+ col_json: { kind: "user_renamed", change: %w[jack john]},
34
34
  col_array_string: ["string1", nil, "string2"],
35
35
  col_array_int64: [100, nil, 200, "300"],
36
36
  col_array_float64: [3.14, nil, 2.0/3.0, "3.14"],
@@ -40,8 +40,7 @@ module ActiveRecord
40
40
  col_array_date: [::Date.new(2021, 6, 23), nil, ::Date.new(2021, 6, 24), "2021-06-25"],
41
41
  col_array_timestamp: [::Time.new(2021, 6, 23, 17, 8, 21, "+02:00"), nil, \
42
42
  ::Time.new(2021, 6, 24, 17, 8, 21, "+02:00"), "2021-06-25 17:08:21 +02:00"],
43
- col_array_json: ENV["SPANNER_EMULATOR_HOST"] ? [""] : \
44
- [{ kind: "user_renamed", change: %w[jack john]}, nil, \
43
+ col_array_json: [{ kind: "user_renamed", change: %w[jack john]}, nil, \
45
44
  { kind: "user_renamed", change: %w[alice meredith]},
46
45
  "{\"kind\":\"user_renamed\",\"change\":[\"bob\",\"carol\"]}"]
47
46
  end
@@ -67,7 +66,7 @@ module ActiveRecord
67
66
  assert_equal ::Date.new(2021, 6, 23), record.col_date
68
67
  assert_equal ::Time.new(2021, 6, 23, 17, 8, 21, "+02:00").utc, record.col_timestamp.utc
69
68
  assert_equal ({"kind" => "user_renamed", "change" => %w[jack john]}),
70
- record.col_json unless ENV["SPANNER_EMULATOR_HOST"]
69
+ record.col_json
71
70
 
72
71
  assert_equal ["string1", nil, "string2"], record.col_array_string
73
72
  assert_equal [100, nil, 200, 300], record.col_array_int64
@@ -83,9 +82,9 @@ module ActiveRecord
83
82
  record.col_array_timestamp.map { |timestamp| timestamp&.utc}
84
83
  assert_equal [{"kind" => "user_renamed", "change" => %w[jack john]}, \
85
84
  nil, \
86
- {"kind" => "user_renamed", "change" => %w[alice meredith]},
87
- {"kind" => "user_renamed", "change" => %w[bob carol]}],
88
- record.col_array_json unless ENV["SPANNER_EMULATOR_HOST"]
85
+ {"kind" => "user_renamed", "change" => %w[alice meredith]}, \
86
+ "{\"kind\":\"user_renamed\",\"change\":[\"bob\",\"carol\"]}"],
87
+ record.col_array_json
89
88
  end
90
89
  end
91
90
 
@@ -100,7 +99,7 @@ module ActiveRecord
100
99
  col_bool: false, col_bytes: StringIO.new("new bytes"),
101
100
  col_date: ::Date.new(2021, 6, 28),
102
101
  col_timestamp: ::Time.new(2021, 6, 28, 11, 22, 21, "+02:00"),
103
- col_json: ENV["SPANNER_EMULATOR_HOST"] ? "" : { kind: "user_created", change: %w[jack alice]},
102
+ col_json: { kind: "user_created", change: %w[jack alice]},
104
103
  col_array_string: ["new string 1", "new string 2"],
105
104
  col_array_int64: [300, 200, 100],
106
105
  col_array_float64: [1.1, 2.2, 3.3],
@@ -109,9 +108,7 @@ module ActiveRecord
109
108
  col_array_bytes: [StringIO.new("new bytes 1"), StringIO.new("new bytes 2")],
110
109
  col_array_date: [::Date.new(2021, 6, 28)],
111
110
  col_array_timestamp: [::Time.utc(2020, 12, 31, 0, 0, 0)],
112
- col_array_json: ENV["SPANNER_EMULATOR_HOST"] ?
113
- [""] : \
114
- [{ kind: "user_created", change: %w[jack alice]}]
111
+ col_array_json: [{ kind: "user_created", change: %w[jack alice]}]
115
112
  end
116
113
 
117
114
  # Verify that the record was updated.
@@ -125,7 +122,7 @@ module ActiveRecord
125
122
  assert_equal ::Date.new(2021, 6, 28), record.col_date
126
123
  assert_equal ::Time.new(2021, 6, 28, 11, 22, 21, "+02:00").utc, record.col_timestamp.utc
127
124
  assert_equal ({"kind" => "user_created", "change" => %w[jack alice]}),
128
- record.col_json unless ENV["SPANNER_EMULATOR_HOST"]
125
+ record.col_json
129
126
 
130
127
  assert_equal ["new string 1", "new string 2"], record.col_array_string
131
128
  assert_equal [300, 200, 100], record.col_array_int64
@@ -137,7 +134,7 @@ module ActiveRecord
137
134
  assert_equal [::Date.new(2021, 6, 28)], record.col_array_date
138
135
  assert_equal [::Time.utc(2020, 12, 31, 0, 0, 0)], record.col_array_timestamp.map(&:utc)
139
136
  assert_equal [{"kind" => "user_created", "change" => %w[jack alice]}],
140
- record.col_array_json unless ENV["SPANNER_EMULATOR_HOST"]
137
+ record.col_array_json
141
138
  end
142
139
  end
143
140
 
@@ -18,8 +18,6 @@ module ActiveRecord
18
18
  end
19
19
 
20
20
  def test_set_json
21
- return if ENV["SPANNER_EMULATOR_HOST"]
22
-
23
21
  expected_hash = {"key"=>"value", "array_key"=>%w[value1 value2]}
24
22
  record = TestTypeModel.new details: {key: "value", array_key: %w[value1 value2]}
25
23