activerecord-spanner-adapter 0.6.0 → 1.0.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.
- checksums.yaml +4 -4
- data/.github/blunderbuss.yml +2 -0
- data/.github/sync-repo-settings.yaml +1 -1
- data/.github/workflows/acceptance-tests-on-emulator.yaml +1 -1
- data/.github/workflows/acceptance-tests-on-production.yaml +2 -2
- data/.github/workflows/ci.yaml +1 -1
- data/.github/workflows/release-please-label.yml +4 -4
- data/.github/workflows/release-please.yml +10 -9
- data/.github/workflows/rubocop.yaml +2 -2
- data/.release-please-manifest.json +3 -0
- data/.toys/release.rb +2 -2
- data/CHANGELOG.md +46 -23
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/acceptance/cases/models/query_test.rb +24 -0
- data/acceptance/cases/type/all_types_test.rb +16 -14
- data/examples/rails/README.md +9 -9
- data/examples/snippets/generated-column/db/schema.rb +3 -3
- data/examples/snippets/hints/README.md +19 -0
- data/examples/snippets/{interleaved-tables → hints}/Rakefile +2 -2
- data/examples/snippets/hints/application.rb +47 -0
- data/examples/snippets/{interleaved-tables → hints}/config/database.yml +0 -0
- data/examples/snippets/hints/db/migrate/01_create_tables.rb +23 -0
- data/examples/snippets/{interleaved-tables → hints}/db/schema.rb +10 -14
- data/examples/snippets/{interleaved-tables → hints}/db/seeds.rb +0 -11
- data/examples/snippets/hints/models/album.rb +9 -0
- data/examples/snippets/hints/models/singer.rb +9 -0
- data/examples/snippets/partitioned-dml/README.md +16 -0
- data/examples/snippets/partitioned-dml/Rakefile +13 -0
- data/examples/snippets/partitioned-dml/application.rb +48 -0
- data/examples/snippets/partitioned-dml/config/database.yml +8 -0
- data/examples/snippets/partitioned-dml/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/partitioned-dml/db/schema.rb +26 -0
- data/examples/snippets/partitioned-dml/db/seeds.rb +29 -0
- data/examples/snippets/partitioned-dml/models/album.rb +9 -0
- data/examples/snippets/partitioned-dml/models/singer.rb +9 -0
- data/lib/active_record/connection_adapters/spanner_adapter.rb +1 -1
- data/lib/active_record/tasks/spanner_database_tasks.rb +1 -1
- data/lib/active_record/type/spanner/array.rb +19 -5
- data/lib/activerecord_spanner_adapter/base.rb +31 -10
- data/lib/activerecord_spanner_adapter/connection.rb +46 -20
- data/lib/activerecord_spanner_adapter/information_schema.rb +2 -1
- data/lib/activerecord_spanner_adapter/transaction.rb +52 -21
- data/lib/activerecord_spanner_adapter/version.rb +1 -1
- data/lib/arel/visitors/spanner.rb +39 -0
- data/lib/spanner_client_ext.rb +4 -0
- data/release-please-config.json +19 -0
- metadata +24 -13
- data/examples/snippets/interleaved-tables/README.md +0 -152
- data/examples/snippets/interleaved-tables/application.rb +0 -109
- data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +0 -44
- data/examples/snippets/interleaved-tables/models/album.rb +0 -15
- data/examples/snippets/interleaved-tables/models/singer.rb +0 -20
- data/examples/snippets/interleaved-tables/models/track.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcc2624f18893422bf8ac9c23d07fff039e79cee5f51b975054314f49820b694
|
4
|
+
data.tar.gz: 7145b48f67236eb7ee9aac20bd1dfa907268419f262abf82cd6973acba25ab64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49aed5257b191aee1e9271c1d04e91c2ff1663c78e9b1e70e89acda430587324991a10cb1b2aabdfd9b1e9d70ab862b3a1579fda5c032023175303fa260deeed
|
7
|
+
data.tar.gz: 1764369d2a370d4c8d35cbbcd3b9c45130514cc6e76bac67e5a9dafbf2bf020734b973be44f354b13da9acaaffdebaba78e31046da56c6e62efe0546aca30611
|
@@ -1,7 +1,7 @@
|
|
1
1
|
on:
|
2
2
|
push:
|
3
3
|
branches:
|
4
|
-
-
|
4
|
+
- main
|
5
5
|
pull_request:
|
6
6
|
name: acceptance tests on production
|
7
7
|
jobs:
|
@@ -35,7 +35,7 @@ jobs:
|
|
35
35
|
bundler-cache: true
|
36
36
|
ruby-version: ${{ matrix.ruby }}
|
37
37
|
- name: Setup GCloud
|
38
|
-
uses: google-github-actions/setup-gcloud@
|
38
|
+
uses: google-github-actions/setup-gcloud@v0
|
39
39
|
with:
|
40
40
|
project_id: ${{ secrets.GCP_PROJECT_ID }}
|
41
41
|
service_account_key: ${{ secrets.GCP_SA_KEY }}
|
data/.github/workflows/ci.yaml
CHANGED
@@ -2,21 +2,21 @@ name: release-please-label
|
|
2
2
|
on:
|
3
3
|
pull_request_target:
|
4
4
|
branches:
|
5
|
-
-
|
5
|
+
- main
|
6
6
|
types:
|
7
7
|
- opened
|
8
8
|
jobs:
|
9
9
|
release-please-label:
|
10
|
-
if: "${{ github.event.sender.login == 'yoshi-code-bot' && startsWith(github.event.pull_request.title, 'chore: release ') }}"
|
10
|
+
if: "${{ github.event.sender.login == 'yoshi-code-bot' && startsWith(github.event.pull_request.title, 'chore(main): release ') }}"
|
11
11
|
runs-on: ubuntu-latest
|
12
12
|
steps:
|
13
13
|
- name: ReleaseLabel
|
14
|
-
uses: actions/github-script@
|
14
|
+
uses: actions/github-script@v6
|
15
15
|
with:
|
16
16
|
github-token: ${{secrets.YOSHI_APPROVER_TOKEN}}
|
17
17
|
script: |
|
18
18
|
core.info('Labeling release');
|
19
|
-
await github.issues.addLabels({
|
19
|
+
await github.rest.issues.addLabels({
|
20
20
|
owner: context.repo.owner,
|
21
21
|
repo: context.repo.repo,
|
22
22
|
issue_number: context.payload.pull_request.number,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
name: Release-Please
|
2
2
|
on:
|
3
3
|
schedule:
|
4
|
-
- cron: '
|
4
|
+
- cron: '57 10 * * *'
|
5
5
|
workflow_dispatch:
|
6
6
|
inputs:
|
7
7
|
gem:
|
@@ -21,19 +21,20 @@ jobs:
|
|
21
21
|
steps:
|
22
22
|
- name: Checkout repo
|
23
23
|
uses: actions/checkout@v2
|
24
|
-
- name: Install Ruby
|
24
|
+
- name: Install Ruby 3.0
|
25
25
|
uses: ruby/setup-ruby@v1
|
26
26
|
with:
|
27
|
-
ruby-version: "
|
28
|
-
- name: Install NodeJS
|
27
|
+
ruby-version: "3.0"
|
28
|
+
- name: Install NodeJS 16.x
|
29
29
|
uses: actions/setup-node@v2
|
30
30
|
with:
|
31
|
-
node-version: "
|
31
|
+
node-version: "16.x"
|
32
32
|
- name: Install tools
|
33
|
-
run: "gem install --no-document toys
|
33
|
+
run: "gem install --no-document toys"
|
34
34
|
- name: execute
|
35
35
|
run: |
|
36
|
-
toys release
|
36
|
+
toys release manifest -v \
|
37
|
+
--fork --skip-labeling \
|
37
38
|
--github-event-name=${{ github.event_name }} \
|
38
|
-
|
39
|
-
|
39
|
+
${{ github.event.inputs.args }} \
|
40
|
+
-- ${{ github.event.inputs.gem }}
|
@@ -4,7 +4,7 @@ on:
|
|
4
4
|
pull_request:
|
5
5
|
types: [opened, synchronize]
|
6
6
|
push:
|
7
|
-
branches: [
|
7
|
+
branches: [ main ]
|
8
8
|
|
9
9
|
jobs:
|
10
10
|
build:
|
@@ -18,7 +18,7 @@ jobs:
|
|
18
18
|
with:
|
19
19
|
ruby-version: '2.5'
|
20
20
|
- name: cache gems
|
21
|
-
uses: actions/cache@
|
21
|
+
uses: actions/cache@v2
|
22
22
|
with:
|
23
23
|
path: vendor/bundle
|
24
24
|
key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
|
data/.toys/release.rb
CHANGED
@@ -14,5 +14,5 @@
|
|
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/
|
18
|
-
path: "
|
17
|
+
load_git remote: "https://github.com/googleapis/ruby-common-tools.git",
|
18
|
+
path: "toys/release"
|
data/CHANGELOG.md
CHANGED
@@ -1,35 +1,58 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
### 1.0.1 (2022-04-21)
|
4
4
|
|
5
|
+
#### Bug Fixes
|
5
6
|
|
6
|
-
|
7
|
+
* ActiveRecord::Type::Spanner::Array does not use element type
|
7
8
|
|
8
|
-
|
9
|
-
* support single stale reads ([#127](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/127)) ([a600628](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/a600628267355b808f478ed543bc505e73f95d4a))
|
10
|
-
* support stale reads in read-only transactions ([#126](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/126)) ([8bf7730](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/8bf77300283c01e951725dd5e457270db20e98d2))
|
9
|
+
#### Documentation
|
11
10
|
|
12
|
-
|
11
|
+
* add limitation of interleaved tables
|
12
|
+
* fix a couple of minor formatting issues
|
13
13
|
|
14
|
+
### 1.0.0 (2021-12-07)
|
14
15
|
|
15
|
-
|
16
|
+
* GA release
|
16
17
|
|
17
|
-
|
18
|
-
* Add support for ARRAY data type ([#86](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/86)) ([0c66a62](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/0c66a620cab968779de04faf48e03eec643ebea9))
|
19
|
-
* google-cloud-spanner version upgraded to 2.2 ([#55](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/55)) ([d7581d6](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/d7581d60bd9a9e7b9989565449119f73e2caa694))
|
20
|
-
* Support interleaved tables ([#83](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/83)) ([82265f9](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/82265f94ace79964639a2c65554714752be39724))
|
21
|
-
* retry session not found ([#81](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/81)) ([88fd3b7](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/88fd3b70a03a90de2b667bb0f2e86efe5dc9328b))
|
22
|
-
* support and test multiple ActiveRecord versions ([#107](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/107)) ([db9d96c](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/db9d96c44b9560f6904209df1a9aa42bf50a5844))
|
23
|
-
* support DDL batches on connection ([#72](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/72)) ([0d18cd4](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/0d18cd49641bdb567012d6ac88b1909461d42551))
|
24
|
-
* support generated columns ([#94](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/94)) ([68664eb](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/68664eb5c617abc2954dea274430f416e616a324))
|
25
|
-
* support interleaved indexes + test other index features ([#101](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/101)) ([812e0f7](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/812e0f7f60b36ec26a974f6fb48266de5d840652))
|
26
|
-
* support optimistic locking ([#92](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/92)) ([9eb71d8](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/9eb71d8a207a8df0406241bff5780593eb0afd34))
|
27
|
-
* support PDML transactions ([#106](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/106)) ([fa0599a](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/fa0599afe986a184bb6ab26340305eeaa753dafa))
|
28
|
-
* support prepared statements and query cache ([#74](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/74)) ([fed8258](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/fed825862c95e3e052410e3576de18fc3b7849b7))
|
29
|
-
* support read only transactions ([#80](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/80)) ([2d6097b](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/2d6097bd8f4530634a41dcdbcbb3a02614f482b8))
|
30
|
-
* support setting attributes to commit timestamp ([#89](https://www.github.com/googleapis/ruby-spanner-activerecord/issues/89)) ([cdd8448](https://www.github.com/googleapis/ruby-spanner-activerecord/commit/cdd844852da92fa4e2c43fd06eeef31310d6ff8a))
|
18
|
+
### 0.7.1 (2021-11-21)
|
31
19
|
|
20
|
+
#### Performance Improvements
|
32
21
|
|
33
|
-
|
22
|
+
* inline BeginTransaction with first statement in the transaction
|
34
23
|
|
35
|
-
|
24
|
+
### 0.7.0 (2021-10-03)
|
25
|
+
|
26
|
+
#### Features
|
27
|
+
|
28
|
+
* add support for query hints
|
29
|
+
|
30
|
+
### 0.6.0 (2021-09-09)
|
31
|
+
|
32
|
+
#### Features
|
33
|
+
|
34
|
+
* support JSON data type
|
35
|
+
* support single stale reads
|
36
|
+
* support stale reads in read-only transactions
|
37
|
+
|
38
|
+
### 0.5.0 (2021-08-31)
|
39
|
+
|
40
|
+
#### Features
|
41
|
+
|
42
|
+
* Add support for NUMERIC type
|
43
|
+
* Add support for ARRAY data type
|
44
|
+
* google-cloud-spanner version upgraded to 2.2
|
45
|
+
* retry session not found
|
46
|
+
* support and test multiple ActiveRecord versions
|
47
|
+
* support DDL batches on connection
|
48
|
+
* support generated columns
|
49
|
+
* support interleaved indexes + test other index features
|
50
|
+
* support optimistic locking
|
51
|
+
* support PDML transactions
|
52
|
+
* support prepared statements and query cache
|
53
|
+
* support read only transactions
|
54
|
+
* support setting attributes to commit timestamp
|
55
|
+
|
56
|
+
#### Performance Improvements
|
57
|
+
|
58
|
+
* add benchmarks
|
data/CONTRIBUTING.md
CHANGED
@@ -70,7 +70,7 @@ $ cd ruby-spanner-activerecord
|
|
70
70
|
$ bundle exec rubocop
|
71
71
|
```
|
72
72
|
|
73
|
-
The rubocop settings depend on [googleapis/ruby-style](https://github.com/googleapis/ruby-style/), in addition to [.rubocop.yml](https://github.com/googleapis/ruby-spanner-activerecord/blob/
|
73
|
+
The rubocop settings depend on [googleapis/ruby-style](https://github.com/googleapis/ruby-style/), in addition to [.rubocop.yml](https://github.com/googleapis/ruby-spanner-activerecord/blob/main/.rubocop.yml).
|
74
74
|
|
75
75
|
## Code of Conduct
|
76
76
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|

|
6
6
|
|
7
|
-
This project provides a Cloud Spanner adapter for ActiveRecord. It
|
7
|
+
This project provides a Cloud Spanner adapter for ActiveRecord. It supports the following versions:
|
8
8
|
|
9
9
|
- ActiveRecord 6.0.x with Ruby 2.6 and 2.7.
|
10
10
|
- ActiveRecord 6.1.x with Ruby 2.6 and higher.
|
@@ -69,13 +69,13 @@ Some noteworthy examples in the snippets directory:
|
|
69
69
|
- [mutations](examples/snippets/mutations): Shows how you can use [mutations instead of DML](https://cloud.google.com/spanner/docs/dml-versus-mutations)
|
70
70
|
for inserting, updating and deleting data in a Cloud Spanner database. Mutations can have a significant performance
|
71
71
|
advantage compared to DML statements, but do not allow read-your-writes semantics during a transaction.
|
72
|
-
- [interleaved-tables](examples/snippets/interleaved-tables): Shows how to create and work with a hierarchy of `INTERLEAVED IN` tables.
|
73
72
|
- [array-data-type](examples/snippets/array-data-type): Shows how to work with `ARRAY` data types.
|
74
73
|
|
75
74
|
## Limitations
|
76
75
|
|
77
76
|
Limitation|Comment|Resolution
|
78
77
|
---|---|---
|
78
|
+
Interleaved tables are not supported|Cloud Spanner requires to use composite primary keys for interleaved tables, but Active Record does not support composite primary keys. More details: [#160](https://github.com/googleapis/ruby-spanner-activerecord/issues/160) |Use non-interleaved tables.
|
79
79
|
Lack of DEFAULT for columns [change_column_default](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_default)|Cloud Spanner does not support DEFAULT values for columns. The use of default must be enforced in your controller logic| Always set a value in your model or controller logic.
|
80
80
|
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.
|
81
81
|
Table without Primary Key| Cloud Spanner support does not support tables without a primary key.| Always define a primary key for your table.
|
@@ -93,4 +93,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
93
93
|
|
94
94
|
## Code of Conduct
|
95
95
|
|
96
|
-
Everyone interacting in the Activerecord::Spanner project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/googleapis/ruby-spanner-activerecord/blob/
|
96
|
+
Everyone interacting in the Activerecord::Spanner project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/googleapis/ruby-spanner-activerecord/blob/main/CODE_OF_CONDUCT.md).
|
@@ -142,6 +142,30 @@ module ActiveRecord
|
|
142
142
|
|
143
143
|
assert_equal [post], posts.to_a
|
144
144
|
end
|
145
|
+
|
146
|
+
def test_statement_hint
|
147
|
+
post = Post.optimizer_hints("statement_hint: @{USE_ADDITIONAL_PARALLELISM=TRUE}")
|
148
|
+
.select(:title).to_a.first
|
149
|
+
|
150
|
+
assert_nil post.id
|
151
|
+
assert_equal "Title - 1", post.title
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_table_hint
|
155
|
+
post = Post.optimizer_hints("table_hint: posts@{FORCE_INDEX=_BASE_TABLE}")
|
156
|
+
.select(:title).to_a.first
|
157
|
+
|
158
|
+
assert_nil post.id
|
159
|
+
assert_equal "Title - 1", post.title
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_join_hint
|
163
|
+
post = Post.joins("inner join @{JOIN_TYPE=HASH_JOIN} comments on posts.id=comments.post_id")
|
164
|
+
.select(:title).to_a.first
|
165
|
+
|
166
|
+
assert_nil post.id
|
167
|
+
assert_equal "Title - 1", post.title
|
168
|
+
end
|
145
169
|
end
|
146
170
|
end
|
147
171
|
end
|
@@ -32,17 +32,18 @@ module ActiveRecord
|
|
32
32
|
col_timestamp: ::Time.new(2021, 6, 23, 17, 8, 21, "+02:00"),
|
33
33
|
col_json: ENV["SPANNER_EMULATOR_HOST"] ? "" : { kind: "user_renamed", change: %w[jack john]},
|
34
34
|
col_array_string: ["string1", nil, "string2"],
|
35
|
-
col_array_int64: [100, nil, 200],
|
36
|
-
col_array_float64: [3.14, nil, 2.0/3.0],
|
37
|
-
col_array_numeric: [6.626, nil, 3.20],
|
38
|
-
col_array_bool: [true, nil, false],
|
35
|
+
col_array_int64: [100, nil, 200, "300"],
|
36
|
+
col_array_float64: [3.14, nil, 2.0/3.0, "3.14"],
|
37
|
+
col_array_numeric: [6.626, nil, 3.20, "400"],
|
38
|
+
col_array_bool: [true, nil, false, "false"],
|
39
39
|
col_array_bytes: [StringIO.new("bytes1"), nil, StringIO.new("bytes2")],
|
40
|
-
col_array_date: [::Date.new(2021, 6, 23), nil, ::Date.new(2021, 6, 24)],
|
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
|
-
::Time.new(2021, 6, 24, 17, 8, 21, "+02:00")],
|
42
|
+
::Time.new(2021, 6, 24, 17, 8, 21, "+02:00"), "2021-06-25 17:08:21 +02:00"],
|
43
43
|
col_array_json: ENV["SPANNER_EMULATOR_HOST"] ? [""] : \
|
44
44
|
[{ kind: "user_renamed", change: %w[jack john]}, nil, \
|
45
|
-
{ kind: "user_renamed", change: %w[alice meredith]}
|
45
|
+
{ kind: "user_renamed", change: %w[alice meredith]},
|
46
|
+
"{\"kind\":\"user_renamed\",\"change\":[\"bob\",\"carol\"]}"]
|
46
47
|
end
|
47
48
|
|
48
49
|
def test_create_record
|
@@ -69,20 +70,21 @@ module ActiveRecord
|
|
69
70
|
record.col_json unless ENV["SPANNER_EMULATOR_HOST"]
|
70
71
|
|
71
72
|
assert_equal ["string1", nil, "string2"], record.col_array_string
|
72
|
-
assert_equal [100, nil, 200], record.col_array_int64
|
73
|
-
assert_equal [3.14, nil, 2.0/3.0], record.col_array_float64
|
74
|
-
assert_equal [6.626, nil, 3.20], record.col_array_numeric
|
75
|
-
assert_equal [true, nil, false], record.col_array_bool
|
73
|
+
assert_equal [100, nil, 200, 300], record.col_array_int64
|
74
|
+
assert_equal [3.14, nil, 2.0/3.0, 3.14], record.col_array_float64
|
75
|
+
assert_equal [6.626, nil, 3.20, 400], record.col_array_numeric
|
76
|
+
assert_equal [true, nil, false, false], record.col_array_bool
|
76
77
|
assert_equal [StringIO.new("bytes1"), nil, StringIO.new("bytes2")].map { |bytes| bytes&.read },
|
77
78
|
record.col_array_bytes.map { |bytes| bytes&.read }
|
78
|
-
assert_equal [::Date.new(2021, 6, 23), nil, ::Date.new(2021, 6, 24)], record.col_array_date
|
79
|
+
assert_equal [::Date.new(2021, 6, 23), nil, ::Date.new(2021, 6, 24), ::Date.new(2021, 06, 25)], record.col_array_date
|
79
80
|
assert_equal [::Time.new(2021, 6, 23, 17, 8, 21, "+02:00"), \
|
80
81
|
nil, \
|
81
|
-
::Time.new(2021, 6, 24, 17, 8, 21, "+02:00")].map { |timestamp| timestamp&.utc },
|
82
|
+
::Time.new(2021, 6, 24, 17, 8, 21, "+02:00"), ::Time.new(2021, 6, 25, 17, 8, 21, "+02:00")].map { |timestamp| timestamp&.utc },
|
82
83
|
record.col_array_timestamp.map { |timestamp| timestamp&.utc}
|
83
84
|
assert_equal [{"kind" => "user_renamed", "change" => %w[jack john]}, \
|
84
85
|
nil, \
|
85
|
-
{"kind" => "user_renamed", "change" => %w[alice meredith]}
|
86
|
+
{"kind" => "user_renamed", "change" => %w[alice meredith]},
|
87
|
+
{"kind" => "user_renamed", "change" => %w[bob carol]}],
|
86
88
|
record.col_array_json unless ENV["SPANNER_EMULATOR_HOST"]
|
87
89
|
end
|
88
90
|
end
|
data/examples/rails/README.md
CHANGED
@@ -99,7 +99,7 @@ If you are not familiar with Active Record, you can read more about it on [Ruby
|
|
99
99
|
### Use Cloud Spanner adapter in Gemfile
|
100
100
|
1. Edit the Gemfile file of the `blog` app and add the `activerecord-spanner-adapter` gem:
|
101
101
|
```ruby
|
102
|
-
gem 'activerecord-spanner-adapter'
|
102
|
+
gem 'activerecord-spanner-adapter'
|
103
103
|
```
|
104
104
|
1. Install gems:
|
105
105
|
|
@@ -142,17 +142,17 @@ Replace `[PROJECT_ID]` with the project id you are currently using.
|
|
142
142
|
### Create database
|
143
143
|
|
144
144
|
You now can run the following command to create the database:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
145
|
+
|
146
|
+
```shell
|
147
|
+
./bin/rails db:create
|
148
|
+
```
|
149
|
+
|
150
|
+
You should see output like the following: `Created database 'blog_dev'`
|
151
|
+
|
152
152
|
### Generate a Model and apply the migration
|
153
153
|
1. Use the model generato to define a model:
|
154
154
|
```shell
|
155
|
-
bin/rails generate model Article title:string body:text
|
155
|
+
./bin/rails generate model Article title:string body:text
|
156
156
|
```
|
157
157
|
1. Apply the migration:
|
158
158
|
```shell
|
@@ -2,8 +2,8 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
# This file is the source Rails uses to define your schema when running `rails
|
6
|
-
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
7
|
# be faster and is potentially less error prone than running all of your
|
8
8
|
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
9
|
# migrations use external dependencies or application code.
|
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
ActiveRecord::Schema.define(version: 1) do
|
14
14
|
|
15
|
-
create_table "singers", force: :cascade do |t|
|
15
|
+
create_table "singers", id: { limit: 8 }, force: :cascade do |t|
|
16
16
|
t.string "first_name", limit: 100
|
17
17
|
t.string "last_name", limit: 200, null: false
|
18
18
|
t.string "full_name", limit: 300, null: false
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Sample - Query Hints
|
2
|
+
|
3
|
+
This example shows how to use query hints Spanner ActiveRecord adapter. Statement hints and
|
4
|
+
table hints can be specified using the optimizer_hints method. Join hints must be specified
|
5
|
+
in a join string.
|
6
|
+
|
7
|
+
See https://cloud.google.com/spanner/docs/query-syntax#sql_syntax for more information on
|
8
|
+
the supported query hints.
|
9
|
+
|
10
|
+
## Running the Sample
|
11
|
+
|
12
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
13
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
14
|
+
|
15
|
+
Run the application with the command
|
16
|
+
|
17
|
+
```bash
|
18
|
+
bundle exec rake run
|
19
|
+
```
|
@@ -7,7 +7,7 @@
|
|
7
7
|
require_relative "../config/environment"
|
8
8
|
require "sinatra/activerecord/rake"
|
9
9
|
|
10
|
-
desc "Sample showing how to work with
|
10
|
+
desc "Sample showing how to work with generated columns in ActiveRecord."
|
11
11
|
task :run do
|
12
|
-
Dir.chdir("..") { sh "bundle exec rake run[
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[hints]" }
|
13
13
|
end
|
@@ -0,0 +1,47 @@
|
|
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 "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
|
14
|
+
puts ""
|
15
|
+
puts "Listing all singers using additional parallelism:"
|
16
|
+
# A statement hint must be prefixed with 'statement_hint:'
|
17
|
+
Singer.optimizer_hints("statement_hint: @{USE_ADDITIONAL_PARALLELISM=TRUE}")
|
18
|
+
.order("last_name, first_name").each do |singer|
|
19
|
+
puts singer.full_name
|
20
|
+
end
|
21
|
+
|
22
|
+
puts ""
|
23
|
+
puts "Listing all singers using the index on full_name:"
|
24
|
+
# All table hints must be prefixed with 'table_hint:'.
|
25
|
+
# Queries may contain multiple table hints.
|
26
|
+
Singer.optimizer_hints("table_hint: singers@{FORCE_INDEX=index_singers_on_full_name}")
|
27
|
+
.order("full_name").each do |singer|
|
28
|
+
puts singer.full_name
|
29
|
+
end
|
30
|
+
|
31
|
+
puts ""
|
32
|
+
puts "Listing all singers with at least one album that starts with 'blue':"
|
33
|
+
# Join hints cannot be specified using an optimizer_hint. Instead, the join can
|
34
|
+
# be specified using a string that includes the join hint.
|
35
|
+
Singer.joins("INNER JOIN @{JOIN_METHOD=HASH_JOIN} albums " \
|
36
|
+
"on singers.id=albums.singer_id AND albums.title LIKE 'blue%'")
|
37
|
+
.distinct.order("last_name, first_name").each do |singer|
|
38
|
+
puts singer.full_name
|
39
|
+
end
|
40
|
+
|
41
|
+
puts ""
|
42
|
+
puts "Press any key to end the application"
|
43
|
+
STDIN.getch
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Application.run
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
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, limit: 100
|
12
|
+
t.string :last_name, limit: 200, null: false
|
13
|
+
t.string :full_name, limit: 300, null: false, as: "COALESCE(first_name || ' ', '') || last_name", stored: true
|
14
|
+
t.index [:full_name], name: "index_singers_on_full_name"
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :albums do |t|
|
18
|
+
t.string :title
|
19
|
+
t.references :singer, index: false, foreign_key: true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
# This file is the source Rails uses to define your schema when running `rails
|
6
|
-
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
7
|
# be faster and is potentially less error prone than running all of your
|
8
8
|
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
9
|
# migrations use external dependencies or application code.
|
@@ -12,21 +12,17 @@
|
|
12
12
|
|
13
13
|
ActiveRecord::Schema.define(version: 1) do
|
14
14
|
|
15
|
-
create_table "albums",
|
16
|
-
t.integer "singerid", limit: 8, null: false
|
15
|
+
create_table "albums", id: { limit: 8 }, force: :cascade do |t|
|
17
16
|
t.string "title"
|
17
|
+
t.integer "singer_id", limit: 8
|
18
18
|
end
|
19
19
|
|
20
|
-
create_table "singers",
|
21
|
-
t.string "first_name"
|
22
|
-
t.string "last_name"
|
23
|
-
|
24
|
-
|
25
|
-
create_table "tracks", primary_key: "trackid", force: :cascade do |t|
|
26
|
-
t.integer "singerid", limit: 8, null: false
|
27
|
-
t.integer "albumid", limit: 8, null: false
|
28
|
-
t.string "title"
|
29
|
-
t.decimal "duration"
|
20
|
+
create_table "singers", id: { limit: 8 }, force: :cascade do |t|
|
21
|
+
t.string "first_name", limit: 100
|
22
|
+
t.string "last_name", limit: 200, null: false
|
23
|
+
t.string "full_name", limit: 300, null: false
|
24
|
+
t.index ["full_name"], name: "index_singers_on_full_name", order: { full_name: :asc }
|
30
25
|
end
|
31
26
|
|
27
|
+
add_foreign_key "albums", "singers"
|
32
28
|
end
|
@@ -7,7 +7,6 @@
|
|
7
7
|
require_relative "../../config/environment.rb"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
|
-
require_relative "../models/track"
|
11
10
|
|
12
11
|
first_names = %w[Pete Alice John Ethel Trudy Naomi Wendy Ruben Thomas Elly]
|
13
12
|
last_names = %w[Wendelson Allison Peterson Johnson Henderson Ericsson Aronson Tennet Courtou]
|
@@ -15,11 +14,6 @@ last_names = %w[Wendelson Allison Peterson Johnson Henderson Ericsson Aronson Te
|
|
15
14
|
adjectives = %w[daily happy blue generous cooked bad open]
|
16
15
|
nouns = %w[windows potatoes bank street tree glass bottle]
|
17
16
|
|
18
|
-
verbs = %w[operate waste package chew yield express polish stress slip want cough campaign cultivate report park refer]
|
19
|
-
adverbs = %w[directly right hopefully personally economically privately supposedly consequently fully later urgently]
|
20
|
-
|
21
|
-
durations = [3.14, 5.4, 3.3, 4.1, 5.0, 3.2, 3.0, 3.5, 4.0, 4.5, 5.5, 6.0]
|
22
|
-
|
23
17
|
# This ensures all the records are inserted using one read/write transaction that will use mutations instead of DML.
|
24
18
|
ActiveRecord::Base.transaction isolation: :buffered_mutations do
|
25
19
|
singers = []
|
@@ -32,9 +26,4 @@ ActiveRecord::Base.transaction isolation: :buffered_mutations do
|
|
32
26
|
singer = singers.sample
|
33
27
|
albums << Album.create(title: "#{adjectives.sample} #{nouns.sample}", singer: singer)
|
34
28
|
end
|
35
|
-
|
36
|
-
200.times do
|
37
|
-
album = albums.sample
|
38
|
-
Track.create title: "#{verbs.sample} #{adverbs.sample}", duration: durations.sample, album: album
|
39
|
-
end
|
40
29
|
end
|