activerecord-spanner-adapter 1.5.1 → 1.6.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/acceptance-tests-on-emulator.yaml +1 -1
  3. data/.github/workflows/acceptance-tests-on-production.yaml +5 -3
  4. data/.github/workflows/ci.yaml +1 -1
  5. data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +1 -1
  6. data/.github/workflows/nightly-acceptance-tests-on-production.yaml +5 -3
  7. data/.github/workflows/nightly-unit-tests.yaml +1 -1
  8. data/.github/workflows/release-please-label.yml +1 -1
  9. data/.release-please-manifest.json +1 -1
  10. data/CHANGELOG.md +8 -0
  11. data/Gemfile +5 -2
  12. data/README.md +10 -10
  13. data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb +6 -0
  14. data/acceptance/cases/migration/change_schema_test.rb +19 -3
  15. data/acceptance/cases/migration/schema_dumper_test.rb +10 -1
  16. data/acceptance/cases/models/interleave_test.rb +6 -0
  17. data/acceptance/cases/tasks/database_tasks_test.rb +340 -2
  18. data/acceptance/cases/transactions/optimistic_locking_test.rb +6 -0
  19. data/acceptance/cases/transactions/read_write_transactions_test.rb +24 -0
  20. data/acceptance/models/table_with_sequence.rb +10 -0
  21. data/acceptance/schema/schema.rb +65 -19
  22. data/acceptance/test_helper.rb +1 -1
  23. data/activerecord-spanner-adapter.gemspec +1 -1
  24. data/examples/snippets/bit-reversed-sequence/README.md +103 -0
  25. data/examples/snippets/bit-reversed-sequence/Rakefile +13 -0
  26. data/examples/snippets/bit-reversed-sequence/application.rb +68 -0
  27. data/examples/snippets/bit-reversed-sequence/config/database.yml +8 -0
  28. data/examples/snippets/bit-reversed-sequence/db/migrate/01_create_tables.rb +33 -0
  29. data/examples/snippets/bit-reversed-sequence/db/schema.rb +31 -0
  30. data/examples/snippets/bit-reversed-sequence/db/seeds.rb +31 -0
  31. data/examples/snippets/bit-reversed-sequence/models/album.rb +11 -0
  32. data/examples/snippets/bit-reversed-sequence/models/singer.rb +15 -0
  33. data/examples/snippets/interleaved-tables/README.md +44 -53
  34. data/examples/snippets/interleaved-tables/Rakefile +2 -2
  35. data/examples/snippets/interleaved-tables/application.rb +2 -2
  36. data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +12 -18
  37. data/examples/snippets/interleaved-tables/db/schema.rb +9 -7
  38. data/examples/snippets/interleaved-tables/db/seeds.rb +1 -1
  39. data/examples/snippets/interleaved-tables/models/album.rb +3 -7
  40. data/examples/snippets/interleaved-tables/models/singer.rb +1 -1
  41. data/examples/snippets/interleaved-tables/models/track.rb +6 -7
  42. data/examples/snippets/interleaved-tables-before-7.1/README.md +167 -0
  43. data/examples/snippets/interleaved-tables-before-7.1/Rakefile +13 -0
  44. data/examples/snippets/interleaved-tables-before-7.1/application.rb +126 -0
  45. data/examples/snippets/interleaved-tables-before-7.1/config/database.yml +8 -0
  46. data/examples/snippets/interleaved-tables-before-7.1/db/migrate/01_create_tables.rb +44 -0
  47. data/examples/snippets/interleaved-tables-before-7.1/db/schema.rb +37 -0
  48. data/examples/snippets/interleaved-tables-before-7.1/db/seeds.rb +40 -0
  49. data/examples/snippets/interleaved-tables-before-7.1/models/album.rb +20 -0
  50. data/examples/snippets/interleaved-tables-before-7.1/models/singer.rb +18 -0
  51. data/examples/snippets/interleaved-tables-before-7.1/models/track.rb +28 -0
  52. data/examples/snippets/query-logs/README.md +43 -0
  53. data/examples/snippets/query-logs/Rakefile +13 -0
  54. data/examples/snippets/query-logs/application.rb +63 -0
  55. data/examples/snippets/query-logs/config/database.yml +8 -0
  56. data/examples/snippets/query-logs/db/migrate/01_create_tables.rb +21 -0
  57. data/examples/snippets/query-logs/db/schema.rb +31 -0
  58. data/examples/snippets/query-logs/db/seeds.rb +24 -0
  59. data/examples/snippets/query-logs/models/album.rb +9 -0
  60. data/examples/snippets/query-logs/models/singer.rb +9 -0
  61. data/lib/active_record/connection_adapters/spanner/column.rb +13 -0
  62. data/lib/active_record/connection_adapters/spanner/database_statements.rb +144 -35
  63. data/lib/active_record/connection_adapters/spanner/schema_cache.rb +3 -21
  64. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +11 -0
  65. data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +4 -0
  66. data/lib/active_record/connection_adapters/spanner/schema_statements.rb +3 -2
  67. data/lib/active_record/connection_adapters/spanner_adapter.rb +28 -9
  68. data/lib/activerecord_spanner_adapter/base.rb +56 -19
  69. data/lib/activerecord_spanner_adapter/information_schema.rb +33 -24
  70. data/lib/activerecord_spanner_adapter/primary_key.rb +1 -1
  71. data/lib/activerecord_spanner_adapter/table/column.rb +4 -9
  72. data/lib/activerecord_spanner_adapter/version.rb +1 -1
  73. data/lib/arel/visitors/spanner.rb +3 -1
  74. metadata +33 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73df0f7ee319edb7461b0fa60f8f8b611b38d798de2c0caf20a9c7d6796a7a85
