activerecord-spanner-adapter 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +36 -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 +26 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +9 -4
- data/LICENSE +6 -6
- data/README.md +67 -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 +147 -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 +67 -0
- data/acceptance/cases/transactions/read_write_transactions_test.rb +248 -0
- data/acceptance/cases/type/all_types_test.rb +152 -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/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 +143 -0
- data/acceptance/test_helper.rb +260 -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/interleaved-tables/README.md +152 -0
- data/examples/snippets/interleaved-tables/Rakefile +13 -0
- data/examples/snippets/interleaved-tables/application.rb +109 -0
- data/examples/snippets/interleaved-tables/config/database.yml +8 -0
- data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +44 -0
- data/examples/snippets/interleaved-tables/db/schema.rb +32 -0
- data/examples/snippets/interleaved-tables/db/seeds.rb +40 -0
- data/examples/snippets/interleaved-tables/models/album.rb +15 -0
- data/examples/snippets/interleaved-tables/models/singer.rb +20 -0
- data/examples/snippets/interleaved-tables/models/track.rb +25 -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/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 +49 -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/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 +224 -269
- 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 +182 -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 +32 -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 +217 -0
- data/lib/activerecord_spanner_adapter/connection.rb +324 -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 +261 -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 +113 -0
- data/lib/activerecord_spanner_adapter/version.rb +9 -0
- data/lib/arel/visitors/spanner.rb +35 -0
- data/lib/spanner_client_ext.rb +82 -0
- data/renovate.json +5 -0
- metadata +387 -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,29 @@
|
|
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.date "release_date"
|
18
|
+
t.integer "singer_id", limit: 8
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table "singers", force: :cascade 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
|
25
|
+
t.date "birth_date"
|
26
|
+
t.binary "picture"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/bin/console
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
-
require "activerecord
|
4
|
+
require "activerecord-spanner-adapter"
|
5
|
+
|
6
|
+
require "active_record"
|
5
7
|
|
6
8
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
9
|
# with your gem easier. You can also use a different console, if you like.
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
11
|
+
require "pry"
|
12
|
+
require "pry-byebug" # For easy debugging
|
13
|
+
Pry.start
|
@@ -0,0 +1,262 @@
|
|
1
|
+
## activerecord-spanner-adapter for Rails tutorial
|
2
|
+
|
3
|
+
This example shows how to use activerecord-spanner-adapter for Cloud Spanner as a backend database for [Rails's tutorials](https://guides.rubyonrails.org/getting_started.html).
|
4
|
+
|
5
|
+
### Create a Spanner instance
|
6
|
+
This step will create a Cloud Spanner instance. Cloud Spanner is a billable component of the Google Cloud. For information on the cost of using Cloud Spanner, see [Pricing](https://cloud.google.com/spanner/pricing).
|
7
|
+
|
8
|
+
__Note__: If you want to try the tutorial without Cloud Spanner cost, you can use the emulator. Read the [doc](https://cloud.google.com/spanner/docs/emulator) for more details.
|
9
|
+
|
10
|
+
1. Set the project environment variable:
|
11
|
+
```shell
|
12
|
+
export PROJECT_ID=[your-cloud-project-id]
|
13
|
+
```
|
14
|
+
1. Set the default project:
|
15
|
+
```shell
|
16
|
+
gcloud config set project $PROJECT_ID
|
17
|
+
```
|
18
|
+
1. If you haven't enabled the Cloud Spanner service, enable it:
|
19
|
+
```shell
|
20
|
+
gcloud services enable spanner.googleapis.com
|
21
|
+
```
|
22
|
+
1. Create an instance. This tutorial will use a one-node instance in `regional-us-central1`.
|
23
|
+
You can choose a region close to you:
|
24
|
+
```shell
|
25
|
+
gcloud spanner instances create test-instance --config=regional-us-central1 \
|
26
|
+
--description="Rails Demo Instance" --nodes=1
|
27
|
+
```
|
28
|
+
1. Verify the instance has been created:
|
29
|
+
```shell
|
30
|
+
gcloud spanner instances list
|
31
|
+
```
|
32
|
+
You should see output like the following:
|
33
|
+
```
|
34
|
+
NAME DISPLAY_NAME CONFIG NODE_COUNT STATE
|
35
|
+
test-instance Rails Demo Instance regional-us-central1 1 READY
|
36
|
+
```
|
37
|
+
1. Set the default instance:
|
38
|
+
```shell
|
39
|
+
gcloud config set spanner/instance test-instance
|
40
|
+
```
|
41
|
+
|
42
|
+
Read the [Cloud Spanner setup guide](https://cloud.google.com/spanner/docs/getting-started/set-up) for more details.
|
43
|
+
|
44
|
+
### Create a Rails project
|
45
|
+
|
46
|
+
If you don't have Ruby and Rails installed, please follow the steps in the following links to install them:
|
47
|
+
|
48
|
+
- [Installing Ruby](https://www.ruby-lang.org/en/documentation/installation/)
|
49
|
+
- [Installing Rails](https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails)
|
50
|
+
|
51
|
+
If you are not familiar with Active Record, you can read more about it on [Ruby on Rails Guides](https://guides.rubyonrails.org/)
|
52
|
+
|
53
|
+
1. Verify the Ruby and Rails versions:
|
54
|
+
```shell
|
55
|
+
ruby --version
|
56
|
+
rails --version
|
57
|
+
```
|
58
|
+
The versions should be Ruby 2.6 or higher and Rails 6.0 or higher.
|
59
|
+
1. Create a new Rails project:
|
60
|
+
|
61
|
+
```shell
|
62
|
+
rails new blog
|
63
|
+
```
|
64
|
+
1. The `blog` directory will have a number of generated files and folders that make up the structure of a Rails application. You can list them:
|
65
|
+
```shell
|
66
|
+
cd blog
|
67
|
+
ls -l
|
68
|
+
```
|
69
|
+
1. Starting up the web server and make sure the sample application works:
|
70
|
+
```shell
|
71
|
+
bin/rails server
|
72
|
+
```
|
73
|
+
After the server starts, open your browser and navigate to [http://localhost:3000](http://localhost:3000). You should see the default Rails page with the sentence: __Yay! You're on Rails!__
|
74
|
+
|
75
|
+
### Create a service account
|
76
|
+
|
77
|
+
1. Create a service account:
|
78
|
+
```shell
|
79
|
+
gcloud iam service-accounts create activerecord-spanner
|
80
|
+
```
|
81
|
+
1. Grant an IAM role to access Cloud Spanner:
|
82
|
+
```shell
|
83
|
+
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
|
84
|
+
--member="serviceAccount:activerecord-spanner@${PROJECT_ID}.iam.gserviceaccount.com" \
|
85
|
+
--role="roles/spanner.databaseAdmin"
|
86
|
+
```
|
87
|
+
Here the role `roles/spanner.databaseAdmin` is granted to the service account. If you want to restrict the permissions further, you can choose to create a custom role with proper permissions.
|
88
|
+
1. Create a key file and download it:
|
89
|
+
```shell
|
90
|
+
gcloud iam service-accounts keys create activerecord-spanner-key.json \
|
91
|
+
--iam-account=activerecord-spanner@${PROJECT_ID}.iam.gserviceaccount.com
|
92
|
+
```
|
93
|
+
This tutorial uses the key file to access Cloud Spanner. If you are using services such as Compute Engine, Cloud Run, or Cloud Functions, you can associate the service account to the instance and avoid using the key file.
|
94
|
+
1. From the previous step, a key file should be created and downloaded. You can run the following command to view its content:
|
95
|
+
```shell
|
96
|
+
cat activerecord-spanner-key.json
|
97
|
+
```
|
98
|
+
|
99
|
+
### Use Cloud Spanner adapter in Gemfile
|
100
|
+
1. Edit the Gemfile file of the `blog` app and add the `activerecord-spanner-adapter` gem:
|
101
|
+
```ruby
|
102
|
+
gem 'activerecord-spanner-adapter', git: 'https://github.com/googleapis/ruby-spanner-activerecord.git'
|
103
|
+
```
|
104
|
+
1. Install gems:
|
105
|
+
|
106
|
+
```shell
|
107
|
+
bundle install
|
108
|
+
```
|
109
|
+
|
110
|
+
### Update database.yml to use Cloud Spanner.
|
111
|
+
After the Cloud Spanner instance is running, you'll need a few variables:
|
112
|
+
* Cloud project id
|
113
|
+
* Cloud Spanner instance id, such as `test-instance`
|
114
|
+
* Database name, such as `blog_dev`
|
115
|
+
* Credential: Credential key file path or export `GOOGLE_CLOUD_KEYFILE`environment variable.
|
116
|
+
|
117
|
+
Edit the file `config/database.yml` and make the section `DATABASES` into the following:
|
118
|
+
|
119
|
+
```yml
|
120
|
+
default: &default
|
121
|
+
adapter: "spanner"
|
122
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 10 } %>
|
123
|
+
project: [PROJECT_ID]
|
124
|
+
instance: test-instance
|
125
|
+
credentials: activerecord-spanner-key.json
|
126
|
+
|
127
|
+
development:
|
128
|
+
<<: *default
|
129
|
+
database: blog_dev
|
130
|
+
|
131
|
+
test:
|
132
|
+
<<: *default
|
133
|
+
database: blog_test
|
134
|
+
|
135
|
+
production:
|
136
|
+
<<: *default
|
137
|
+
database: blog
|
138
|
+
```
|
139
|
+
|
140
|
+
Replace `[PROJECT_ID]` with the project id you are currently using.
|
141
|
+
|
142
|
+
### Create database
|
143
|
+
|
144
|
+
You now can run the following command to create the database:
|
145
|
+
```shell
|
146
|
+
./bin/rails db:create
|
147
|
+
```
|
148
|
+
You should see output like the following:
|
149
|
+
```
|
150
|
+
Created database 'blog_dev'
|
151
|
+
```
|
152
|
+
### Generate a Model and apply the migration
|
153
|
+
1. Use the model generato to define a model:
|
154
|
+
```shell
|
155
|
+
bin/rails generate model Article title:string body:text
|
156
|
+
```
|
157
|
+
1. Apply the migration:
|
158
|
+
```shell
|
159
|
+
./bin/rails db:migrate
|
160
|
+
```
|
161
|
+
The command takes a while to complete. When it's done, you will have an output like the following:
|
162
|
+
```
|
163
|
+
$ ./bin/rails db:migrate
|
164
|
+
== 20210803025742 CreateArticles: migrating ===================================
|
165
|
+
-- create_table(:articles)
|
166
|
+
-> 23.5728s
|
167
|
+
== 20210803025742 CreateArticles: migrated (23.5729s) =========================
|
168
|
+
```
|
169
|
+
|
170
|
+
### Use the CLI to interact with the database
|
171
|
+
1. Run the following command to start `irb`:
|
172
|
+
```shell
|
173
|
+
bin/rails console
|
174
|
+
```
|
175
|
+
1. At the prompt, initialize a new `Article` object:
|
176
|
+
```ruby
|
177
|
+
article = Article.new(title: "Hello Rails", body: "I am on Rails!")
|
178
|
+
```
|
179
|
+
1. Run the following command to save the object to the database:
|
180
|
+
```ruby
|
181
|
+
article.save
|
182
|
+
```
|
183
|
+
1. Review the object and you can see the field `id`, `created_at`, and `updated_at` have been set:
|
184
|
+
```ruby
|
185
|
+
article
|
186
|
+
```
|
187
|
+
Sample output:
|
188
|
+
```
|
189
|
+
=> #<Article id: 4170057092403543076, title: "Hello Rails", body: "I am on Rails!", created_at: "2021-08-03 03:06:26.096275000 +0000", updated_at: "2021-08-03 03:06:26.096275000 +0000">
|
190
|
+
```
|
191
|
+
1. You can find `Article.find(id)` or `Article.all` to fetch data from the database. For example:
|
192
|
+
```ruby
|
193
|
+
irb(main):007:0> Article.find(4170057092403543076)
|
194
|
+
Article Load (49.2ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`id` = @p1 LIMIT @p2
|
195
|
+
=> #<Article id: 4170057092403543076, title: "Hello Rails", body: "I am on Rails!", created_at: "2021-08-03 03:06:26.096275000 +0000", updated_at: "2021-08-03 03:06:26.096275000 +0000">
|
196
|
+
|
197
|
+
irb(main):008:0> Article.all
|
198
|
+
Article Load (73.9ms) SELECT `articles`.* FROM `articles` /* loading for inspect */ LIMIT @p1
|
199
|
+
=> #<ActiveRecord::Relation [#<Article id: 4170057092403543076, title: "Hello Rails", body: "I am on Rails!", created_at: "2021-08-03 03:06:26.096275000 +0000", updated_at: "2021-08-03 03:06:26.096275000 +0000">]>
|
200
|
+
```
|
201
|
+
|
202
|
+
### Update the app to show a list of records
|
203
|
+
1. Use the controller generator to create a controller:
|
204
|
+
```shell
|
205
|
+
bin/rails generate controller Articles index
|
206
|
+
```
|
207
|
+
1. Open the file `app/controllers/articles_controller.rb`, and change the `index` action to fetch all articles from the database:
|
208
|
+
```ruby
|
209
|
+
class ArticlesController < ApplicationController
|
210
|
+
def index
|
211
|
+
@articles = Article.all
|
212
|
+
end
|
213
|
+
end
|
214
|
+
```
|
215
|
+
1. Open `app/views/articles/index.html.erb`, and update the file as the following:
|
216
|
+
```html
|
217
|
+
<h1>Articles</h1>
|
218
|
+
<ul>
|
219
|
+
<% @articles.each do |article| %>
|
220
|
+
<li>
|
221
|
+
<%= article.title %>
|
222
|
+
</li>
|
223
|
+
<% end %>
|
224
|
+
</ul>
|
225
|
+
```
|
226
|
+
1. Run your server again
|
227
|
+
```shell
|
228
|
+
./bin/rails s
|
229
|
+
```
|
230
|
+
1. In your browser, navigate to the URL [http://localhost:3000/articles/index](http://localhost:3000/articles/index). And you will see the `Hello Rails` record you entered previously.
|
231
|
+
1. [Optional] you can follow the rest of the steps in the [Getting Started with Rails](https://guides.rubyonrails.org/getting_started.html) guide.
|
232
|
+
|
233
|
+
### Clean up
|
234
|
+
|
235
|
+
To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, you can delete the resources you created. You can either
|
236
|
+
delete the entire project or delete individual resources.
|
237
|
+
|
238
|
+
Deleting a project has the following effects:
|
239
|
+
|
240
|
+
* Everything in the project is deleted. If you used an existing project for this tutorial, when you delete it, you also delete any other work you've done in the
|
241
|
+
project.
|
242
|
+
* Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs
|
243
|
+
that use the project ID, delete selected resources inside the project instead of deleting the whole project.
|
244
|
+
|
245
|
+
If you plan to explore multiple tutorials, reusing projects can help you to avoid exceeding project quota limits.
|
246
|
+
|
247
|
+
#### Delete the project
|
248
|
+
|
249
|
+
The easiest way to eliminate billing is to delete the project you created for the tutorial.
|
250
|
+
|
251
|
+
1. In the Cloud Console, go to the [**Manage resources** page](https://console.cloud.google.com/iam-admin/projects).
|
252
|
+
1. In the project list, select the project that you want to delete and then click **Delete**.
|
253
|
+
1. In the dialog, type the project ID and then click **Shut down** to delete the project.
|
254
|
+
|
255
|
+
#### Delete the resources
|
256
|
+
|
257
|
+
If you don't want to delete the project, you can delete the provisioned resources:
|
258
|
+
|
259
|
+
gcloud iam service-accounts delete \
|
260
|
+
activerecord-spanner@${PROJECT_ID}.iam.gserviceaccount.com
|
261
|
+
|
262
|
+
gcloud spanner instances delete test-instance
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Sample snippets
|
2
|
+
|
3
|
+
This directory contains a number of simple standalone samples that show how to use ActiveRecord with Cloud Spanner.
|
4
|
+
|
5
|
+
### Running from this directory
|
6
|
+
The samples can be executed using the following command in this directory:
|
7
|
+
|
8
|
+
```bash
|
9
|
+
bundle exec rake run\[<sample_name>\]
|
10
|
+
```
|
11
|
+
|
12
|
+
Example:
|
13
|
+
|
14
|
+
```bash
|
15
|
+
bundle exec rake run\[quickstart\]
|
16
|
+
```
|
17
|
+
|
18
|
+
The available samples can be listed using the command
|
19
|
+
|
20
|
+
```bash
|
21
|
+
bundle exec rake list
|
22
|
+
```
|
23
|
+
|
24
|
+
### Running from sample directory
|
25
|
+
You can also run a sample by calling the following command __in the directory of the sample__:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
bundle exec rake run
|
29
|
+
```
|
@@ -0,0 +1,57 @@
|
|
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 "docker"
|
9
|
+
|
10
|
+
desc "Lists all available samples."
|
11
|
+
task :list do
|
12
|
+
samples = Dir.entries(".").select do |entry|
|
13
|
+
File.directory?(File.join(".", entry)) \
|
14
|
+
&& !%w[. ..].include?(entry) \
|
15
|
+
&& File.exist?(File.join(".", entry, "application.rb"))
|
16
|
+
end
|
17
|
+
puts "Available samples: "
|
18
|
+
samples.sort.each { |dir| puts " #{dir}" }
|
19
|
+
puts ""
|
20
|
+
puts "Run a sample with the command `bundle exec rake run\\[<sample-name>\\]`"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Runs a simple ActiveRecord tutorial on a Spanner emulator."
|
24
|
+
task :run, [:sample] do |_t, args|
|
25
|
+
sample = args[:sample]
|
26
|
+
unless sample
|
27
|
+
puts "Missing argument :sample. Running quickstart sample"
|
28
|
+
puts ""
|
29
|
+
sample = "quickstart"
|
30
|
+
end
|
31
|
+
|
32
|
+
puts "Downloading Spanner emulator image..."
|
33
|
+
Docker::Image.create "fromImage" => "gcr.io/cloud-spanner-emulator/emulator:latest"
|
34
|
+
puts "Creating Spanner emulator container..."
|
35
|
+
container = Docker::Container.create(
|
36
|
+
"Image" => "gcr.io/cloud-spanner-emulator/emulator:latest",
|
37
|
+
"ExposedPorts" => { "9010/tcp" => {} },
|
38
|
+
"HostConfig" => {
|
39
|
+
"PortBindings" => {
|
40
|
+
"9010/tcp" => [{ "HostPort" => "9010" }]
|
41
|
+
}
|
42
|
+
}
|
43
|
+
)
|
44
|
+
|
45
|
+
begin
|
46
|
+
puts "Starting Spanner emulator..."
|
47
|
+
container.start!
|
48
|
+
Dir.chdir sample do
|
49
|
+
sh "ruby ../bin/create_emulator_instance.rb"
|
50
|
+
sh "rake db:migrate"
|
51
|
+
sh "rake db:seed"
|
52
|
+
sh "ruby application.rb"
|
53
|
+
end
|
54
|
+
ensure
|
55
|
+
container.stop!
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Sample - Array Data Type
|
2
|
+
|
3
|
+
This example shows how to use the `ARRAY` data type with the Spanner ActiveRecord adapter. The sample uses a single
|
4
|
+
table that has one column for each possible `ARRAY` data type:
|
5
|
+
|
6
|
+
```sql
|
7
|
+
CREATE TABLE entity_with_array_types (
|
8
|
+
id INT64 NOT NULL,
|
9
|
+
col_array_string ARRAY<STRING(MAX)>,
|
10
|
+
col_array_int64 ARRAY<INT64>,
|
11
|
+
col_array_float64 ARRAY<FLOAT64>,
|
12
|
+
col_array_numeric ARRAY<NUMERIC>,
|
13
|
+
col_array_bool ARRAY<BOOL>,
|
14
|
+
col_array_bytes ARRAY<BYTES(MAX)>,
|
15
|
+
col_array_date ARRAY<DATE>,
|
16
|
+
col_array_timestamp ARRAY<TIMESTAMP>,
|
17
|
+
) PRIMARY KEY (id);
|
18
|
+
```
|
19
|
+
|
20
|
+
This schema is created in ActiveRecord as follows:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
create_table :entity_with_array_types do |t|
|
24
|
+
# Create a table with a column with each possible array type.
|
25
|
+
t.column :col_array_string, :string, array: true
|
26
|
+
t.column :col_array_int64, :bigint, array: true
|
27
|
+
t.column :col_array_float64, :float, array: true
|
28
|
+
t.column :col_array_numeric, :numeric, array: true
|
29
|
+
t.column :col_array_bool, :boolean, array: true
|
30
|
+
t.column :col_array_bytes, :binary, array: true
|
31
|
+
t.column :col_array_date, :date, array: true
|
32
|
+
t.column :col_array_timestamp, :datetime, array: true
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Running the Sample
|
37
|
+
|
38
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
39
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
40
|
+
|
41
|
+
Run the application with the command
|
42
|
+
|
43
|
+
```bash
|
44
|
+
bundle exec rake run
|
45
|
+
```
|