activerecord-spanner-adapter 1.5.0 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/acceptance-tests-on-emulator.yaml +1 -1
- data/.github/workflows/acceptance-tests-on-production.yaml +5 -3
- data/.github/workflows/ci.yaml +1 -1
- data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +1 -1
- data/.github/workflows/nightly-acceptance-tests-on-production.yaml +5 -3
- data/.github/workflows/nightly-unit-tests.yaml +1 -1
- data/.github/workflows/release-please-label.yml +1 -1
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +5 -2
- data/README.md +10 -10
- data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb +6 -0
- data/acceptance/cases/migration/change_schema_test.rb +19 -3
- data/acceptance/cases/migration/schema_dumper_test.rb +10 -1
- data/acceptance/cases/models/insert_all_test.rb +22 -0
- data/acceptance/cases/models/interleave_test.rb +6 -0
- data/acceptance/cases/tasks/database_tasks_test.rb +340 -2
- data/acceptance/cases/transactions/optimistic_locking_test.rb +6 -0
- data/acceptance/cases/transactions/read_write_transactions_test.rb +24 -0
- data/acceptance/models/table_with_sequence.rb +10 -0
- data/acceptance/schema/schema.rb +65 -19
- data/acceptance/test_helper.rb +1 -1
- data/activerecord-spanner-adapter.gemspec +1 -1
- data/examples/snippets/bit-reversed-sequence/README.md +103 -0
- data/examples/snippets/bit-reversed-sequence/Rakefile +13 -0
- data/examples/snippets/bit-reversed-sequence/application.rb +68 -0
- data/examples/snippets/bit-reversed-sequence/config/database.yml +8 -0
- data/examples/snippets/bit-reversed-sequence/db/migrate/01_create_tables.rb +33 -0
- data/examples/snippets/bit-reversed-sequence/db/schema.rb +31 -0
- data/examples/snippets/bit-reversed-sequence/db/seeds.rb +31 -0
- data/examples/snippets/bit-reversed-sequence/models/album.rb +11 -0
- data/examples/snippets/bit-reversed-sequence/models/singer.rb +15 -0
- data/examples/snippets/interleaved-tables/README.md +44 -53
- data/examples/snippets/interleaved-tables/Rakefile +2 -2
- data/examples/snippets/interleaved-tables/application.rb +2 -2
- data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +12 -18
- data/examples/snippets/interleaved-tables/db/schema.rb +9 -7
- data/examples/snippets/interleaved-tables/db/seeds.rb +1 -1
- data/examples/snippets/interleaved-tables/models/album.rb +3 -7
- data/examples/snippets/interleaved-tables/models/singer.rb +1 -1
- data/examples/snippets/interleaved-tables/models/track.rb +6 -7
- data/examples/snippets/interleaved-tables-before-7.1/README.md +167 -0
- data/examples/snippets/interleaved-tables-before-7.1/Rakefile +13 -0
- data/examples/snippets/interleaved-tables-before-7.1/application.rb +126 -0
- data/examples/snippets/interleaved-tables-before-7.1/config/database.yml +8 -0
- data/examples/snippets/interleaved-tables-before-7.1/db/migrate/01_create_tables.rb +44 -0
- data/examples/snippets/interleaved-tables-before-7.1/db/schema.rb +37 -0
- data/examples/snippets/interleaved-tables-before-7.1/db/seeds.rb +40 -0
- data/examples/snippets/interleaved-tables-before-7.1/models/album.rb +20 -0
- data/examples/snippets/interleaved-tables-before-7.1/models/singer.rb +18 -0
- data/examples/snippets/interleaved-tables-before-7.1/models/track.rb +28 -0
- data/examples/snippets/query-logs/README.md +43 -0
- data/examples/snippets/query-logs/Rakefile +13 -0
- data/examples/snippets/query-logs/application.rb +63 -0
- data/examples/snippets/query-logs/config/database.yml +8 -0
- data/examples/snippets/query-logs/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/query-logs/db/schema.rb +31 -0
- data/examples/snippets/query-logs/db/seeds.rb +24 -0
- data/examples/snippets/query-logs/models/album.rb +9 -0
- data/examples/snippets/query-logs/models/singer.rb +9 -0
- data/lib/active_record/connection_adapters/spanner/column.rb +13 -0
- data/lib/active_record/connection_adapters/spanner/database_statements.rb +144 -35
- data/lib/active_record/connection_adapters/spanner/schema_cache.rb +3 -21
- data/lib/active_record/connection_adapters/spanner/schema_creation.rb +11 -0
- data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/spanner/schema_statements.rb +3 -2
- data/lib/active_record/connection_adapters/spanner_adapter.rb +28 -9
- data/lib/activerecord_spanner_adapter/base.rb +58 -21
- data/lib/activerecord_spanner_adapter/information_schema.rb +33 -24
- data/lib/activerecord_spanner_adapter/primary_key.rb +1 -1
- data/lib/activerecord_spanner_adapter/table/column.rb +4 -9
- data/lib/activerecord_spanner_adapter/version.rb +1 -1
- data/lib/arel/visitors/spanner.rb +3 -1
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ad2384bb1890bb224c89a146c42f615f89c6e2892848da5e701a091d90fa95b
|
4
|
+
data.tar.gz: 0e8a9c608068ff30011bc9bca68b10ab0d22b910260a37a6d4a492365adf78b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1894765bbc1e3dfac270d73199a4f235ae95724ca18145d6850cce27c38ef2018b59e9035cf2fa91bc30d3f650e080b8eea58c3e91a66035db3a4d07c35ca1be
|
7
|
+
data.tar.gz: 4a9b93d7990fa78f901864bed816e75ff5d0f9da34a530c7107f475d8fd06dc71817fbf8b2c1e0262e4656bf7ab363917ecf7b7c82315b6d5fa84cce0d22489d
|
@@ -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@
|
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
|
data/.github/workflows/ci.yaml
CHANGED
@@ -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@
|
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
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
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
|
+
|
11
|
+
### 1.5.1 (2023-12-12)
|
12
|
+
|
13
|
+
#### Bug Fixes
|
14
|
+
|
15
|
+
* more permissive arg passthrough for insert_all and upsert_all ([#283](https://github.com/googleapis/ruby-spanner-activerecord/issues/283))
|
16
|
+
|
3
17
|
### 1.5.0 (2023-11-03)
|
4
18
|
|
5
19
|
#### Features
|
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.
|
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
|
-
|
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
|
94
|
-
Lack of sequential
|
95
|
-
Table without Primary Key| Cloud Spanner support does not support tables without a primary key
|
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
|
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
|
99
|
-
Only GoogleSQL-dialect databases| Cloud Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases.
|
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
|
|
data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -33,6 +33,12 @@ module ActiveRecord
|
|
33
33
|
assert_raise(NotImplementedError) { Author.insert_all(values) }
|
34
34
|
end
|
35
35
|
|
36
|
+
def test_insert
|
37
|
+
value = { id: Author.next_sequence_value, name: "Alice" }
|
38
|
+
|
39
|
+
assert_raise(NotImplementedError) { Author.insert(value) }
|
40
|
+
end
|
41
|
+
|
36
42
|
def test_insert_all!
|
37
43
|
values = [
|
38
44
|
{ id: Author.next_sequence_value, name: "Alice" },
|
@@ -85,6 +91,22 @@ module ActiveRecord
|
|
85
91
|
assert_equal "Carol", authors[2].name
|
86
92
|
end
|
87
93
|
|
94
|
+
def test_upsert
|
95
|
+
Author.create id: 1, name: "David"
|
96
|
+
authors = Author.all.order(:name)
|
97
|
+
assert_equal 1, authors.length
|
98
|
+
assert_equal "David", authors[0].name
|
99
|
+
|
100
|
+
value = { id: 1, name: "Alice" }
|
101
|
+
|
102
|
+
Author.upsert(value)
|
103
|
+
|
104
|
+
authors = Author.all.order(:name)
|
105
|
+
|
106
|
+
assert_equal 1, authors.length
|
107
|
+
assert_equal "Alice", authors[0].name
|
108
|
+
end
|
109
|
+
|
88
110
|
def test_upsert_all
|
89
111
|
Author.create id: 1, name: "David"
|
90
112
|
authors = Author.all.order(:name)
|
@@ -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
|
|