4
- data.tar.gz: 9dedd540069c5bc85d458008c20e48b9b550a75388a1f4d48b1b29b34bb689d4
3
+ metadata.gz: 2ad2384bb1890bb224c89a146c42f615f89c6e2892848da5e701a091d90fa95b
4
+ data.tar.gz: 0e8a9c608068ff30011bc9bca68b10ab0d22b910260a37a6d4a492365adf78b0
5
5
  SHA512:
6
- metadata.gz: faac93588f6e703f183a773caf553d61b64370439093ac27a7d1a4893f6d887c887fbf1be9082baf78bb81e2c23b24f45a1e4053672e386595ff95c0980a0c4b
7
- data.tar.gz: 4d6061c3daf7760d3015a33b52a41354f6bafa21b594a0c2b44852ae928935e1b2e23421ce417de2e65eecdc56de0890d97d0321e07fd3a3c3c104cf56856c88
6
+ metadata.gz: 1894765bbc1e3dfac270d73199a4f235ae95724ca18145d6850cce27c38ef2018b59e9035cf2fa91bc30d3f650e080b8eea58c3e91a66035db3a4d07c35ca1be
7
+ data.tar.gz: 4a9b93d7990fa78f901864bed816e75ff5d0f9da34a530c7107f475d8fd06dc71817fbf8b2c1e0262e4656bf7ab363917ecf7b7c82315b6d5fa84cce0d22489d
@@ -19,7 +19,7 @@ jobs:
19
19
  max-parallel: 4
20
20
  matrix:
21
21
  ruby: ["2.7", "3.0", "3.1", "3.2"]
22
- ar: ["~> 6.0.6", "~> 6.1.7", "~> 7.0.4"]
22
+ ar: ["~> 6.0.6", "~> 6.1.7", "~> 7.0.4", "~> 7.1.0"]
23
23
  # Exclude combinations that are not supported.
24
24
  exclude:
25
25
  - ruby: "3.0"
@@ -34,12 +34,14 @@ jobs:
34
34
  with:
35
35
  bundler-cache: true
36
36
  ruby-version: ${{ matrix.ruby }}
37
+ - name: Authenticate Google Cloud
38
+ uses: google-github-actions/auth@v2
39
+ with:
40
+ credentials_json: ${{ secrets.GCP_SA_KEY }}
37
41
  - name: Setup GCloud
38
- uses: google-github-actions/setup-gcloud@v0
42
+ uses: google-github-actions/setup-gcloud@v2
39
43
  with:
40
44
  project_id: ${{ secrets.GCP_PROJECT_ID }}
41
- service_account_key: ${{ secrets.GCP_SA_KEY }}
42
- export_default_credentials: true
43
45
  - name: Install dependencies
44
46
  run: bundle install
45
47
  - name: Run acceptance tests on production
@@ -11,7 +11,7 @@ jobs:
11
11
  max-parallel: 4
12
12
  matrix:
13
13
  ruby: ["2.7", "3.0", "3.1", "3.2"]
14
- ar: ["~> 6.0.6", "~> 6.1.7", "~> 7.0.4"]
14
+ ar: ["~> 6.0.6", "~> 6.1.7", "~> 7.0.4", "~> 7.1.0"]
15
15
  # Exclude combinations that are not supported.
16
16
  exclude:
17
17
  - ruby: "3.0"
@@ -20,7 +20,7 @@ jobs:
20
20
  matrix:
21
21
  # Run acceptance tests all supported combinations of Ruby and ActiveRecord.
22
22
  ruby: [2.7, 3.0, 3.1, 3.2]
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, 7.0.4, 7.0.5, 7.0.6, 7.0.7]
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, 7.0.4, 7.0.5, 7.0.6, 7.0.7, 7.1.0, 7.1.1, 7.1.2]
24
24
  # Exclude combinations that are not supported.
25
25
  exclude:
26
26
  - ruby: 3.0
@@ -20,12 +20,14 @@ jobs:
20
20
  with:
21
21
  bundler-cache: true
22
22
  ruby-version: ${{ matrix.ruby }}
23
+ - name: Authenticate Google Cloud
24
+ uses: google-github-actions/auth@v2
25
+ with:
26
+ credentials_json: ${{ secrets.GCP_SA_KEY }}
23
27
  - name: Setup GCloud
