activerecord-spanner-adapter 0.3.0 → 1.0.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 +5 -5
- data/.github/CODEOWNERS +7 -0
- data/.github/sync-repo-settings.yaml +16 -0
- data/.github/workflows/acceptance-tests-on-emulator.yaml +45 -0
- data/.github/workflows/acceptance-tests-on-production.yaml +49 -0
- data/.github/workflows/ci.yaml +33 -0
- data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +52 -0
- data/.github/workflows/nightly-acceptance-tests-on-production.yaml +35 -0
- data/.github/workflows/nightly-unit-tests.yaml +40 -0
- data/.github/workflows/release-please-label.yml +25 -0
- data/.github/workflows/release-please.yml +39 -0
- data/.github/workflows/rubocop.yaml +31 -0
- data/.gitignore +67 -5
- data/.kokoro/populate-secrets.sh +77 -0
- data/.kokoro/release.cfg +33 -0
- data/.kokoro/release.sh +15 -0
- data/.kokoro/trampoline_v2.sh +489 -0
- data/.rubocop.yml +46 -0
- data/.toys/release.rb +18 -0
- data/.trampolinerc +48 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +55 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +9 -4
- data/LICENSE +6 -6
- data/README.md +66 -30
- data/Rakefile +79 -3
- data/SECURITY.md +7 -0
- data/acceptance/cases/associations/has_many_associations_test.rb +119 -0
- data/acceptance/cases/associations/has_many_through_associations_test.rb +63 -0
- data/acceptance/cases/associations/has_one_associations_test.rb +79 -0
- data/acceptance/cases/associations/has_one_through_associations_test.rb +98 -0
- data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb +211 -0
- data/acceptance/cases/migration/change_schema_test.rb +433 -0
- data/acceptance/cases/migration/change_table_test.rb +115 -0
- data/acceptance/cases/migration/column_attributes_test.rb +122 -0
- data/acceptance/cases/migration/column_positioning_test.rb +48 -0
- data/acceptance/cases/migration/columns_test.rb +201 -0
- data/acceptance/cases/migration/command_recorder_test.rb +406 -0
- data/acceptance/cases/migration/create_join_table_test.rb +216 -0
- data/acceptance/cases/migration/ddl_batching_test.rb +80 -0
- data/acceptance/cases/migration/foreign_key_test.rb +297 -0
- data/acceptance/cases/migration/index_test.rb +211 -0
- data/acceptance/cases/migration/references_foreign_key_test.rb +259 -0
- data/acceptance/cases/migration/references_index_test.rb +135 -0
- data/acceptance/cases/migration/references_statements_test.rb +166 -0
- data/acceptance/cases/migration/rename_column_test.rb +96 -0
- data/acceptance/cases/models/calculation_query_test.rb +128 -0
- data/acceptance/cases/models/generated_column_test.rb +126 -0
- data/acceptance/cases/models/mutation_test.rb +122 -0
- data/acceptance/cases/models/query_test.rb +171 -0
- data/acceptance/cases/sessions/session_not_found_test.rb +121 -0
- data/acceptance/cases/transactions/optimistic_locking_test.rb +141 -0
- data/acceptance/cases/transactions/read_only_transactions_test.rb +130 -0
- data/acceptance/cases/transactions/read_write_transactions_test.rb +248 -0
- data/acceptance/cases/type/all_types_test.rb +172 -0
- data/acceptance/cases/type/binary_test.rb +59 -0
- data/acceptance/cases/type/boolean_test.rb +31 -0
- data/acceptance/cases/type/date_test.rb +32 -0
- data/acceptance/cases/type/date_time_test.rb +30 -0
- data/acceptance/cases/type/float_test.rb +27 -0
- data/acceptance/cases/type/integer_test.rb +44 -0
- data/acceptance/cases/type/json_test.rb +34 -0
- data/acceptance/cases/type/numeric_test.rb +27 -0
- data/acceptance/cases/type/string_test.rb +79 -0
- data/acceptance/cases/type/text_test.rb +30 -0
- data/acceptance/cases/type/time_test.rb +87 -0
- data/acceptance/models/account.rb +13 -0
- data/acceptance/models/address.rb +9 -0
- data/acceptance/models/album.rb +12 -0
- data/acceptance/models/all_types.rb +8 -0
- data/acceptance/models/author.rb +11 -0
- data/acceptance/models/club.rb +12 -0
- data/acceptance/models/comment.rb +9 -0
- data/acceptance/models/customer.rb +9 -0
- data/acceptance/models/department.rb +9 -0
- data/acceptance/models/firm.rb +10 -0
- data/acceptance/models/member.rb +13 -0
- data/acceptance/models/member_type.rb +9 -0
- data/acceptance/models/membership.rb +10 -0
- data/acceptance/models/organization.rb +9 -0
- data/acceptance/models/post.rb +10 -0
- data/acceptance/models/singer.rb +10 -0
- data/acceptance/models/track.rb +20 -0
- data/acceptance/models/transaction.rb +9 -0
- data/acceptance/schema/schema.rb +147 -0
- data/acceptance/test_helper.rb +261 -0
- data/activerecord-spanner-adapter.gemspec +32 -17
- data/assets/solidus-db.png +0 -0
- data/benchmarks/README.md +17 -0
- data/benchmarks/Rakefile +14 -0
- data/benchmarks/application.rb +308 -0
- data/benchmarks/config/database.yml +8 -0
- data/benchmarks/config/environment.rb +12 -0
- data/benchmarks/db/migrate/01_create_tables.rb +25 -0
- data/benchmarks/db/schema.rb +29 -0
- data/benchmarks/models/album.rb +9 -0
- data/benchmarks/models/singer.rb +9 -0
- data/bin/console +6 -7
- data/examples/rails/README.md +262 -0
- data/examples/snippets/README.md +29 -0
- data/examples/snippets/Rakefile +57 -0
- data/examples/snippets/array-data-type/README.md +45 -0
- data/examples/snippets/array-data-type/Rakefile +13 -0
- data/examples/snippets/array-data-type/application.rb +45 -0
- data/examples/snippets/array-data-type/config/database.yml +8 -0
- data/examples/snippets/array-data-type/db/migrate/01_create_tables.rb +24 -0
- data/examples/snippets/array-data-type/db/schema.rb +26 -0
- data/examples/snippets/array-data-type/db/seeds.rb +5 -0
- data/examples/snippets/array-data-type/models/entity_with_array_types.rb +18 -0
- data/examples/snippets/bin/create_emulator_instance.rb +18 -0
- data/examples/snippets/bulk-insert/README.md +21 -0
- data/examples/snippets/bulk-insert/Rakefile +13 -0
- data/examples/snippets/bulk-insert/application.rb +64 -0
- data/examples/snippets/bulk-insert/config/database.yml +8 -0
- data/examples/snippets/bulk-insert/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/bulk-insert/db/schema.rb +26 -0
- data/examples/snippets/bulk-insert/db/seeds.rb +5 -0
- data/examples/snippets/bulk-insert/models/album.rb +9 -0
- data/examples/snippets/bulk-insert/models/singer.rb +9 -0
- data/examples/snippets/commit-timestamp/README.md +18 -0
- data/examples/snippets/commit-timestamp/Rakefile +13 -0
- data/examples/snippets/commit-timestamp/application.rb +53 -0
- data/examples/snippets/commit-timestamp/config/database.yml +8 -0
- data/examples/snippets/commit-timestamp/db/migrate/01_create_tables.rb +26 -0
- data/examples/snippets/commit-timestamp/db/schema.rb +29 -0
- data/examples/snippets/commit-timestamp/db/seeds.rb +5 -0
- data/examples/snippets/commit-timestamp/models/album.rb +9 -0
- data/examples/snippets/commit-timestamp/models/singer.rb +9 -0
- data/examples/snippets/config/environment.rb +21 -0
- data/examples/snippets/create-records/README.md +12 -0
- data/examples/snippets/create-records/Rakefile +13 -0
- data/examples/snippets/create-records/application.rb +42 -0
- data/examples/snippets/create-records/config/database.yml +8 -0
- data/examples/snippets/create-records/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/create-records/db/schema.rb +26 -0
- data/examples/snippets/create-records/db/seeds.rb +5 -0
- data/examples/snippets/create-records/models/album.rb +9 -0
- data/examples/snippets/create-records/models/singer.rb +9 -0
- data/examples/snippets/date-data-type/README.md +19 -0
- data/examples/snippets/date-data-type/Rakefile +13 -0
- data/examples/snippets/date-data-type/application.rb +35 -0
- data/examples/snippets/date-data-type/config/database.yml +8 -0
- data/examples/snippets/date-data-type/db/migrate/01_create_tables.rb +20 -0
- data/examples/snippets/date-data-type/db/schema.rb +21 -0
- data/examples/snippets/date-data-type/db/seeds.rb +16 -0
- data/examples/snippets/date-data-type/models/singer.rb +8 -0
- data/examples/snippets/generated-column/README.md +41 -0
- data/examples/snippets/generated-column/Rakefile +13 -0
- data/examples/snippets/generated-column/application.rb +37 -0
- data/examples/snippets/generated-column/config/database.yml +8 -0
- data/examples/snippets/generated-column/db/migrate/01_create_tables.rb +23 -0
- data/examples/snippets/generated-column/db/schema.rb +21 -0
- data/examples/snippets/generated-column/db/seeds.rb +18 -0
- data/examples/snippets/generated-column/models/singer.rb +8 -0
- data/examples/snippets/hints/README.md +19 -0
- data/examples/snippets/hints/Rakefile +13 -0
- data/examples/snippets/hints/application.rb +47 -0
- data/examples/snippets/hints/config/database.yml +8 -0
- data/examples/snippets/hints/db/migrate/01_create_tables.rb +23 -0
- data/examples/snippets/hints/db/schema.rb +28 -0
- data/examples/snippets/hints/db/seeds.rb +29 -0
- data/examples/snippets/hints/models/album.rb +9 -0
- data/examples/snippets/hints/models/singer.rb +9 -0
- data/examples/snippets/migrations/README.md +43 -0
- data/examples/snippets/migrations/Rakefile +13 -0
- data/examples/snippets/migrations/application.rb +26 -0
- data/examples/snippets/migrations/config/database.yml +8 -0
- data/examples/snippets/migrations/db/migrate/01_create_tables.rb +28 -0
- data/examples/snippets/migrations/db/schema.rb +33 -0
- data/examples/snippets/migrations/db/seeds.rb +5 -0
- data/examples/snippets/migrations/models/album.rb +10 -0
- data/examples/snippets/migrations/models/singer.rb +10 -0
- data/examples/snippets/migrations/models/track.rb +9 -0
- data/examples/snippets/mutations/README.md +34 -0
- data/examples/snippets/mutations/Rakefile +13 -0
- data/examples/snippets/mutations/application.rb +47 -0
- data/examples/snippets/mutations/config/database.yml +8 -0
- data/examples/snippets/mutations/db/migrate/01_create_tables.rb +22 -0
- data/examples/snippets/mutations/db/schema.rb +27 -0
- data/examples/snippets/mutations/db/seeds.rb +25 -0
- data/examples/snippets/mutations/models/album.rb +9 -0
- data/examples/snippets/mutations/models/singer.rb +9 -0
- data/examples/snippets/optimistic-locking/README.md +12 -0
- data/examples/snippets/optimistic-locking/Rakefile +13 -0
- data/examples/snippets/optimistic-locking/application.rb +48 -0
- data/examples/snippets/optimistic-locking/config/database.yml +8 -0
- data/examples/snippets/optimistic-locking/db/migrate/01_create_tables.rb +26 -0
- data/examples/snippets/optimistic-locking/db/schema.rb +29 -0
- data/examples/snippets/optimistic-locking/db/seeds.rb +25 -0
- data/examples/snippets/optimistic-locking/models/album.rb +9 -0
- data/examples/snippets/optimistic-locking/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/examples/snippets/quickstart/README.md +26 -0
- data/examples/snippets/quickstart/Rakefile +13 -0
- data/examples/snippets/quickstart/application.rb +51 -0
- data/examples/snippets/quickstart/config/database.yml +8 -0
- data/examples/snippets/quickstart/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/quickstart/db/schema.rb +26 -0
- data/examples/snippets/quickstart/db/seeds.rb +24 -0
- data/examples/snippets/quickstart/models/album.rb +9 -0
- data/examples/snippets/quickstart/models/singer.rb +9 -0
- data/examples/snippets/read-only-transactions/README.md +13 -0
- data/examples/snippets/read-only-transactions/Rakefile +13 -0
- data/examples/snippets/read-only-transactions/application.rb +77 -0
- data/examples/snippets/read-only-transactions/config/database.yml +8 -0
- data/examples/snippets/read-only-transactions/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/read-only-transactions/db/schema.rb +26 -0
- data/examples/snippets/read-only-transactions/db/seeds.rb +24 -0
- data/examples/snippets/read-only-transactions/models/album.rb +9 -0
- data/examples/snippets/read-only-transactions/models/singer.rb +9 -0
- data/examples/snippets/read-write-transactions/README.md +12 -0
- data/examples/snippets/read-write-transactions/Rakefile +13 -0
- data/examples/snippets/read-write-transactions/application.rb +39 -0
- data/examples/snippets/read-write-transactions/config/database.yml +8 -0
- data/examples/snippets/read-write-transactions/db/migrate/01_create_tables.rb +22 -0
- data/examples/snippets/read-write-transactions/db/schema.rb +27 -0
- data/examples/snippets/read-write-transactions/db/seeds.rb +25 -0
- data/examples/snippets/read-write-transactions/models/album.rb +9 -0
- data/examples/snippets/read-write-transactions/models/singer.rb +9 -0
- data/examples/snippets/stale-reads/README.md +27 -0
- data/examples/snippets/stale-reads/Rakefile +13 -0
- data/examples/snippets/stale-reads/application.rb +63 -0
- data/examples/snippets/stale-reads/config/database.yml +8 -0
- data/examples/snippets/stale-reads/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/stale-reads/db/schema.rb +26 -0
- data/examples/snippets/stale-reads/db/seeds.rb +24 -0
- data/examples/snippets/stale-reads/models/album.rb +9 -0
- data/examples/snippets/stale-reads/models/singer.rb +9 -0
- data/examples/snippets/timestamp-data-type/README.md +17 -0
- data/examples/snippets/timestamp-data-type/Rakefile +13 -0
- data/examples/snippets/timestamp-data-type/application.rb +42 -0
- data/examples/snippets/timestamp-data-type/config/database.yml +8 -0
- data/examples/snippets/timestamp-data-type/db/migrate/01_create_tables.rb +21 -0
- data/examples/snippets/timestamp-data-type/db/schema.rb +21 -0
- data/examples/snippets/timestamp-data-type/db/seeds.rb +6 -0
- data/examples/snippets/timestamp-data-type/models/meeting.rb +19 -0
- data/examples/solidus/README.md +172 -0
- data/lib/active_record/connection_adapters/spanner/database_statements.rb +244 -266
- data/lib/active_record/connection_adapters/spanner/quoting.rb +42 -50
- data/lib/active_record/connection_adapters/spanner/schema_cache.rb +43 -0
- data/lib/active_record/connection_adapters/spanner/schema_creation.rb +125 -9
- data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +122 -0
- data/lib/active_record/connection_adapters/spanner/schema_dumper.rb +19 -0
- data/lib/active_record/connection_adapters/spanner/schema_statements.rb +553 -139
- data/lib/active_record/connection_adapters/spanner/type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/spanner_adapter.rb +185 -78
- data/lib/active_record/tasks/spanner_database_tasks.rb +74 -0
- data/lib/active_record/type/spanner/array.rb +32 -0
- data/lib/active_record/type/spanner/bytes.rb +26 -0
- data/lib/active_record/type/spanner/spanner_active_record_converter.rb +33 -0
- data/lib/active_record/type/spanner/time.rb +37 -0
- data/lib/activerecord-spanner-adapter.rb +23 -0
- data/lib/activerecord_spanner_adapter/base.rb +238 -0
- data/lib/activerecord_spanner_adapter/connection.rb +350 -0
- data/lib/activerecord_spanner_adapter/errors.rb +13 -0
- data/lib/activerecord_spanner_adapter/foreign_key.rb +29 -0
- data/lib/activerecord_spanner_adapter/index/column.rb +38 -0
- data/lib/activerecord_spanner_adapter/index.rb +80 -0
- data/lib/activerecord_spanner_adapter/information_schema.rb +262 -0
- data/lib/activerecord_spanner_adapter/primary_key.rb +31 -0
- data/lib/activerecord_spanner_adapter/table/column.rb +59 -0
- data/lib/activerecord_spanner_adapter/table.rb +61 -0
- data/lib/activerecord_spanner_adapter/transaction.rb +154 -0
- data/lib/activerecord_spanner_adapter/version.rb +9 -0
- data/lib/arel/visitors/spanner.rb +111 -0
- data/lib/spanner_client_ext.rb +107 -0
- data/renovate.json +5 -0
- metadata +405 -34
- data/.travis.yml +0 -5
- data/lib/active_record/connection_adapters/spanner/client.rb +0 -190
- data/lib/active_record/connection_adapters/spanner.rb +0 -10
- data/lib/activerecord-spanner-adapter/version.rb +0 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
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
|
|
7
|
+
# be faster and is potentially less error prone than running all of your
|
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
9
|
+
# migrations use external dependencies or application code.
|
|
10
|
+
#
|
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
14
|
+
|
|
15
|
+
create_table "singers", force: :cascade do |t|
|
|
16
|
+
t.string "first_name"
|
|
17
|
+
t.string "last_name"
|
|
18
|
+
t.date "birth_date"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
#
|
|
7
|
+
require_relative "../../config/environment.rb"
|
|
8
|
+
require_relative "../models/singer"
|
|
9
|
+
|
|
10
|
+
first_names = %w[Nelson Todd William Alex Dominique Adenoid Steve Nathan Beverly Annie Amy Norma Diana Regan Phyllis]
|
|
11
|
+
last_names = %w[Thornton Morgan Lawson Collins Frost Maxwell Sanders Fleming Jones Webb Walker French Montgomery Quinn]
|
|
12
|
+
|
|
13
|
+
30.times do
|
|
14
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample,
|
|
15
|
+
birth_date: Date.new(rand(1920...2010), rand(1...12), rand(1...28))
|
|
16
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Sample - Generated Columns
|
|
2
|
+
|
|
3
|
+
This example shows how to use generated columns with the Spanner ActiveRecord adapter.
|
|
4
|
+
|
|
5
|
+
See https://cloud.google.com/spanner/docs/generated-column/how-to for more information on generated columns.
|
|
6
|
+
|
|
7
|
+
This example uses the following table schema:
|
|
8
|
+
|
|
9
|
+
```sql
|
|
10
|
+
CREATE TABLE singers (
|
|
11
|
+
id INT64 NOT NULL,
|
|
12
|
+
first_name STRING(100),
|
|
13
|
+
last_name STRING(200) NOT NULL,
|
|
14
|
+
full_name STRING(300) NOT NULL AS (COALESCE(first_name || ' ', '') || last_name) STORED,
|
|
15
|
+
) PRIMARY KEY (id);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This schema can be created in ActiveRecord as follows:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
create_table :singers do |t|
|
|
22
|
+
t.string :first_name, limit: 100
|
|
23
|
+
t.string :last_name, limit: 200, null: false
|
|
24
|
+
t.string :full_name, limit: 300, null: false, as: "COALESCE(first_name || ' ', '') || last_name", stored: true
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The `full_name` attribute will automatically be set by Cloud Spanner, and it is not allowed to set a value for the
|
|
29
|
+
attribute when creating a record in ActiveRecord, or to update the value of an existing record. Instead, only the
|
|
30
|
+
`first_name` and `last_name` attributes should be set.
|
|
31
|
+
|
|
32
|
+
## Running the Sample
|
|
33
|
+
|
|
34
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
35
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
36
|
+
|
|
37
|
+
Run the application with the command
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bundle exec rake run
|
|
41
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
|
|
7
|
+
require_relative "../config/environment"
|
|
8
|
+
require "sinatra/activerecord/rake"
|
|
9
|
+
|
|
10
|
+
desc "Sample showing how to work with generated columns in ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[generated-column]" }
|
|
13
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
|
|
11
|
+
class Application
|
|
12
|
+
def self.run
|
|
13
|
+
puts ""
|
|
14
|
+
puts "Listing all singers:"
|
|
15
|
+
Singer.all.order("last_name, first_name").each do |singer|
|
|
16
|
+
puts singer.full_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Create a new singer and print out the full name.
|
|
20
|
+
singer = Singer.create first_name: "Alice", last_name: "Rees"
|
|
21
|
+
singer.reload
|
|
22
|
+
puts ""
|
|
23
|
+
puts "Singer created: #{singer.full_name}"
|
|
24
|
+
|
|
25
|
+
# Update the last name of the singer and print out the full name.
|
|
26
|
+
singer.update last_name: "Rees-Goodwin"
|
|
27
|
+
singer.reload
|
|
28
|
+
puts ""
|
|
29
|
+
puts "Singer updated: #{singer.full_name}"
|
|
30
|
+
|
|
31
|
+
puts ""
|
|
32
|
+
puts "Press any key to end the application"
|
|
33
|
+
STDIN.getch
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Application.run
|
|
@@ -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
|
+
|
|
14
|
+
# Create a generated column that contains the full name of the singer. This will be the concatenated first name
|
|
15
|
+
# and last name of the singer, or only the last name if the first name is null. The `as` keyword is what
|
|
16
|
+
# instructs the Spanner ActiveRecord adapter to create a generated column. Note the `stored` option that is set
|
|
17
|
+
# to true. This is required, as Cloud Spanner (currently) does not support non-stored generated columns.
|
|
18
|
+
# See also https://cloud.google.com/spanner/docs/generated-column/how-to for more information.
|
|
19
|
+
t.string :full_name, limit: 300, null: false, as: "COALESCE(first_name || ' ', '') || last_name", stored: true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
4
|
+
#
|
|
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
|
+
# be faster and is potentially less error prone than running all of your
|
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
9
|
+
# migrations use external dependencies or application code.
|
|
10
|
+
#
|
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
14
|
+
|
|
15
|
+
create_table "singers", id: { limit: 8 }, force: :cascade do |t|
|
|
16
|
+
t.string "first_name", limit: 100
|
|
17
|
+
t.string "last_name", limit: 200, null: false
|
|
18
|
+
t.string "full_name", limit: 300, null: false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
|
|
7
|
+
require_relative "../../config/environment.rb"
|
|
8
|
+
require_relative "../models/singer"
|
|
9
|
+
|
|
10
|
+
first_names = %w[Pete Alice John Ethel Trudy Naomi Wendy Ruben Thomas Elly]
|
|
11
|
+
last_names = %w[Wendelson Allison Peterson Johnson Henderson Ericsson Aronson Tennet Courtou]
|
|
12
|
+
|
|
13
|
+
# This ensures all the records are inserted using one read/write transaction that will use mutations instead of DML.
|
|
14
|
+
ActiveRecord::Base.transaction isolation: :buffered_mutations do
|
|
15
|
+
10.times do
|
|
16
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
|
|
7
|
+
require_relative "../config/environment"
|
|
8
|
+
require "sinatra/activerecord/rake"
|
|
9
|
+
|
|
10
|
+
desc "Sample showing how to work with generated columns in ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[hints]" }
|
|
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
|
|
@@ -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
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
4
|
+
#
|
|
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
|
+
# be faster and is potentially less error prone than running all of your
|
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
9
|
+
# migrations use external dependencies or application code.
|
|
10
|
+
#
|
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
14
|
+
|
|
15
|
+
create_table "albums", id: { limit: 8 }, force: :cascade do |t|
|
|
16
|
+
t.string "title"
|
|
17
|
+
t.integer "singer_id", limit: 8
|
|
18
|
+
end
|
|
19
|
+
|
|
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 }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
add_foreign_key "albums", "singers"
|
|
28
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
|
|
7
|
+
require_relative "../../config/environment.rb"
|
|
8
|
+
require_relative "../models/singer"
|
|
9
|
+
require_relative "../models/album"
|
|
10
|
+
|
|
11
|
+
first_names = %w[Pete Alice John Ethel Trudy Naomi Wendy Ruben Thomas Elly]
|
|
12
|
+
last_names = %w[Wendelson Allison Peterson Johnson Henderson Ericsson Aronson Tennet Courtou]
|
|
13
|
+
|
|
14
|
+
adjectives = %w[daily happy blue generous cooked bad open]
|
|
15
|
+
nouns = %w[windows potatoes bank street tree glass bottle]
|
|
16
|
+
|
|
17
|
+
# This ensures all the records are inserted using one read/write transaction that will use mutations instead of DML.
|
|
18
|
+
ActiveRecord::Base.transaction isolation: :buffered_mutations do
|
|
19
|
+
singers = []
|
|
20
|
+
5.times do
|
|
21
|
+
singers << Singer.create(first_name: first_names.sample, last_name: last_names.sample)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
albums = []
|
|
25
|
+
20.times do
|
|
26
|
+
singer = singers.sample
|
|
27
|
+
albums << Album.create(title: "#{adjectives.sample} #{nouns.sample}", singer: singer)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Sample - Migrations
|
|
2
|
+
|
|
3
|
+
This example shows the best way to execute migrations with the Spanner ActiveRecord adapter.
|
|
4
|
+
|
|
5
|
+
It is [strongly recommended](https://cloud.google.com/spanner/docs/schema-updates#best-practices) that you limit the
|
|
6
|
+
frequency of schema updates in Cloud Spanner, and that schema changes are batched together whenever possible. The
|
|
7
|
+
Spanner ActiveRecord adapter supports batching DDL statements together using the `connection.ddl_batch` method. This
|
|
8
|
+
method accepts a block of DDL statements that will be sent to Cloud Spanner as one batch. It is recommended that
|
|
9
|
+
migrations are grouped together in one or in a limited number of batches for optimal performance.
|
|
10
|
+
|
|
11
|
+
This example shows how to create three tables in one batch:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
# Execute the entire migration as one DDL batch.
|
|
15
|
+
connection.ddl_batch do
|
|
16
|
+
create_table :singers do |t|
|
|
17
|
+
t.string :first_name
|
|
18
|
+
t.string :last_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table :albums do |t|
|
|
22
|
+
t.string :title
|
|
23
|
+
t.references :singers
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
create_table :tracks do |t|
|
|
27
|
+
t.string :title
|
|
28
|
+
t.numeric :duration
|
|
29
|
+
t.references :albums
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Running the Sample
|
|
35
|
+
|
|
36
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
37
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
38
|
+
|
|
39
|
+
Run the application with the command
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bundle exec rake run
|
|
43
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2021 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Use of this source code is governed by an MIT-style
|
|
4
|
+
# license that can be found in the LICENSE file or at
|
|
5
|
+
# https://opensource.org/licenses/MIT.
|
|
6
|
+
|
|
7
|
+
require_relative "../config/environment"
|
|
8
|
+
require "sinatra/activerecord/rake"
|
|
9
|
+
|
|
10
|
+
desc "Sample showing the best practice for executing migrations (schema updates) on Cloud Spanner in ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[migrations]" }
|
|
13
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
|
|
10
|
+
class Application
|
|
11
|
+
def self.run
|
|
12
|
+
puts ""
|
|
13
|
+
puts "Created database with the following tables:"
|
|
14
|
+
sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='' AND TABLE_SCHEMA=''"
|
|
15
|
+
tables = ActiveRecord::Base.connection.raw_connection.execute_query sql
|
|
16
|
+
tables.rows.each do |row|
|
|
17
|
+
puts row[:TABLE_NAME]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
puts ""
|
|
21
|
+
puts "Press any key to end the application"
|
|
22
|
+
STDIN.getch
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Application.run
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
# Execute the entire migration as one DDL batch.
|
|
10
|
+
connection.ddl_batch do
|
|
11
|
+
create_table :singers do |t|
|
|
12
|
+
t.string :first_name
|
|
13
|
+
t.string :last_name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
create_table :albums do |t|
|
|
17
|
+
t.string :title
|
|
18
|
+
t.references :singers
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table :tracks do |t|
|
|
22
|
+
t.string :title
|
|
23
|
+
t.numeric :duration
|
|
24
|
+
t.references :albums
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
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
|
|
7
|
+
# be faster and is potentially less error prone than running all of your
|
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
9
|
+
# migrations use external dependencies or application code.
|
|
10
|
+
#
|
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
14
|
+
|
|
15
|
+
create_table "albums", force: :cascade do |t|
|
|
16
|
+
t.string "title"
|
|
17
|
+
t.integer "singers_id", limit: 8
|
|
18
|
+
t.index ["singers_id"], name: "index_albums_on_singers_id", order: { singers_id: :asc }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table "singers", force: :cascade do |t|
|
|
22
|
+
t.string "first_name"
|
|
23
|
+
t.string "last_name"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
create_table "tracks", force: :cascade do |t|
|
|
27
|
+
t.string "title"
|
|
28
|
+
t.decimal "duration"
|
|
29
|
+
t.integer "albums_id", limit: 8
|
|
30
|
+
t.index ["albums_id"], name: "index_tracks_on_albums_id", order: { albums_id: :asc }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
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 Album < ActiveRecord::Base
|
|
8
|
+
belongs_to :singer
|
|
9
|
+
has_many :tracks
|
|
10
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
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 Singer < ActiveRecord::Base
|
|
8
|
+
has_many :albums
|
|
9
|
+
has_many :tracks, through: :albums
|
|
10
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Sample - Mutations
|
|
2
|
+
|
|
3
|
+
Writing data to a Cloud Spanner database can be done using two different features:
|
|
4
|
+
* Data Modification Language (DML)
|
|
5
|
+
* Mutations
|
|
6
|
+
|
|
7
|
+
Changes that are written using DML can be read back during the same read/write transaction. Changes that are
|
|
8
|
+
written using Mutations are however buffered locally in the client and only sent to Cloud Spanner when the
|
|
9
|
+
transaction is committed. Mutations are therefore not readable during the same read/write transaction. The
|
|
10
|
+
Spanner ActiveRecord adapter will use DML by default when modifications are made during a read/write transaction.
|
|
11
|
+
Mutations can however be executed more efficiently by Cloud Spanner, which can significantly reduce the execution
|
|
12
|
+
time for read/write transactions that modify a large number of records. The Spanner ActiveRecord adapter will
|
|
13
|
+
therefore use Mutations in the following cases:
|
|
14
|
+
|
|
15
|
+
1. No explicit transaction block: When entities are modified outside of an explicit transaction block, ActiveRecord
|
|
16
|
+
will automatically create an implicit transaction and save the data to the database. This means that the data can
|
|
17
|
+
never be read back during the same transaction. The Spanner ActiveRecord adapter recognizes this situation and
|
|
18
|
+
automatically switches to using Mutations for these transactions to optimize the execution speed.
|
|
19
|
+
2. Using a custom isolation level: The Spanner ActiveRecord adapter supports the custom isolation level
|
|
20
|
+
`:buffered_mutations` that will instruct the underlying Spanner transaction to use Mutations instead
|
|
21
|
+
of DML for all data operations in the transaction that can be executed using Mutations. Transactions with this
|
|
22
|
+
isolation level do not support read-your-writes.
|
|
23
|
+
|
|
24
|
+
This sample shows how to use the `:buffered_mutations` isolation level to instruct the Spanner ActiveRecord
|
|
25
|
+
adapter to use mutations instead of DML during a transaction.
|
|
26
|
+
|
|
27
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
28
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
29
|
+
|
|
30
|
+
Run the application with the command
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bundle exec rake run
|
|
34
|
+
```
|