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,80 @@
|
|
|
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
|
+
require "test_helper"
|
|
10
|
+
|
|
11
|
+
module ActiveRecord
|
|
12
|
+
class Migration
|
|
13
|
+
class DDLBatchingTest < SpannerAdapter::TestCase
|
|
14
|
+
include SpannerAdapter::Migration::TestHelper
|
|
15
|
+
include ActiveSupport::Testing::Stream
|
|
16
|
+
|
|
17
|
+
class Box < ActiveRecord::Base
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class CreateBoxMigration < ActiveRecord::Migration::Current
|
|
21
|
+
def change
|
|
22
|
+
connection.ddl_batch do
|
|
23
|
+
create_table("boxes") do |t|
|
|
24
|
+
t.string :name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
add_column :boxes, :length, :integer
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Box.create(name: "Box1", length: 10)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def setup
|
|
35
|
+
skip_test_table_create!
|
|
36
|
+
|
|
37
|
+
super
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def teardown
|
|
41
|
+
super
|
|
42
|
+
|
|
43
|
+
connection.ddl_batch do
|
|
44
|
+
[:boxes, :ddl_batch_test].each do |name|
|
|
45
|
+
if connection.table_exists?(name)
|
|
46
|
+
connection.drop_table name
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_ddl_batching
|
|
53
|
+
information_schema = connection.send :information_schema
|
|
54
|
+
|
|
55
|
+
connection.ddl_batch do
|
|
56
|
+
connection.create_table("ddl_batch_test") do |t|
|
|
57
|
+
t.string :name
|
|
58
|
+
end
|
|
59
|
+
connection.add_column :ddl_batch_test, :created_at, :time
|
|
60
|
+
|
|
61
|
+
assert_not information_schema.table(:ddl_batch_test)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
assert information_schema.table(:ddl_batch_test)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_ddl_batching_with_dml_statement
|
|
68
|
+
migration = CreateBoxMigration.new
|
|
69
|
+
silence_stream($stdout) { migration.migrate(:up) }
|
|
70
|
+
|
|
71
|
+
assert connection.table_exists?(:boxes)
|
|
72
|
+
assert connection.column_exists?(:boxes, :length, :integer)
|
|
73
|
+
|
|
74
|
+
assert_equal 1, Box.count
|
|
75
|
+
box = Box.first
|
|
76
|
+
assert_equal 10, box.length
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,297 @@
|
|
|
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
|
+
require "test_helper"
|
|
10
|
+
|
|
11
|
+
module ActiveRecord
|
|
12
|
+
class Migration
|
|
13
|
+
class ForeignKeyTest < SpannerAdapter::TestCase
|
|
14
|
+
include SpannerAdapter::Migration::TestHelper
|
|
15
|
+
include ActiveSupport::Testing::Stream
|
|
16
|
+
|
|
17
|
+
class Rocket < ActiveRecord::Base
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Astronaut < ActiveRecord::Base
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def setup
|
|
24
|
+
skip_test_table_create!
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
connection.ddl_batch do
|
|
28
|
+
connection.create_table "rockets", force: true do |t|
|
|
29
|
+
t.string :name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
connection.create_table "astronauts", force: true do |t|
|
|
33
|
+
t.string :name
|
|
34
|
+
t.references :rocket
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def teardown
|
|
40
|
+
connection.ddl_batch do
|
|
41
|
+
connection.drop_table "astronauts", if_exists: true
|
|
42
|
+
connection.drop_table "rockets", if_exists: true
|
|
43
|
+
connection.drop_table "fk_test_has_fk", if_exists: true
|
|
44
|
+
connection.drop_table "fk_test_has_pk", if_exists: true
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_foreign_keys
|
|
49
|
+
connection.ddl_batch do
|
|
50
|
+
connection.create_table :fk_test_has_pk, primary_key: "pk_id", force: :cascade do |t|
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
connection.create_table :fk_test_has_fk, force: true do |t|
|
|
54
|
+
t.references :fk, null: false
|
|
55
|
+
t.foreign_key :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
foreign_keys = connection.foreign_keys("fk_test_has_fk")
|
|
60
|
+
assert_equal 1, foreign_keys.size
|
|
61
|
+
|
|
62
|
+
fk = foreign_keys.first
|
|
63
|
+
assert_equal "fk_test_has_fk", fk.from_table
|
|
64
|
+
assert_equal "fk_test_has_pk", fk.to_table
|
|
65
|
+
assert_equal "fk_id", fk.column
|
|
66
|
+
assert_equal "pk_id", fk.primary_key
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_add_foreign_key_inferes_column
|
|
70
|
+
connection.ddl_batch do
|
|
71
|
+
connection.add_foreign_key :astronauts, :rockets
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
foreign_keys = connection.foreign_keys("astronauts")
|
|
75
|
+
assert_equal 1, foreign_keys.size
|
|
76
|
+
|
|
77
|
+
fk = foreign_keys.first
|
|
78
|
+
assert_equal "astronauts", fk.from_table
|
|
79
|
+
assert_equal "rockets", fk.to_table
|
|
80
|
+
assert_equal "rocket_id", fk.column
|
|
81
|
+
assert_equal "id", fk.primary_key
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_add_foreign_key_with_column
|
|
85
|
+
connection.ddl_batch do
|
|
86
|
+
connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
foreign_keys = connection.foreign_keys("astronauts")
|
|
90
|
+
assert_equal 1, foreign_keys.size
|
|
91
|
+
|
|
92
|
+
fk = foreign_keys.first
|
|
93
|
+
assert_equal "astronauts", fk.from_table
|
|
94
|
+
assert_equal "rockets", fk.to_table
|
|
95
|
+
assert_equal "rocket_id", fk.column
|
|
96
|
+
assert_equal "id", fk.primary_key
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_add_foreign_key_with_non_standard_primary_key
|
|
100
|
+
connection.ddl_batch do
|
|
101
|
+
connection.create_table :space_shuttles, id: false, force: true do |t|
|
|
102
|
+
t.integer :pk, primary_key: true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
connection.add_foreign_key(:astronauts, :space_shuttles,
|
|
106
|
+
column: "rocket_id", primary_key: "pk", name: "custom_pk")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
foreign_keys = connection.foreign_keys("astronauts")
|
|
110
|
+
assert_equal 1, foreign_keys.size
|
|
111
|
+
|
|
112
|
+
fk = foreign_keys.first
|
|
113
|
+
assert_equal "astronauts", fk.from_table
|
|
114
|
+
assert_equal "space_shuttles", fk.to_table
|
|
115
|
+
assert_equal "pk", fk.primary_key
|
|
116
|
+
ensure
|
|
117
|
+
connection.ddl_batch do
|
|
118
|
+
connection.remove_foreign_key :astronauts, name: "custom_pk", to_table: "space_shuttles"
|
|
119
|
+
connection.drop_table :space_shuttles
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_foreign_key_exists
|
|
124
|
+
connection.ddl_batch do
|
|
125
|
+
connection.add_foreign_key :astronauts, :rockets
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
assert connection.foreign_key_exists?(:astronauts, :rockets)
|
|
129
|
+
assert_not connection.foreign_key_exists?(:astronauts, :stars)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_foreign_key_exists_by_column
|
|
133
|
+
connection.ddl_batch do
|
|
134
|
+
connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
assert connection.foreign_key_exists?(:astronauts, column: "rocket_id")
|
|
138
|
+
assert_not connection.foreign_key_exists?(:astronauts, column: "star_id")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_foreign_key_exists_by_name
|
|
142
|
+
connection.ddl_batch do
|
|
143
|
+
connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
assert connection.foreign_key_exists?(:astronauts, name: "fancy_named_fk")
|
|
147
|
+
assert_not connection.foreign_key_exists?(:astronauts, name: "other_fancy_named_fk")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_foreign_key_exists_in_change_table
|
|
151
|
+
connection.change_table(:astronauts) do |t|
|
|
152
|
+
t.foreign_key :rockets, column: "rocket_id", name: "fancy_named_fk"
|
|
153
|
+
|
|
154
|
+
assert t.foreign_key_exists?(column: "rocket_id")
|
|
155
|
+
assert_not t.foreign_key_exists?(column: "star_id")
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_remove_foreign_key_inferes_column
|
|
160
|
+
connection.ddl_batch do
|
|
161
|
+
connection.add_foreign_key :astronauts, :rockets
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
assert_equal 1, connection.foreign_keys("astronauts").size
|
|
165
|
+
connection.ddl_batch do
|
|
166
|
+
@connection.remove_foreign_key :astronauts, :rockets
|
|
167
|
+
end
|
|
168
|
+
assert_equal [], connection.foreign_keys("astronauts")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def test_remove_foreign_key_by_column
|
|
172
|
+
connection.ddl_batch do
|
|
173
|
+
connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
assert_equal 1, connection.foreign_keys("astronauts").size
|
|
177
|
+
connection.ddl_batch do
|
|
178
|
+
@connection.remove_foreign_key :astronauts, column: "rocket_id"
|
|
179
|
+
end
|
|
180
|
+
assert_equal [], connection.foreign_keys("astronauts")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def test_remove_foreign_key_by_symbol_column
|
|
184
|
+
connection.ddl_batch do
|
|
185
|
+
connection.add_foreign_key :astronauts, :rockets, column: :rocket_id
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
assert_equal 1, connection.foreign_keys("astronauts").size
|
|
189
|
+
connection.ddl_batch do
|
|
190
|
+
connection.remove_foreign_key :astronauts, column: :rocket_id
|
|
191
|
+
end
|
|
192
|
+
assert_equal [], connection.foreign_keys("astronauts")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def test_remove_foreign_key_by_name
|
|
196
|
+
connection.ddl_batch do
|
|
197
|
+
connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
assert_equal 1, connection.foreign_keys("astronauts").size
|
|
201
|
+
connection.ddl_batch do
|
|
202
|
+
connection.remove_foreign_key :astronauts, name: "fancy_named_fk"
|
|
203
|
+
end
|
|
204
|
+
assert_equal [], connection.foreign_keys("astronauts")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def test_remove_foreign_non_existing_foreign_key_raises
|
|
208
|
+
e = assert_raises ArgumentError do
|
|
209
|
+
connection.remove_foreign_key :astronauts, :rockets
|
|
210
|
+
end
|
|
211
|
+
assert_equal "Table 'astronauts' has no foreign key for rockets", e.message
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_remove_foreign_key_by_the_select_one_on_the_same_table
|
|
215
|
+
connection.ddl_batch do
|
|
216
|
+
connection.add_foreign_key :astronauts, :rockets
|
|
217
|
+
connection.add_reference :astronauts, :myrocket, foreign_key: { to_table: :rockets }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
assert_equal 2, connection.foreign_keys("astronauts").size
|
|
221
|
+
|
|
222
|
+
connection.ddl_batch do
|
|
223
|
+
connection.remove_foreign_key :astronauts, :rockets, column: "myrocket_id"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
assert_equal [["astronauts", "rockets", "rocket_id"]],
|
|
227
|
+
connection.foreign_keys("astronauts").map { |fk| [fk.from_table, fk.to_table, fk.column] }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
class CreateCitiesAndHousesMigration < ActiveRecord::Migration::Current
|
|
231
|
+
def change
|
|
232
|
+
connection.ddl_batch do
|
|
233
|
+
create_table("cities") { |t| }
|
|
234
|
+
|
|
235
|
+
create_table("houses") do |t|
|
|
236
|
+
t.references :city
|
|
237
|
+
end
|
|
238
|
+
add_foreign_key :houses, :cities, column: "city_id"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# remove and re-add to test that schema is updated and not accidentally cached
|
|
242
|
+
remove_foreign_key :houses, :cities
|
|
243
|
+
add_foreign_key :houses, :cities, column: "city_id"
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def test_add_foreign_key_is_reversible
|
|
248
|
+
migration = CreateCitiesAndHousesMigration.new
|
|
249
|
+
silence_stream($stdout) { migration.migrate(:up) }
|
|
250
|
+
assert_equal 1, connection.foreign_keys("houses").size
|
|
251
|
+
ensure
|
|
252
|
+
silence_stream($stdout) { migration.migrate(:down) }
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
class CreateSchoolsAndClassesMigration < ActiveRecord::Migration::Current
|
|
256
|
+
def up
|
|
257
|
+
connection.ddl_batch do
|
|
258
|
+
create_table(:schools)
|
|
259
|
+
|
|
260
|
+
create_table(:classes) do |t|
|
|
261
|
+
t.references :school
|
|
262
|
+
end
|
|
263
|
+
add_foreign_key :classes, :schools
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def down
|
|
268
|
+
connection.ddl_batch do
|
|
269
|
+
drop_table :classes, if_exists: true
|
|
270
|
+
drop_table :schools, if_exists: true
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def test_add_foreign_key_with_prefix
|
|
276
|
+
ActiveRecord::Base.table_name_prefix = "p_"
|
|
277
|
+
migration = CreateSchoolsAndClassesMigration.new
|
|
278
|
+
silence_stream($stdout) { migration.migrate(:up) }
|
|
279
|
+
assert_equal 1, connection.foreign_keys("p_classes").size
|
|
280
|
+
ensure
|
|
281
|
+
silence_stream($stdout) { migration.migrate(:down) }
|
|
282
|
+
ActiveRecord::Base.table_name_prefix = nil
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def test_add_foreign_key_with_suffix
|
|
286
|
+
ActiveRecord::Base.table_name_suffix = "_s"
|
|
287
|
+
migration = CreateSchoolsAndClassesMigration.new
|
|
288
|
+
silence_stream($stdout) { migration.migrate(:up) }
|
|
289
|
+
assert_equal 1, connection.foreign_keys("classes_s").size
|
|
290
|
+
ensure
|
|
291
|
+
silence_stream($stdout) { migration.migrate(:down) }
|
|
292
|
+
ActiveRecord::Base.table_name_suffix = nil
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
@@ -0,0 +1,211 @@
|
|
|
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
|
+
require "test_helper"
|
|
10
|
+
|
|
11
|
+
module ActiveRecord
|
|
12
|
+
class Migration
|
|
13
|
+
class IndexTest < SpannerAdapter::TestCase
|
|
14
|
+
include SpannerAdapter::Migration::TestHelper
|
|
15
|
+
|
|
16
|
+
attr_reader :table_name
|
|
17
|
+
|
|
18
|
+
def setup
|
|
19
|
+
skip_test_table_create!
|
|
20
|
+
super
|
|
21
|
+
|
|
22
|
+
@table_name = :testings
|
|
23
|
+
|
|
24
|
+
connection.ddl_batch do
|
|
25
|
+
connection.create_table table_name do |t|
|
|
26
|
+
t.column :foo, :string, limit: 100
|
|
27
|
+
t.column :bar, :string, limit: 100
|
|
28
|
+
|
|
29
|
+
t.string :first_name
|
|
30
|
+
t.string :last_name, limit: 100
|
|
31
|
+
t.string :key, limit: 100
|
|
32
|
+
t.boolean :administrator
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def teardown
|
|
38
|
+
connection.ddl_batch do
|
|
39
|
+
connection.drop_table :testings
|
|
40
|
+
end rescue nil
|
|
41
|
+
ActiveRecord::Base.primary_key_prefix_type = nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_rename_index
|
|
45
|
+
connection.add_index(table_name, [:foo], name: "old_idx")
|
|
46
|
+
connection.ddl_batch do
|
|
47
|
+
connection.rename_index(table_name, "old_idx", "new_idx")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
assert_not connection.index_name_exists?(table_name, "old_idx")
|
|
51
|
+
assert connection.index_name_exists?(table_name, "new_idx")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_rename_index_too_long
|
|
55
|
+
too_long_index_name = good_index_name + "x"
|
|
56
|
+
connection.add_index(table_name, [:foo], name: "old_idx")
|
|
57
|
+
e = assert_raises(ArgumentError) {
|
|
58
|
+
connection.rename_index(table_name, "old_idx", too_long_index_name)
|
|
59
|
+
}
|
|
60
|
+
assert_match(/too long; the limit is #{connection.index_name_length} characters/, e.message)
|
|
61
|
+
|
|
62
|
+
assert connection.index_name_exists?(table_name, "old_idx")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_remove_nonexistent_index
|
|
66
|
+
assert_raise(ArgumentError) { connection.remove_index(table_name, "no_such_index") }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_add_index_works_with_long_index_names
|
|
70
|
+
connection.add_index(table_name, "foo", name: good_index_name)
|
|
71
|
+
|
|
72
|
+
assert connection.index_name_exists?(table_name, good_index_name)
|
|
73
|
+
connection.remove_index(table_name, name: good_index_name)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_add_index_does_not_accept_too_long_index_names
|
|
77
|
+
too_long_index_name = good_index_name + "x"
|
|
78
|
+
|
|
79
|
+
e = assert_raises(ArgumentError) {
|
|
80
|
+
connection.add_index(table_name, "foo", name: too_long_index_name)
|
|
81
|
+
}
|
|
82
|
+
assert_match(/too long; the limit is #{connection.index_name_length} characters/, e.message)
|
|
83
|
+
|
|
84
|
+
assert_not connection.index_name_exists?(table_name, too_long_index_name)
|
|
85
|
+
connection.add_index(table_name, "foo", name: good_index_name)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_internal_index_with_name_matching_database_limit
|
|
89
|
+
good_index_name = "x" * connection.index_name_length
|
|
90
|
+
connection.add_index(table_name, "foo", name: good_index_name)
|
|
91
|
+
|
|
92
|
+
assert connection.index_name_exists?(table_name, good_index_name)
|
|
93
|
+
connection.remove_index(table_name, name: good_index_name)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_index_symbol_names
|
|
97
|
+
connection.add_index table_name, :foo, name: :symbol_index_name
|
|
98
|
+
assert connection.index_exists?(table_name, :foo, name: :symbol_index_name)
|
|
99
|
+
|
|
100
|
+
connection.remove_index table_name, name: :symbol_index_name
|
|
101
|
+
assert_not connection.index_exists?(table_name, :foo, name: :symbol_index_name)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_index_exists
|
|
105
|
+
connection.add_index :testings, :foo
|
|
106
|
+
|
|
107
|
+
assert connection.index_exists?(:testings, :foo)
|
|
108
|
+
assert_not connection.index_exists?(:testings, :bar)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_index_exists_on_multiple_columns
|
|
112
|
+
connection.add_index :testings, [:foo, :bar]
|
|
113
|
+
|
|
114
|
+
assert connection.index_exists?(:testings, [:foo, :bar])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_index_exists_with_custom_name_checks_columns
|
|
118
|
+
connection.add_index :testings, [:foo, :bar], name: "my_index"
|
|
119
|
+
assert connection.index_exists?(:testings, [:foo, :bar], name: "my_index")
|
|
120
|
+
assert_not connection.index_exists?(:testings, [:foo], name: "my_index")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_valid_index_options
|
|
124
|
+
assert_raise ArgumentError do
|
|
125
|
+
connection.add_index :testings, :foo, unqiue: true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def test_unique_index_exists
|
|
130
|
+
connection.add_index :testings, :foo, unique: true
|
|
131
|
+
|
|
132
|
+
assert connection.index_exists?(:testings, :foo, unique: true)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def test_order_index_exists
|
|
136
|
+
connection.add_index :testings, :foo, order: { foo: :desc }
|
|
137
|
+
|
|
138
|
+
assert connection.index_exists?(:testings, :foo)
|
|
139
|
+
|
|
140
|
+
index = connection.indexes(:testings).first
|
|
141
|
+
assert_equal({ foo: :desc }, index.orders)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_named_index_exists
|
|
145
|
+
connection.add_index :testings, :foo, name: "custom_index_name"
|
|
146
|
+
|
|
147
|
+
assert connection.index_exists?(:testings, :foo)
|
|
148
|
+
assert connection.index_exists?(:testings, :foo, name: "custom_index_name")
|
|
149
|
+
assert_not connection.index_exists?(:testings, :foo, name: "other_index_name")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def test_remove_named_index
|
|
153
|
+
connection.add_index :testings, :foo, name: "index_testings_on_custom_index_name"
|
|
154
|
+
|
|
155
|
+
assert connection.index_exists?(:testings, :foo)
|
|
156
|
+
|
|
157
|
+
assert_raise(ArgumentError) { connection.remove_index(:testings, "custom_index_name") }
|
|
158
|
+
|
|
159
|
+
connection.remove_index :testings, :foo
|
|
160
|
+
assert_not connection.index_exists?(:testings, :foo)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def test_add_index
|
|
164
|
+
connection.add_index("testings", "last_name")
|
|
165
|
+
connection.remove_index("testings", "last_name")
|
|
166
|
+
|
|
167
|
+
connection.add_index("testings", ["last_name", "first_name"])
|
|
168
|
+
connection.remove_index("testings", column: ["last_name", "first_name"])
|
|
169
|
+
|
|
170
|
+
connection.add_index("testings", ["last_name", "first_name"])
|
|
171
|
+
connection.remove_index("testings", name: :index_testings_on_last_name_and_first_name)
|
|
172
|
+
connection.add_index("testings", ["last_name", "first_name"])
|
|
173
|
+
connection.remove_index("testings", "last_name_and_first_name")
|
|
174
|
+
|
|
175
|
+
connection.add_index("testings", ["last_name", "first_name"])
|
|
176
|
+
connection.remove_index("testings", ["last_name", "first_name"])
|
|
177
|
+
|
|
178
|
+
connection.add_index("testings", "key", unique: true)
|
|
179
|
+
connection.remove_index("testings", "key")
|
|
180
|
+
|
|
181
|
+
connection.add_index("testings", ["key"], name: "key_idx", unique: true)
|
|
182
|
+
connection.remove_index("testings", name: "key_idx")
|
|
183
|
+
|
|
184
|
+
connection.add_index("testings", %w(last_name first_name administrator), name: "named_admin")
|
|
185
|
+
connection.remove_index("testings", name: "named_admin")
|
|
186
|
+
|
|
187
|
+
connection.add_index("testings", ["last_name"], order: { last_name: :desc })
|
|
188
|
+
connection.remove_index("testings", ["last_name"])
|
|
189
|
+
connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc })
|
|
190
|
+
connection.remove_index("testings", ["last_name", "first_name"])
|
|
191
|
+
connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc, first_name: :asc })
|
|
192
|
+
connection.remove_index("testings", ["last_name", "first_name"])
|
|
193
|
+
connection.add_index("testings", ["last_name", "first_name"], order: :desc)
|
|
194
|
+
connection.remove_index("testings", ["last_name", "first_name"])
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def test_add_interleaved_index
|
|
198
|
+
connection.add_index "albums", ["singerid", "title"], interleave_in: :singers
|
|
199
|
+
index = connection.indexes(:albums).first
|
|
200
|
+
|
|
201
|
+
assert index, "Could not find interleaved index"
|
|
202
|
+
assert_equal "singers", index.interleave_in
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
private
|
|
206
|
+
def good_index_name
|
|
207
|
+
"x" * connection.index_name_length
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|