activerecord-spanner-adapter 0.3.0 → 0.5.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 +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,37 @@
|
|
|
1
|
+
# Copyright 2020 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
|
+
# frozen_string_literal: true
|
|
8
|
+
|
|
9
|
+
module ActiveRecord
|
|
10
|
+
module ConnectionAdapters
|
|
11
|
+
module Spanner
|
|
12
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
|
13
|
+
undef to_yaml if method_defined? :to_yaml
|
|
14
|
+
|
|
15
|
+
attr_reader :ordinal_position
|
|
16
|
+
|
|
17
|
+
def initialize type_metadata, ordinal_position: nil
|
|
18
|
+
super type_metadata
|
|
19
|
+
@ordinal_position = ordinal_position
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def == other
|
|
23
|
+
other.is_a?(TypeMetadata) &&
|
|
24
|
+
__getobj__ == other.__getobj__ &&
|
|
25
|
+
ordinal_position == other.ordinal_position
|
|
26
|
+
end
|
|
27
|
+
alias eql? ==
|
|
28
|
+
|
|
29
|
+
def hash
|
|
30
|
+
TypeMetadata.hash ^
|
|
31
|
+
__getobj__.hash ^
|
|
32
|
+
ordinal_position.hash
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -1,126 +1,230 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
1
|
+
# Copyright 2020 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 "securerandom"
|
|
8
|
+
require "google/cloud/spanner"
|
|
9
|
+
require "spanner_client_ext"
|
|
10
|
+
require "active_record/connection_adapters/abstract_adapter"
|
|
11
|
+
require "active_record/connection_adapters/spanner/database_statements"
|
|
12
|
+
require "active_record/connection_adapters/spanner/schema_statements"
|
|
13
|
+
require "active_record/connection_adapters/spanner/schema_cache"
|
|
14
|
+
require "active_record/connection_adapters/spanner/schema_definitions"
|
|
15
|
+
require "active_record/connection_adapters/spanner/type_metadata"
|
|
16
|
+
require "active_record/connection_adapters/spanner/quoting"
|
|
17
|
+
require "active_record/type/spanner/array"
|
|
18
|
+
require "active_record/type/spanner/bytes"
|
|
19
|
+
require "active_record/type/spanner/spanner_active_record_converter"
|
|
20
|
+
require "active_record/type/spanner/time"
|
|
21
|
+
require "arel/visitors/spanner"
|
|
22
|
+
require "activerecord_spanner_adapter/base"
|
|
23
|
+
require "activerecord_spanner_adapter/connection"
|
|
24
|
+
require "activerecord_spanner_adapter/errors"
|
|
25
|
+
require "activerecord_spanner_adapter/information_schema"
|
|
26
|
+
require "activerecord_spanner_adapter/primary_key"
|
|
27
|
+
require "activerecord_spanner_adapter/transaction"
|
|
10
28
|
|
|
11
29
|
module ActiveRecord
|
|
12
|
-
module ConnectionHandling
|
|
13
|
-
def spanner_connection
|
|
14
|
-
|
|
30
|
+
module ConnectionHandling # :nodoc:
|
|
31
|
+
def spanner_connection config
|
|
32
|
+
connection = ActiveRecordSpannerAdapter::Connection.new config
|
|
33
|
+
connection.connect!
|
|
34
|
+
ConnectionAdapters::SpannerAdapter.new connection, logger, nil, config
|
|
35
|
+
rescue Google::Cloud::Error => error
|
|
36
|
+
if error.instance_of? Google::Cloud::NotFoundError
|
|
37
|
+
raise ActiveRecord::NoDatabaseError
|
|
38
|
+
end
|
|
39
|
+
raise error
|
|
15
40
|
end
|
|
16
41
|
end
|
|
17
42
|
|
|
18
43
|
module ConnectionAdapters
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
module AbstractPool
|
|
45
|
+
def get_schema_cache connection
|
|
46
|
+
@schema_cache ||= SpannerSchemaCache.new connection
|
|
47
|
+
@schema_cache.connection = connection
|
|
48
|
+
@schema_cache
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
23
52
|
class SpannerAdapter < AbstractAdapter
|
|
24
|
-
ADAPTER_NAME =
|
|
25
|
-
|
|
26
|
-
|
|
53
|
+
ADAPTER_NAME = "spanner".freeze
|
|
54
|
+
NATIVE_DATABASE_TYPES = {
|
|
55
|
+
primary_key: "INT64",
|
|
56
|
+
parent_key: "INT64",
|
|
57
|
+
string: { name: "STRING", limit: "MAX" },
|
|
58
|
+
text: { name: "STRING", limit: "MAX" },
|
|
59
|
+
integer: { name: "INT64" },
|
|
60
|
+
bigint: { name: "INT64" },
|
|
61
|
+
float: { name: "FLOAT64" },
|
|
62
|
+
decimal: { name: "NUMERIC" },
|
|
63
|
+
numeric: { name: "NUMERIC" },
|
|
64
|
+
datetime: { name: "TIMESTAMP" },
|
|
65
|
+
time: { name: "TIMESTAMP" },
|
|
66
|
+
date: { name: "DATE" },
|
|
67
|
+
binary: { name: "BYTES", limit: "MAX" },
|
|
68
|
+
boolean: { name: "BOOL" }
|
|
69
|
+
}.freeze
|
|
27
70
|
|
|
28
|
-
include Spanner::SchemaStatements
|
|
29
|
-
include Spanner::DatabaseStatements
|
|
30
71
|
include Spanner::Quoting
|
|
72
|
+
include Spanner::DatabaseStatements
|
|
73
|
+
include Spanner::SchemaStatements
|
|
31
74
|
|
|
32
|
-
def initialize
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
super(connection, logger, config)
|
|
75
|
+
def initialize connection, logger, connection_options, config
|
|
76
|
+
super connection, logger, config
|
|
77
|
+
@connection_options = connection_options
|
|
36
78
|
end
|
|
37
79
|
|
|
38
|
-
def
|
|
39
|
-
|
|
80
|
+
def max_identifier_length
|
|
81
|
+
128
|
|
40
82
|
end
|
|
41
83
|
|
|
42
|
-
def
|
|
43
|
-
|
|
84
|
+
def native_database_types
|
|
85
|
+
NATIVE_DATABASE_TYPES
|
|
44
86
|
end
|
|
45
87
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
88
|
+
# Database
|
|
89
|
+
|
|
90
|
+
def self.database_exists? config
|
|
91
|
+
connection = ActiveRecordSpannerAdapter::Connection.new config
|
|
92
|
+
connection.connect!
|
|
93
|
+
true
|
|
94
|
+
rescue ActiveRecord::NoDatabaseError
|
|
95
|
+
false
|
|
51
96
|
end
|
|
52
97
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@
|
|
57
|
-
@database_id = params[:database]
|
|
98
|
+
# Connection management
|
|
99
|
+
|
|
100
|
+
def active?
|
|
101
|
+
@connection.active?
|
|
58
102
|
end
|
|
59
103
|
|
|
60
104
|
def disconnect!
|
|
61
105
|
super
|
|
62
|
-
|
|
106
|
+
@connection.disconnect!
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def reset!
|
|
110
|
+
super
|
|
111
|
+
@connection.reset!
|
|
112
|
+
end
|
|
113
|
+
alias reconnect! reset!
|
|
114
|
+
|
|
115
|
+
# Spanner Connection API
|
|
116
|
+
delegate :ddl_batch, :ddl_batch?, :start_batch_ddl, :abort_batch, :run_batch, to: :@connection
|
|
117
|
+
|
|
118
|
+
def current_spanner_transaction
|
|
119
|
+
@connection.current_transaction
|
|
63
120
|
end
|
|
64
121
|
|
|
65
|
-
|
|
122
|
+
# Supported features
|
|
123
|
+
|
|
124
|
+
def supports_bulk_alter?
|
|
66
125
|
true
|
|
67
126
|
end
|
|
68
127
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
SecureRandom.uuid
|
|
128
|
+
def supports_common_table_expressions?
|
|
129
|
+
true
|
|
72
130
|
end
|
|
73
131
|
|
|
74
|
-
|
|
75
|
-
|
|
132
|
+
def supports_explain?
|
|
133
|
+
false
|
|
134
|
+
end
|
|
76
135
|
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
136
|
+
def supports_foreign_keys?
|
|
137
|
+
true
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def supports_index_sort_order?
|
|
141
|
+
true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def supports_insert_on_conflict?
|
|
145
|
+
true
|
|
146
|
+
end
|
|
147
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
|
148
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
|
149
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
|
150
|
+
|
|
151
|
+
def supports_insert_returning?
|
|
152
|
+
true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def supports_multi_insert?
|
|
156
|
+
true
|
|
88
157
|
end
|
|
89
158
|
|
|
90
|
-
def
|
|
91
|
-
|
|
92
|
-
|
|
159
|
+
def supports_optimizer_hints?
|
|
160
|
+
true
|
|
161
|
+
end
|
|
93
162
|
|
|
94
|
-
|
|
163
|
+
def supports_primary_key?
|
|
164
|
+
true
|
|
95
165
|
end
|
|
96
166
|
|
|
97
|
-
def
|
|
98
|
-
|
|
167
|
+
def prefetch_primary_key? _table_name = nil
|
|
168
|
+
true
|
|
169
|
+
end
|
|
99
170
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
171
|
+
# Generate next sequence number for primary key
|
|
172
|
+
def next_sequence_value _sequence_name
|
|
173
|
+
SecureRandom.uuid.gsub("-", "").hex & 0x7FFFFFFFFFFFFFFF
|
|
174
|
+
end
|
|
104
175
|
|
|
105
|
-
|
|
176
|
+
def arel_visitor
|
|
177
|
+
Arel::Visitors::Spanner.new self
|
|
106
178
|
end
|
|
107
179
|
|
|
108
|
-
|
|
109
|
-
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
def initialize_type_map m = type_map
|
|
183
|
+
m.register_type "BOOL", Type::Boolean.new
|
|
184
|
+
register_class_with_limit(
|
|
185
|
+
m, %r{^BYTES}i, ActiveRecord::Type::Spanner::Bytes
|
|
186
|
+
)
|
|
187
|
+
m.register_type "DATE", Type::Date.new
|
|
188
|
+
m.register_type "FLOAT64", Type::Float.new
|
|
189
|
+
m.register_type "NUMERIC", Type::Decimal.new
|
|
190
|
+
m.register_type "INT64", Type::Integer.new(limit: 8)
|
|
191
|
+
register_class_with_limit m, %r{^STRING}i, Type::String
|
|
192
|
+
m.register_type "TIMESTAMP", ActiveRecord::Type::Spanner::Time.new
|
|
193
|
+
|
|
194
|
+
register_array_types m
|
|
110
195
|
end
|
|
111
196
|
|
|
112
|
-
def
|
|
113
|
-
|
|
197
|
+
def register_array_types m
|
|
198
|
+
m.register_type %r{^ARRAY<BOOL>}i, Type::Spanner::Array.new(Type::Boolean.new)
|
|
199
|
+
m.register_type %r{^ARRAY<BYTES\((MAX|d+)\)>}i, Type::Spanner::Array.new(Type::Binary.new)
|
|
200
|
+
m.register_type %r{^ARRAY<DATE>}i, Type::Spanner::Array.new(Type::Date.new)
|
|
201
|
+
m.register_type %r{^ARRAY<FLOAT64>}i, Type::Spanner::Array.new(Type::Float.new)
|
|
202
|
+
m.register_type %r{^ARRAY<NUMERIC>}i, Type::Spanner::Array.new(Type::Decimal.new)
|
|
203
|
+
m.register_type %r{^ARRAY<INT64>}i, Type::Spanner::Array.new(Type::Integer.new(limit: 8))
|
|
204
|
+
m.register_type %r{^ARRAY<STRING\((MAX|d+)\)>}i, Type::Spanner::Array.new(Type::String.new)
|
|
205
|
+
m.register_type %r{^ARRAY<TIMESTAMP>}i, Type::Spanner::Array.new(ActiveRecord::Type::Spanner::Time.new)
|
|
114
206
|
end
|
|
115
207
|
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
|
|
208
|
+
def extract_limit sql_type
|
|
209
|
+
value = /\((.*)\)/.match sql_type
|
|
210
|
+
return unless value
|
|
211
|
+
|
|
212
|
+
value[1] == "MAX" ? "MAX" : value[1].to_i
|
|
119
213
|
end
|
|
120
214
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
215
|
+
def translate_exception exception, message:, sql:, binds:
|
|
216
|
+
if exception.is_a? Google::Cloud::FailedPreconditionError
|
|
217
|
+
case exception.message
|
|
218
|
+
when /.*does not specify a non-null value for these NOT NULL columns.*/,
|
|
219
|
+
/.*must not be NULL.*/
|
|
220
|
+
NotNullViolation.new message, sql: sql, binds: binds
|
|
221
|
+
else
|
|
222
|
+
super
|
|
223
|
+
end
|
|
224
|
+
else
|
|
225
|
+
super
|
|
226
|
+
end
|
|
227
|
+
end
|
|
124
228
|
end
|
|
125
229
|
end
|
|
126
230
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Copyright 2020 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 "active_record/connection_adapters/spanner_adapter"
|
|
8
|
+
|
|
9
|
+
module ActiveRecord
|
|
10
|
+
module Tasks
|
|
11
|
+
class SpannerDatabaseTasks
|
|
12
|
+
def initialize config
|
|
13
|
+
config = config.symbolize_keys
|
|
14
|
+
@connection = ActiveRecordSpannerAdapter::Connection.new config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create
|
|
18
|
+
@connection.create_database
|
|
19
|
+
rescue Google::Cloud::Error => error
|
|
20
|
+
if error.instance_of? Google::Cloud::AlreadyExistsError
|
|
21
|
+
raise ActiveRecord::Tasks::DatabaseAlreadyExists
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
raise error
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def drop
|
|
28
|
+
@connection.database.drop
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def purge
|
|
32
|
+
drop
|
|
33
|
+
create
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def charset
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def collation
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def structure_dump filename, _extra_flags
|
|
45
|
+
file = File.open filename, "w"
|
|
46
|
+
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
|
47
|
+
|
|
48
|
+
if ignore_tables.any?
|
|
49
|
+
index_regx = /^CREATE(.*)INDEX(.*)ON (#{ignore_tables.join "|"})\(/
|
|
50
|
+
table_regx = /^CREATE TABLE (#{ignore_tables.join "|"})/
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@connection.database.ddl(force: true).each do |statement|
|
|
54
|
+
next if ignore_tables.any? &&
|
|
55
|
+
(table_regx =~ statement || index_regx =~ statement)
|
|
56
|
+
file.write statement
|
|
57
|
+
file.write "\n"
|
|
58
|
+
end
|
|
59
|
+
ensure
|
|
60
|
+
file.close
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def structure_load filename, _extra_flags
|
|
64
|
+
statements = File.read(filename).split(/(?=^CREATE)/)
|
|
65
|
+
@connection.execute_ddl statements
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
DatabaseTasks.register_task(
|
|
70
|
+
/spanner/,
|
|
71
|
+
"ActiveRecord::Tasks::SpannerDatabaseTasks"
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
module ActiveRecord
|
|
8
|
+
module Type
|
|
9
|
+
module Spanner
|
|
10
|
+
class Array < Type::Value
|
|
11
|
+
attr_reader :element_type
|
|
12
|
+
delegate :type, :user_input_in_time_zone, :limit, :precision, :scale, to: :element_type
|
|
13
|
+
|
|
14
|
+
def initialize element_type
|
|
15
|
+
@element_type = element_type
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def serialize value
|
|
19
|
+
return super if value.nil?
|
|
20
|
+
return super unless @element_type.is_a? Type::Decimal
|
|
21
|
+
return super unless value.respond_to? :map
|
|
22
|
+
|
|
23
|
+
# Convert a decimal (NUMERIC) array to a String array to prevent it from being encoded as a FLOAT64 array.
|
|
24
|
+
value.map do |v|
|
|
25
|
+
next if v.nil?
|
|
26
|
+
v.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|