24
- uses: google-github-actions/setup-gcloud@v0
28
+ uses: google-github-actions/setup-gcloud@v2
25
29
  with:
26
30
  project_id: ${{ secrets.GCP_PROJECT_ID }}
27
- service_account_key: ${{ secrets.GCP_SA_KEY }}
28
- export_default_credentials: true
29
31
  - name: Install dependencies
30
32
  run: bundle install
31
33
  - name: Run acceptance tests on production
@@ -12,7 +12,7 @@ jobs:
12
12
  matrix:
13
13
  # Run unit tests all supported combinations of Ruby and ActiveRecord.
14
14
  ruby: [2.7, 3.0, 3.1, 3.2]
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, 7.0.4, 7.0.5]
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, 7.0.4, 7.0.5, 7.1.0, 7.1.1, 7.1.2]
16
16
  # Exclude combinations that are not supported.
17
17
  exclude:
18
18
  - ruby: 3.0
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - name: ReleaseLabel
14
- uses: actions/github-script@v6
14
+ uses: actions/github-script@v7
15
15
  with:
16
16
  github-token: ${{secrets.YOSHI_APPROVER_TOKEN}}
17
17
  script: |
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.5.1"
2
+ ".": "1.6.0"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ### 1.6.0 (2023-12-20)
4
+
5
+ #### Features
6
+
7
+ * interleaved tables with built-in composite pk ([#282](https://github.com/googleapis/ruby-spanner-activerecord/issues/282))
8
+ * support Query Logs ([#291](https://github.com/googleapis/ruby-spanner-activerecord/issues/291))
9
+ * support Rails 7.1 ([#278](https://github.com/googleapis/ruby-spanner-activerecord/issues/278))
10
+
3
11
  ### 1.5.1 (2023-12-12)
4
12
 
5
13
  #### Bug Fixes
data/Gemfile CHANGED
@@ -4,12 +4,15 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem "activerecord", ENV.fetch("AR_VERSION", "~> 6.1.6.1")
7
- gem "minitest", "~> 5.19.0"
7
+ gem "minitest", "~> 5.20.0"
8
+ gem "minitest-rg", "~> 5.3.0"
8
9
  gem "pry", "~> 0.13.0"
9
10
  gem "pry-byebug", "~> 3.9.0"
10
11
 
11
12
  # Required for samples and testing.
12
- gem "composite_primary_keys"
13
+ install_if -> { ENV.fetch("AR_VERSION", "~> 6.1.6.1").dup.to_s.sub!("~>", "").strip < "7.1.0" && !ENV["SKIP_COMPOSITE_PK"] } do
14
+ gem "composite_primary_keys"
15
+ end
13
16
 
14
17
  # Required for samples
15
18
  gem "docker-api"
data/README.md CHANGED
@@ -84,19 +84,19 @@ Some noteworthy examples in the snippets directory:
84
84
  for inserting, updating and deleting data in a Cloud Spanner database. Mutations can have a significant performance
85
85
  advantage compared to DML statements, but do not allow read-your-writes semantics during a transaction.
86
86
  - [array-data-type](examples/snippets/array-data-type): Shows how to work with `ARRAY` data types.
87
- - [interleaved-tables](examples/snippets/interleaved-tables): Shows how to work with [Interleaved Tables](https://cloud.google.com/spanner/docs/schema-and-data-model#create-interleaved-tables).
87
+ - [interleaved-tables](examples/snippets/interleaved-tables-before-7.1): Shows how to work with [Interleaved Tables](https://cloud.google.com/spanner/docs/schema-and-data-model#create-interleaved-tables).
88
88
 
89
89
  ## Limitations
90
90
 
91
- Limitation|Comment|Resolution
92
- ---|---|---
93
- Interleaved tables require composite primary keys| Cloud Spanner requires composite primary keys for interleaved tables. See {file:examples/snippets/interleaved-tables/README.md this example} for an example on how to use interleaved tables with ActiveRecord |Use composite primary keys.
94
- Lack of sequential and auto-assigned IDs|Cloud Spanner doesn't autogenerate IDs and this integration instead creates UUID4 to avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key) so you SHOULD NOT rely on IDs being sorted| UUID4s are automatically generated for primary keys.
95
- Table without Primary Key| Cloud Spanner support does not support tables without a primary key.| Always define a primary key for your table.
96
- Table names CANNOT have spaces within them whether back-ticked or not|Cloud Spanner DOES NOT support tables with spaces in them for example `Entity ID`|Ensure that your table names don't contain spaces.
97
- Table names CANNOT have punctuation marks and MUST contain valid UTF-8|Cloud Spanner DOES NOT support punctuation marks e.g. periods ".", question marks "?" in table names|Ensure that your table names don't contain punctuation marks.
98
- Index with fields length [add_index](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index)|Cloud Spanner does not support index with fields length | Ensure that your database definition does not include index definitions with field lengths.
99
- Only GoogleSQL-dialect databases| Cloud Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases. | Ensure that your database uses the GoogleSQL dialect.
91
+ | Limitation | Comment | Resolution |
92
+ |-----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
93
+ | Interleaved tables require composite primary keys | Cloud Spanner requires composite primary keys for interleaved tables. See {file:examples/snippets/interleaved-tables/README.md this example} for an example on how to use interleaved tables with ActiveRecord | Use composite primary keys. |
94
+ | Lack of sequential IDs | Cloud Spanner uses either using bit-reversed sequences or UUID4 to generated primary keys to avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key) so you SHOULD NOT rely on IDs being sorted | Use either UUID4s or bit-reversed sequences to automatically generate primary keys. |
95
+ | Table without Primary Key | Cloud Spanner support does not support tables without a primary key. | Always define a primary key for your table. |
96
+ | Table names CANNOT have spaces within them whether back-ticked or not | Cloud Spanner DOES NOT support tables with spaces in them for example `Entity ID` | Ensure that your table names don't contain spaces. |
97
+ | Table names CANNOT have punctuation marks and MUST contain valid UTF-8 | Cloud Spanner DOES NOT support punctuation marks e.g. periods ".", question marks "?" in table names | Ensure that your table names don't contain punctuation marks. |
98
+ | Index with fields length [add_index](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index) | Cloud Spanner does not support index with fields length | Ensure that your database definition does not include index definitions with field lengths. |
99
+ | Only GoogleSQL-dialect databases | Cloud Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases. | Ensure that your database uses the GoogleSQL dialect. |
100
100
 
101
101
  ## Contributing
102
102
 
@@ -6,6 +6,12 @@
6
6
 
7
7
  # frozen_string_literal: true
8
8
 
9
+ # ActiveRecord 7.1 introduced native support for composite primary keys.
10
+ # This deprecates the https://github.com/composite-primary-keys/composite_primary_keys gem that was previously used in
11
+ # this library to support composite primary keys, which again are needed for interleaved tables. These tests use the
12
+ # third-party composite primary key gem and are therefore not executed for Rails 7.1 and higher.
13
+ return if ActiveRecord::gem_version >= Gem::Version.create('7.1.0')
14
+
9
15
  require "test_helper"
10
16
  require "models/singer"
11
17
  require "models/album"
@@ -196,8 +196,14 @@ module ActiveRecord
196
196
  end
197
197
  end
198
198
  end
199
+ expected = if ActiveRecord::gem_version < Gem::Version.create('7.1.0')
200
+ "you can't redefine the primary key column 'id'. To define a custom primary key, pass { id: false } to create_table."
201
+ else
202
+ "you can't redefine the primary key column 'id' on 'testings'. To define a custom primary key, pass { id: false } to create_table."
203
+ end
204
+
199
205
 
200
- assert_equal "you can't redefine the primary key column 'id'. To define a custom primary key, pass { id: false } to create_table.", error.message
206
+ assert_equal expected, error.message
201
207
  end
202
208
 
203
209
  def test_create_table_raises_when_redefining_custom_primary_key_column
@@ -209,7 +215,12 @@ module ActiveRecord
209
215
  end
210
216
  end
211
217
 
212
- assert_equal "you can't redefine the primary key column 'testing_id'. To define a custom primary key, pass { id: false } to create_table.", error.message
218
+ expected = if ActiveRecord::gem_version < Gem::Version.create('7.1.0')
219
+ "you can't redefine the primary key column 'testing_id'. To define a custom primary key, pass { id: false } to create_table."
220
+ else
221
+ "you can't redefine the primary key column 'testing_id' on 'testings'. To define a custom primary key, pass { id: false } to create_table."
222
+ end
223
+ assert_equal expected, error.message
213
224
  end
214
225
 
215
226
  def test_create_table_raises_when_defining_existing_column
@@ -222,7 +233,12 @@ module ActiveRecord
222
233
  end
223
234
  end
224
235
 
225
- assert_equal "you can't define an already defined column 'testing_column'.", error.message
236
+ expected = if ActiveRecord::gem_version < Gem::Version.create('7.1.0')
237
+ "you can't define an already defined column 'testing_column'."
238
+ else
239
+ "you can't define an already defined column 'testing_column' on 'testings'."
240
+ end
241
+ assert_equal expected, error.message
226
242
  end
227
243
 
228
244
  def test_create_table_with_timestamps_should_create_datetime_columns
@@ -13,6 +13,10 @@ module ActiveRecord
13
13
  class IndexTest < SpannerAdapter::TestCase
14
14
  include SpannerAdapter::Migration::TestHelper
15
15
 
16
+ def is_7_1_or_higher?
17
+ ActiveRecord::gem_version >= Gem::Version.create('7.1.0')
18
+ end
19
+
16
20
  def test_dump_schema_contains_start_batch_ddl
17
21
  connection = ActiveRecord::Base.connection
18
22
  schema = StringIO.new
@@ -34,7 +38,12 @@ module ActiveRecord
34
38
  connection = ActiveRecord::Base.connection
35
39
  schema = StringIO.new
36
40
  ActiveRecord::SchemaDumper.dump connection, schema
37
- assert schema.string.include?("create_table \"albums\", primary_key: \"albumid\"")
41
+ sql = schema.string
42
+ if is_7_1_or_higher?
43
+ assert schema.string.include?("create_table \"albums\", primary_key: [\"singerid\", \"albumid\"]"), sql
44
+ else
45
+ assert schema.string.include?("create_table \"albums\", primary_key: \"albumid\""), sql
46
+ end
38
47
  end
39
48
 
40
49
  def test_dump_schema_contains_interleaved_index
@@ -6,6 +6,12 @@
6
6
 
7
7
  # frozen_string_literal: true
8
8
 
9
+ # ActiveRecord 7.1 introduced native support for composite primary keys.
10
+ # This deprecates the https://github.com/composite-primary-keys/composite_primary_keys gem that was previously used in
11
+ # this library to support composite primary keys, which again are needed for interleaved tables. These tests use the
12
+ # third-party composite primary key gem and are therefore not executed for Rails 7.1 and higher.
13
+ return if ActiveRecord::gem_version >= Gem::Version.create('7.1.0')
14
+
9
15
  require "test_helper"
10
16
  require "test_helpers/with_separate_database"
11
17
 
@@ -14,6 +14,10 @@ module ActiveRecord
14
14
  class DatabaseTasksTest < SpannerAdapter::TestCase
15
15
  attr_reader :connector_config, :connection
16
16
 
17
+ def is_7_1_or_higher?
18
+ ActiveRecord::gem_version >= Gem::Version.create('7.1.0')
19
+ end
20
+
17
21
  def setup
18
22
  @database_id = "ar-tasks-test-#{SecureRandom.hex 4}"
19
23
  @connector_config = {
@@ -87,8 +91,12 @@ module ActiveRecord
87
91
  end
88
92
  ActiveRecord::Tasks::DatabaseTasks.dump_schema db_config, :sql
89
93
  sql = File.read(filename)
90
- if ENV["SPANNER_EMULATOR_HOST"]
94
+ if ENV["SPANNER_EMULATOR_HOST"] && is_7_1_or_higher?
95
+ assert_equal expected_schema_sql_on_emulator_7_1, sql, msg = sql
96
+ elsif ENV["SPANNER_EMULATOR_HOST"]
91
97
  assert_equal expected_schema_sql_on_emulator, sql, msg = sql
98
+ elsif is_7_1_or_higher?
99
+ assert_equal expected_schema_sql_on_production_7_1, sql, msg = sql
92
100
  else
93
101
  assert_equal expected_schema_sql_on_production, sql, msg = sql
94
102
  end
@@ -235,6 +243,168 @@ CREATE TABLE tracks (
235
243
  ) PRIMARY KEY(singerid, albumid, trackid),
236
244
  INTERLEAVE IN PARENT albums ON DELETE CASCADE;
237
245
  CREATE NULL_FILTERED INDEX index_tracks_on_singerid_and_albumid_and_title ON tracks(singerid, albumid, title), INTERLEAVE IN albums;
246
+ CREATE TABLE table_with_sequence (
247
+ id INT64 NOT NULL DEFAULT (FARM_FINGERPRINT(GENERATE_UUID())),
248
+ name STRING(MAX) NOT NULL,
249
+ age INT64 NOT NULL,
250
+ ) PRIMARY KEY(id);
251
+ CREATE TABLE schema_migrations (
252
+ version STRING(MAX) NOT NULL,
253
+ ) PRIMARY KEY(version);
254
+ CREATE TABLE ar_internal_metadata (
255
+ key STRING(MAX) NOT NULL,
256
+ value STRING(MAX),
257
+ created_at TIMESTAMP NOT NULL,
258
+ updated_at TIMESTAMP NOT NULL,
259
+ ) PRIMARY KEY(key);
260
+ INSERT INTO `schema_migrations` (version) VALUES
261
+ ('1');
262
+
263
+ "
264
+ end
265
+
266
+ def expected_schema_sql_on_emulator_7_1
267
+ "CREATE TABLE all_types (
268
+ id INT64 NOT NULL,
269
+ col_string STRING(MAX),
270
+ col_int64 INT64,
271
+ col_float64 FLOAT64,
272
+ col_numeric NUMERIC,
273
+ col_bool BOOL,
274
+ col_bytes BYTES(MAX),
275
+ col_date DATE,
276
+ col_timestamp TIMESTAMP,
277
+ col_json JSON,
278
+ col_array_string ARRAY<STRING(MAX)>,
279
+ col_array_int64 ARRAY<INT64>,
280
+ col_array_float64 ARRAY<FLOAT64>,
281
+ col_array_numeric ARRAY<NUMERIC>,
282
+ col_array_bool ARRAY<BOOL>,
283
+ col_array_bytes ARRAY<BYTES(MAX)>,
284
+ col_array_date ARRAY<DATE>,
285
+ col_array_timestamp ARRAY<TIMESTAMP>,
286
+ col_array_json ARRAY<JSON>,
287
+ ) PRIMARY KEY(id);
288
+ CREATE TABLE firms (
289
+ id INT64 NOT NULL,
290
+ name STRING(MAX),
291
+ rating INT64,
292
+ description STRING(MAX),
293
+ account_id INT64,
294
+ ) PRIMARY KEY(id);
295
+ CREATE INDEX index_firms_on_account_id ON firms(account_id);
296
+ CREATE TABLE customers (
297
+ id INT64 NOT NULL,
298
+ name STRING(MAX),
299
+ ) PRIMARY KEY(id);
300
+ CREATE TABLE accounts (
301
+ id INT64 NOT NULL,
302
+ customer_id INT64,
303
+ firm_id INT64,
304
+ name STRING(MAX),
305
+ credit_limit INT64,
306
+ transactions_count INT64,
307
+ ) PRIMARY KEY(id);
308
+ CREATE TABLE transactions (
309
+ id INT64 NOT NULL,
310
+ amount FLOAT64,
311
+ account_id INT64,
312
+ ) PRIMARY KEY(id);
313
+ CREATE TABLE departments (
314
+ id INT64 NOT NULL,
315
+ name STRING(MAX),
316
+ resource_type STRING(255),
317
+ resource_id INT64,
318
+ ) PRIMARY KEY(id);
319
+ CREATE INDEX index_departments_on_resource ON departments(resource_type, resource_id);
320
+ CREATE TABLE member_types (
321
+ id INT64 NOT NULL,
322
+ name STRING(MAX),
323
+ ) PRIMARY KEY(id);
324
+ CREATE TABLE members (
325
+ id INT64 NOT NULL,
326
+ name STRING(MAX),
327
+ member_type_id INT64,
328
+ admittable_type STRING(255),
329
+ admittable_id INT64,
330
+ ) PRIMARY KEY(id);
331
+ CREATE TABLE memberships (
332
+ id INT64 NOT NULL,
333
+ joined_on TIMESTAMP,
334
+ club_id INT64,
335
+ member_id INT64,
336
+ favourite BOOL,
337
+ ) PRIMARY KEY(id);
338
+ CREATE TABLE clubs (
339
+ id INT64 NOT NULL,
340
+ name STRING(MAX),
341
+ ) PRIMARY KEY(id);
342
+ CREATE TABLE authors (
343
+ id INT64 NOT NULL,
344
+ name STRING(MAX) NOT NULL,
345
+ registered_date DATE,
346
+ organization_id INT64,
347
+ ) PRIMARY KEY(id);
348
+ CREATE TABLE posts (
349
+ id INT64 NOT NULL,
350
+ title STRING(MAX),
351
+ content STRING(MAX),
352
+ author_id INT64,
353
+ comments_count INT64,
354
+ post_date DATE,
355
+ published_time TIMESTAMP,
356
+ ) PRIMARY KEY(id);
357
+ CREATE INDEX index_posts_on_author_id ON posts(author_id);
358
+ CREATE TABLE comments (
359
+ id INT64 NOT NULL,
360
+ comment STRING(MAX),
361
+ post_id INT64,
362
+ CONSTRAINT fk_rails_2fd19c0db7 FOREIGN KEY(post_id) REFERENCES posts(id),
363
+ ) PRIMARY KEY(id);
364
+ CREATE TABLE addresses (
365
+ id INT64 NOT NULL,
366
+ line1 STRING(MAX),
367
+ postal_code STRING(MAX),
368
+ city STRING(MAX),
369
+ author_id INT64,
370
+ ) PRIMARY KEY(id);
371
+ CREATE TABLE organizations (
372
+ id INT64 NOT NULL,
373
+ name STRING(MAX),
374
+ last_updated TIMESTAMP OPTIONS (
375
+ allow_commit_timestamp = true
376
+ ),
377
+ ) PRIMARY KEY(id);
378
+ CREATE TABLE singers (
379
+ singerid INT64 NOT NULL,
380
+ first_name STRING(200),
381
+ last_name STRING(MAX),
382
+ tracks_count INT64,
383
+ lock_version INT64,
384
+ full_name STRING(MAX) AS (COALESCE(first_name || ' ', '') || last_name) STORED,
385
+ ) PRIMARY KEY(singerid);
386
+ CREATE TABLE albums (
387
+ singerid INT64 NOT NULL,
388
+ albumid INT64 NOT NULL,
389
+ title STRING(MAX),
390
+ lock_version INT64,
391
+ ) PRIMARY KEY(singerid, albumid),
392
+ INTERLEAVE IN PARENT singers ON DELETE NO ACTION;
393
+ CREATE TABLE tracks (
394
+ singerid INT64 NOT NULL,
395
+ albumid INT64 NOT NULL,
396
+ trackid INT64 NOT NULL,
397
+ title STRING(MAX),
398
+ duration NUMERIC,
399
+ lock_version INT64,
400
+ ) PRIMARY KEY(singerid, albumid, trackid),
401
+ INTERLEAVE IN PARENT albums ON DELETE CASCADE;
402
+ CREATE NULL_FILTERED INDEX index_tracks_on_singerid_and_albumid_and_title ON tracks(singerid, albumid, title), INTERLEAVE IN albums;
403
+ CREATE TABLE table_with_sequence (
404
+ id INT64 NOT NULL DEFAULT (FARM_FINGERPRINT(GENERATE_UUID())),
405
+ name STRING(MAX) NOT NULL,
406
+ age INT64 NOT NULL,
407
+ ) PRIMARY KEY(id);
238
408
  CREATE TABLE schema_migrations (
239
409
  version STRING(MAX) NOT NULL,
240
410
  ) PRIMARY KEY(version);
@@ -251,7 +421,10 @@ INSERT INTO `schema_migrations` (version) VALUES
251
421
  end
252
422
 
253
423
  def expected_schema_sql_on_production
254
- "CREATE TABLE accounts (
424
+ "CREATE SEQUENCE test_sequence OPTIONS (
425
+ sequence_kind = 'bit_reversed_positive'
426
+ );
427
+ CREATE TABLE accounts (
255
428
  id INT64 NOT NULL,
256
429
  customer_id INT64,
257
430
  firm_id INT64,
@@ -391,6 +564,171 @@ CREATE TABLE tracks (
391
564
  ) PRIMARY KEY(singerid, albumid, trackid),
392
565
  INTERLEAVE IN PARENT albums ON DELETE CASCADE;
393
566
  CREATE NULL_FILTERED INDEX index_tracks_on_singerid_and_albumid_and_title ON tracks(singerid, albumid, title), INTERLEAVE IN albums;
567
+ CREATE TABLE table_with_sequence (
568
+ id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE test_sequence)),
569
+ name STRING(MAX) NOT NULL,
570
+ age INT64 NOT NULL,
571
+ ) PRIMARY KEY(id);
572
+ CREATE TABLE transactions (
573
+ id INT64 NOT NULL,
574
+ amount FLOAT64,
575
+ account_id INT64,
576
+ ) PRIMARY KEY(id);
577
+ INSERT INTO `schema_migrations` (version) VALUES
578
+ ('1');
579
+
580
+ "
581
+ end
582
+
583
+ def expected_schema_sql_on_production_7_1
584
+ "CREATE SEQUENCE test_sequence OPTIONS (
585
+ sequence_kind = 'bit_reversed_positive'
586
+ );
587
+ CREATE TABLE accounts (
588
+ id INT64 NOT NULL,
589
+ customer_id INT64,
590
+ firm_id INT64,
591
+ name STRING(MAX),
592
+ credit_limit INT64,
593
+ transactions_count INT64,
594
+ ) PRIMARY KEY(id);
595
+ CREATE TABLE addresses (
596
+ id INT64 NOT NULL,
597
+ line1 STRING(MAX),
598
+ postal_code STRING(MAX),
599
+ city STRING(MAX),
600
+ author_id INT64,
601
+ ) PRIMARY KEY(id);
602
+ CREATE TABLE all_types (
603
+ id INT64 NOT NULL,
604
+ col_string STRING(MAX),
605
+ col_int64 INT64,
606
+ col_float64 FLOAT64,
607
+ col_numeric NUMERIC,
608
+ col_bool BOOL,
609
+ col_bytes BYTES(MAX),
610
+ col_date DATE,
611
+ col_timestamp TIMESTAMP,
612
+ col_json JSON,
613
+ col_array_string ARRAY<STRING(MAX)>,
614
+ col_array_int64 ARRAY<INT64>,
615
+ col_array_float64 ARRAY<FLOAT64>,
616
+ col_array_numeric ARRAY<NUMERIC>,
617
+ col_array_bool ARRAY<BOOL>,
618
+ col_array_bytes ARRAY<BYTES(MAX)>,
619
+ col_array_date ARRAY<DATE>,
620
+ col_array_timestamp ARRAY<TIMESTAMP>,
621
+ col_array_json ARRAY<JSON>,
622
+ ) PRIMARY KEY(id);
623
+ CREATE TABLE ar_internal_metadata (
624
+ key STRING(MAX) NOT NULL,
625
+ value STRING(MAX),
626
+ created_at TIMESTAMP NOT NULL,
627
+ updated_at TIMESTAMP NOT NULL,
628
+ ) PRIMARY KEY(key);
629
+ CREATE TABLE authors (
630
+ id INT64 NOT NULL,
631
+ name STRING(MAX) NOT NULL,
632
+ registered_date DATE,
633
+ organization_id INT64,
634
+ ) PRIMARY KEY(id);
635
+ CREATE TABLE clubs (
636
+ id INT64 NOT NULL,
637
+ name STRING(MAX),
638
+ ) PRIMARY KEY(id);
639
+ CREATE TABLE comments (
640
+ id INT64 NOT NULL,
641
+ comment STRING(MAX),
642
+ post_id INT64,
643
+ ) PRIMARY KEY(id);
644
+ CREATE TABLE customers (
645
+ id INT64 NOT NULL,
646
+ name STRING(MAX),
647
+ ) PRIMARY KEY(id);
648
+ CREATE TABLE departments (
649
+ id INT64 NOT NULL,
650
+ name STRING(MAX),
651
+ resource_type STRING(255),
652
+ resource_id INT64,
653
+ ) PRIMARY KEY(id);
654
+ CREATE INDEX index_departments_on_resource ON departments(resource_type, resource_id);
655
+ CREATE TABLE firms (
656
+ id INT64 NOT NULL,
657
+ name STRING(MAX),
658
+ rating INT64,
659
+ description STRING(MAX),
660
+ account_id INT64,
661
+ ) PRIMARY KEY(id);
662
+ CREATE INDEX index_firms_on_account_id ON firms(account_id);
663
+ CREATE TABLE member_types (
664
+ id INT64 NOT NULL,
665
+ name STRING(MAX),
666
+ ) PRIMARY KEY(id);
667
+ CREATE TABLE members (
668
+ id INT64 NOT NULL,
669
+ name STRING(MAX),
670
+ member_type_id INT64,
671
+ admittable_type STRING(255),
672
+ admittable_id INT64,
673
+ ) PRIMARY KEY(id);
674
+ CREATE TABLE memberships (
675
+ id INT64 NOT NULL,
676
+ joined_on TIMESTAMP,
677
+ club_id INT64,
678
+ member_id INT64,
679
+ favourite BOOL,
680
+ ) PRIMARY KEY(id);
681
+ CREATE TABLE organizations (
682
+ id INT64 NOT NULL,
683
+ name STRING(MAX),
684
+ last_updated TIMESTAMP OPTIONS (
685
+ allow_commit_timestamp = true
686
+ ),
687
+ ) PRIMARY KEY(id);
688
+ CREATE TABLE posts (
689
+ id INT64 NOT NULL,
690
+ title STRING(MAX),
691
+ content STRING(MAX),
692
+ author_id INT64,
693
+ comments_count INT64,
694
+ post_date DATE,
695
+ published_time TIMESTAMP,
696
+ ) PRIMARY KEY(id);
697
+ ALTER TABLE comments ADD CONSTRAINT fk_rails_2fd19c0db7 FOREIGN KEY(post_id) REFERENCES posts(id);
698
+ CREATE INDEX index_posts_on_author_id ON posts(author_id);
699
+ CREATE TABLE schema_migrations (
700
+ version STRING(MAX) NOT NULL,
701
+ ) PRIMARY KEY(version);
702
+ CREATE TABLE singers (
703
+ singerid INT64 NOT NULL,
704
+ first_name STRING(200),
705
+ last_name STRING(MAX),
706
+ tracks_count INT64,
707
+ lock_version INT64,
708
+ full_name STRING(MAX) AS (COALESCE(first_name || ' ', '') || last_name) STORED,
709
+ ) PRIMARY KEY(singerid);
710
+ CREATE TABLE albums (
711
+ singerid INT64 NOT NULL,
712
+ albumid INT64 NOT NULL,
713
+ title STRING(MAX),
714
+ lock_version INT64,
715
+ ) PRIMARY KEY(singerid, albumid),
716
+ INTERLEAVE IN PARENT singers ON DELETE NO ACTION;
717
+ CREATE TABLE tracks (
718
+ singerid INT64 NOT NULL,
719
+ albumid INT64 NOT NULL,
720
+ trackid INT64 NOT NULL,
721
+ title STRING(MAX),
722
+ duration NUMERIC,
723
+ lock_version INT64,
724
+ ) PRIMARY KEY(singerid, albumid, trackid),
725
+ INTERLEAVE IN PARENT albums ON DELETE CASCADE;
726
+ CREATE NULL_FILTERED INDEX index_tracks_on_singerid_and_albumid_and_title ON tracks(singerid, albumid, title), INTERLEAVE IN albums;
727
+ CREATE TABLE table_with_sequence (
728
+ id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE test_sequence)),
729
+ name STRING(MAX) NOT NULL,
730
+ age INT64 NOT NULL,
731
+ ) PRIMARY KEY(id);
394
732
  CREATE TABLE transactions (
395
733
  id INT64 NOT NULL,
396
734
  amount FLOAT64,
@@ -6,6 +6,12 @@
6
6
 
7
7
  # frozen_string_literal: true
8
8
 
9
+ # ActiveRecord 7.1 introduced native support for composite primary keys.
10
+ # This deprecates the https://github.com/composite-primary-keys/composite_primary_keys gem that was previously used in
11
+ # this library to support composite primary keys, which again are needed for interleaved tables. These tests use the
12
+ # third-party composite primary key gem and are therefore not executed for Rails 7.1 and higher.
13
+ return if ActiveRecord::gem_version >= Gem::Version.create('7.1.0')
14
+
9
15
  require "test_helper"
10
16
  require "models/singer"
11
17
  require "models/album"