activerecord-spanner-adapter 0.1.0 → 0.7.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 +42 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +9 -5
- data/LICENSE +6 -6
- data/README.md +67 -30
- data/Rakefile +74 -2
- 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/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/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 -251
- 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 +129 -7
- 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 -141
- data/lib/active_record/connection_adapters/spanner/type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/spanner_adapter.rb +188 -70
- 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 +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 +123 -0
- data/lib/activerecord_spanner_adapter/version.rb +9 -0
- data/lib/arel/visitors/spanner.rb +111 -0
- data/lib/spanner_client_ext.rb +103 -0
- data/renovate.json +5 -0
- metadata +417 -36
- data/.gitmodules +0 -3
- data/.travis.yml +0 -5
- data/lib/active_record/connection_adapters/spanner.rb +0 -10
- data/lib/activerecord-spanner-adapter/version.rb +0 -3
|
@@ -0,0 +1,77 @@
|
|
|
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 # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
14
|
+
# Use a read-only transaction to execute multiple reads at the same commit timestamp.
|
|
15
|
+
# The Spanner ActiveRecord adapter supports the custom isolation level :read_only that
|
|
16
|
+
# will start a read-only Spanner transaction with a strong timestamp bound.
|
|
17
|
+
album1 = nil
|
|
18
|
+
album2 = nil
|
|
19
|
+
ActiveRecord::Base.transaction isolation: :read_only do
|
|
20
|
+
# Read two random titles.
|
|
21
|
+
album1 = Album.all.sample
|
|
22
|
+
album2 = Album.where.not(id: album1.id).sample
|
|
23
|
+
puts ""
|
|
24
|
+
puts "Album title 1: #{album1.title}"
|
|
25
|
+
puts "Album title 2: #{album2.title}"
|
|
26
|
+
|
|
27
|
+
# Update the title of one of the albums in a separate transaction.
|
|
28
|
+
puts ""
|
|
29
|
+
puts "Updating the title of #{album1.title} in a separate transaction"
|
|
30
|
+
t = Thread.new { album1.update title: "New title" }
|
|
31
|
+
t.join
|
|
32
|
+
|
|
33
|
+
puts ""
|
|
34
|
+
puts "Reloading the albums in the read-only transaction. The updated title is not visible."
|
|
35
|
+
puts "Album title 1: #{album1.reload.title}"
|
|
36
|
+
puts "Album title 2: #{album2.reload.title}"
|
|
37
|
+
end
|
|
38
|
+
puts ""
|
|
39
|
+
puts "Reloading the albums **AFTER** the read-only transaction. The updated title is now visible."
|
|
40
|
+
puts "Album title 1: #{album1.reload.title}"
|
|
41
|
+
puts "Album title 2: #{album2.reload.title}"
|
|
42
|
+
|
|
43
|
+
# You can also execute a stale read with ActiveRecord. Specify a hash as the isolation level with one of
|
|
44
|
+
# the following options:
|
|
45
|
+
# * timestamp: Read data at a specific timestamp.
|
|
46
|
+
# * staleness: Read data at a specific staleness measured in seconds.
|
|
47
|
+
|
|
48
|
+
# Get a valid timestamp from the server to use for the transaction.
|
|
49
|
+
timestamp = ActiveRecord::Base.connection.select_all("SELECT CURRENT_TIMESTAMP AS ts")[0]["ts"]
|
|
50
|
+
puts ""
|
|
51
|
+
puts "Read data at timestamp #{timestamp}"
|
|
52
|
+
ActiveRecord::Base.transaction isolation: { timestamp: timestamp } do
|
|
53
|
+
puts "Album title 1: #{album1.reload.title}"
|
|
54
|
+
puts "Album title 2: #{album2.reload.title}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
puts ""
|
|
58
|
+
puts "Read data with staleness 30 seconds"
|
|
59
|
+
ActiveRecord::Base.transaction isolation: { staleness: 30 } do
|
|
60
|
+
begin
|
|
61
|
+
puts "Album title 1: #{album1.reload.title}"
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
# The table will (in almost all cases) not be found, because the timestamp that is being used to read
|
|
64
|
+
# the data will be before the table was created. This will therefore cause a 'Table not found' error.
|
|
65
|
+
puts "Reading data with 30 seconds staleness failed with error: #{e.message}"
|
|
66
|
+
puts ""
|
|
67
|
+
puts "This error is expected."
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
puts ""
|
|
72
|
+
puts "Press any key to end the application"
|
|
73
|
+
STDIN.getch
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
Application.run
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
|
12
|
+
t.string :last_name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
create_table :albums do |t|
|
|
16
|
+
t.string :title
|
|
17
|
+
t.references :singer, index: false, foreign_key: true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
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"
|
|
22
|
+
t.string "last_name"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
add_foreign_key "albums", "singers"
|
|
26
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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 = ["Pete", "Alice", "John", "Ethel", "Trudy", "Naomi", "Wendy", "Ruben", "Thomas", "Elly"]
|
|
12
|
+
last_names = ["Wendelson", "Allison", "Peterson", "Johnson", "Henderson", "Ericsson", "Aronson", "Tennet", "Courtou"]
|
|
13
|
+
|
|
14
|
+
adjectives = ["daily", "happy", "blue", "generous", "cooked", "bad", "open"]
|
|
15
|
+
nouns = ["windows", "potatoes", "bank", "street", "tree", "glass", "bottle"]
|
|
16
|
+
|
|
17
|
+
5.times do
|
|
18
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
20.times do
|
|
22
|
+
singer_id = Singer.all.sample.id
|
|
23
|
+
Album.create title: "#{adjectives.sample} #{nouns.sample}", singer_id: singer_id
|
|
24
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Sample - Read/Write transactions
|
|
2
|
+
|
|
3
|
+
This example shows how to use read/write transactions using the Spanner ActiveRecord adapter.
|
|
4
|
+
|
|
5
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
6
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
7
|
+
|
|
8
|
+
Run the application with the command
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bundle exec rake run
|
|
12
|
+
```
|
|
@@ -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 execute a read/write transaction on Spanner with ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[read-write-transactions]" }
|
|
13
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
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 # rubocop:disable Metrics/AbcSize
|
|
14
|
+
from_album = nil
|
|
15
|
+
to_album = nil
|
|
16
|
+
# Use a read/write transaction to execute multiple statements as an atomic unit.
|
|
17
|
+
ActiveRecord::Base.transaction do
|
|
18
|
+
# Transfer a marketing budget of 10,000 from one album to another.
|
|
19
|
+
from_album = Album.all.sample
|
|
20
|
+
to_album = Album.where.not(id: from_album.id).sample
|
|
21
|
+
|
|
22
|
+
puts ""
|
|
23
|
+
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) "\
|
|
24
|
+
"to #{to_album.title} (#{to_album.marketing_budget})"
|
|
25
|
+
from_album.update marketing_budget: from_album.marketing_budget - 10000
|
|
26
|
+
to_album.update marketing_budget: to_album.marketing_budget + 10000
|
|
27
|
+
end
|
|
28
|
+
puts ""
|
|
29
|
+
puts "Budgets after update:"
|
|
30
|
+
puts "Marketing budget #{from_album.title}: #{from_album.reload.marketing_budget}"
|
|
31
|
+
puts "Marketing budget #{to_album.title}: #{to_album.reload.marketing_budget}"
|
|
32
|
+
|
|
33
|
+
puts ""
|
|
34
|
+
puts "Press any key to end the application"
|
|
35
|
+
STDIN.getch
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Application.run
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
|
12
|
+
t.string :last_name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
create_table :albums do |t|
|
|
16
|
+
t.string :title
|
|
17
|
+
t.numeric :marketing_budget
|
|
18
|
+
t.references :singer, index: false, foreign_key: true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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.decimal "marketing_budget"
|
|
18
|
+
t.integer "singer_id", limit: 8
|
|
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
|
+
add_foreign_key "albums", "singers"
|
|
27
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
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 = ["Pete", "Alice", "John", "Ethel", "Trudy", "Naomi", "Wendy", "Ruben", "Thomas", "Elly"]
|
|
12
|
+
last_names = ["Wendelson", "Allison", "Peterson", "Johnson", "Henderson", "Ericsson", "Aronson", "Tennet", "Courtou"]
|
|
13
|
+
|
|
14
|
+
adjectives = ["daily", "happy", "blue", "generous", "cooked", "bad", "open"]
|
|
15
|
+
nouns = ["windows", "potatoes", "bank", "street", "tree", "glass", "bottle"]
|
|
16
|
+
budgets = [15000, 25000, 10000, 20000, 30000, 12000, 13000]
|
|
17
|
+
|
|
18
|
+
5.times do
|
|
19
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
20.times do
|
|
23
|
+
singer_id = Singer.all.sample.id
|
|
24
|
+
Album.create title: "#{adjectives.sample} #{nouns.sample}", marketing_budget: budgets.sample, singer_id: singer_id
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Sample - Stale reads
|
|
2
|
+
|
|
3
|
+
Read and query operations outside of a transaction block will by default be executed using a
|
|
4
|
+
single-use read-only transaction with strong timestamp bound. This means that the read is
|
|
5
|
+
guaranteed to return all data that has been committed at the time of the read. It is also possible
|
|
6
|
+
to specify that the Spanner ActiveRecord provider should execute a stale read. This is done by
|
|
7
|
+
specifying an optimizer hint for the read or query operation. The hints that are available are:
|
|
8
|
+
|
|
9
|
+
* `max_staleness: <seconds>`
|
|
10
|
+
* `exact_staleness: <seconds>`
|
|
11
|
+
* `min_read_timestamp: <timestamp>`
|
|
12
|
+
* `read_timestamp: <timestamp>`
|
|
13
|
+
|
|
14
|
+
See https://cloud.google.com/spanner/docs/timestamp-bounds for more information on what the
|
|
15
|
+
different timestamp bounds in Cloud Spanner mean.
|
|
16
|
+
|
|
17
|
+
NOTE: These optimizer hints ONLY work OUTSIDE transactions. See the read-only-transactions
|
|
18
|
+
samples for more information on how to specify a timestamp bound for a read-only transaction.
|
|
19
|
+
|
|
20
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
21
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
22
|
+
|
|
23
|
+
Run the application with the command
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bundle exec rake run
|
|
27
|
+
```
|
|
@@ -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 execute stale reads on Spanner with ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[stale-reads]" }
|
|
13
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
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 # rubocop:disable Metrics/AbcSize
|
|
14
|
+
# Get a random album.
|
|
15
|
+
album = Album.all.sample
|
|
16
|
+
|
|
17
|
+
# Get a valid timestamp from the Cloud Spanner server that we can use to specify a timestamp bound.
|
|
18
|
+
timestamp = ActiveRecord::Base.connection.select_all("SELECT CURRENT_TIMESTAMP AS ts")[0]["ts"]
|
|
19
|
+
|
|
20
|
+
# Update the name of the album and then read the version of the album before the update.
|
|
21
|
+
album.update title: "New title"
|
|
22
|
+
|
|
23
|
+
# The timestamp should be specified in the format '2021-09-07T15:22:10.123456789Z'
|
|
24
|
+
timestamp_string = timestamp.xmlschema 9
|
|
25
|
+
|
|
26
|
+
# Read the album at a specific timestamp.
|
|
27
|
+
album_previous_version = Album.optimizer_hints("read_timestamp: #{timestamp_string}").find_by id: album.id
|
|
28
|
+
album = album.reload
|
|
29
|
+
|
|
30
|
+
puts ""
|
|
31
|
+
puts "Updated album title: #{album.title}"
|
|
32
|
+
puts "Previous album version title: #{album_previous_version.title}"
|
|
33
|
+
|
|
34
|
+
# Read the same album using a minimum read timestamp. It could be that we get the first version
|
|
35
|
+
# of the row, but it could also be that we get the updated row.
|
|
36
|
+
album_min_read_timestamp = Album.optimizer_hints("min_read_timestamp: #{timestamp_string}").find_by id: album.id
|
|
37
|
+
puts ""
|
|
38
|
+
puts "Updated album title: #{album.title}"
|
|
39
|
+
puts "Min-read timestamp title: #{album_min_read_timestamp.title}"
|
|
40
|
+
|
|
41
|
+
# Staleness can also be specified as a number of seconds. The number of seconds may contain a fraction.
|
|
42
|
+
# The following reads the album version at exactly 1.5 seconds ago. That will normally be nil, as the
|
|
43
|
+
# row did not yet exist at that moment.
|
|
44
|
+
album_exact_staleness = Album.optimizer_hints("exact_staleness: 1.5").find_by id: album.id
|
|
45
|
+
|
|
46
|
+
puts ""
|
|
47
|
+
puts "Updated album title: #{album.title}"
|
|
48
|
+
puts "Title 1.5 seconds ago: #{album_exact_staleness&.title}"
|
|
49
|
+
|
|
50
|
+
# You can also specify a max staleness. The server will determine the best timestamp to use for the read.
|
|
51
|
+
album_max_staleness = Album.optimizer_hints("max_staleness: 10").find_by id: album.id
|
|
52
|
+
|
|
53
|
+
puts ""
|
|
54
|
+
puts "Updated album title: #{album.title}"
|
|
55
|
+
puts "Title somewhere during the last 10 seconds: #{album_max_staleness&.title}"
|
|
56
|
+
|
|
57
|
+
puts ""
|
|
58
|
+
puts "Press any key to end the application"
|
|
59
|
+
STDIN.getch
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Application.run
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
|
12
|
+
t.string :last_name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
create_table :albums do |t|
|
|
16
|
+
t.string :title
|
|
17
|
+
t.references :singer, index: false, foreign_key: true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
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"
|
|
22
|
+
t.string "last_name"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
add_foreign_key "albums", "singers"
|
|
26
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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 = ["Pete", "Alice", "John", "Ethel", "Trudy", "Naomi", "Wendy", "Ruben", "Thomas", "Elly"]
|
|
12
|
+
last_names = ["Wendelson", "Allison", "Peterson", "Johnson", "Henderson", "Ericsson", "Aronson", "Tennet", "Courtou"]
|
|
13
|
+
|
|
14
|
+
adjectives = ["daily", "happy", "blue", "generous", "cooked", "bad", "open"]
|
|
15
|
+
nouns = ["windows", "potatoes", "bank", "street", "tree", "glass", "bottle"]
|
|
16
|
+
|
|
17
|
+
5.times do
|
|
18
|
+
Singer.create first_name: first_names.sample, last_name: last_names.sample
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
20.times do
|
|
22
|
+
singer_id = Singer.all.sample.id
|
|
23
|
+
Album.create title: "#{adjectives.sample} #{nouns.sample}", singer_id: singer_id
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Sample - Timestamp Data Type
|
|
2
|
+
|
|
3
|
+
This example shows how to use the `TIMESTAMP` data type with the Spanner ActiveRecord adapter. A `TIMESTAMP` represents
|
|
4
|
+
a specific point in time. Cloud Spanner always stores the timestamp in UTC, and it is not possible to include a
|
|
5
|
+
specific timezone in a timestamp value in Cloud Spanner. Instead, a separate column containing a timezone can be used
|
|
6
|
+
if your application needs to store both a timestamp and a timezone. This sample shows how to do this.
|
|
7
|
+
|
|
8
|
+
## Running the Sample
|
|
9
|
+
|
|
10
|
+
The sample will automatically start a Spanner Emulator in a docker container and execute the sample
|
|
11
|
+
against that emulator. The emulator will automatically be stopped when the application finishes.
|
|
12
|
+
|
|
13
|
+
Run the application with the command
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle exec rake run
|
|
17
|
+
```
|
|
@@ -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 the TIMESTAMP data type in ActiveRecord."
|
|
11
|
+
task :run do
|
|
12
|
+
Dir.chdir("..") { sh "bundle exec rake run[timestamp-data-type]" }
|
|
13
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
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/meeting"
|
|
10
|
+
|
|
11
|
+
class Application
|
|
12
|
+
def self.run
|
|
13
|
+
# Set the default local timezone.
|
|
14
|
+
Time.zone = "Europe/Lisbon"
|
|
15
|
+
|
|
16
|
+
# Create a meeting using the local timezone. The timezone information will not be stored in the `meeting_time`
|
|
17
|
+
# column in the database, which is why we also include a separate column where we can store the timezone name.
|
|
18
|
+
meeting_time = Time.zone.local 2021, 7, 1, 10, 30, 0
|
|
19
|
+
meeting = Meeting.create title: "Standup", meeting_time: meeting_time, meeting_timezone: Time.zone.name
|
|
20
|
+
|
|
21
|
+
# The meeting_time is saved in UTC in Cloud Spanner. Reloading it will therefore lose the timezone information in
|
|
22
|
+
# the meeting_time attribute. It is however stored in the separate meeting_timezone attribute, and that can be used
|
|
23
|
+
# to reconstruct the meeting_time in the timezone where the meeting was planned.
|
|
24
|
+
# The Meeting model class also contains two helper methods:
|
|
25
|
+
# 1. `local_meeting_time`: Returns the meeting_time in the local timezone.
|
|
26
|
+
# 2. `meeting_time_in_planned_zone`: Returns the meeting_time in the timezone where it is planned.
|
|
27
|
+
meeting.reload
|
|
28
|
+
puts ""
|
|
29
|
+
puts "#{'Meeting time in UTC:'.ljust 60} #{meeting.meeting_time}"
|
|
30
|
+
puts "#{'Meeting time in the timezone where it was planned:'.ljust 60} #{meeting.meeting_time_in_planned_zone}"
|
|
31
|
+
|
|
32
|
+
# Simulate that the application is now running in the timezone America/Los_Angeles.
|
|
33
|
+
Time.zone = "America/Los_Angeles"
|
|
34
|
+
puts "#{'Meeting time in the local timezone (America/Los_Angeles):'.ljust 60} #{meeting.local_meeting_time}"
|
|
35
|
+
|
|
36
|
+
puts ""
|
|
37
|
+
puts "Press any key to end the application"
|
|
38
|
+
STDIN.getch
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Application.run
|