activerecord-spanner-adapter 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +7 -0
  3. data/.github/sync-repo-settings.yaml +16 -0
  4. data/.github/workflows/acceptance-tests-on-emulator.yaml +45 -0
  5. data/.github/workflows/acceptance-tests-on-production.yaml +49 -0
  6. data/.github/workflows/ci.yaml +33 -0
  7. data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +52 -0
  8. data/.github/workflows/nightly-acceptance-tests-on-production.yaml +35 -0
  9. data/.github/workflows/nightly-unit-tests.yaml +40 -0
  10. data/.github/workflows/release-please-label.yml +25 -0
  11. data/.github/workflows/release-please.yml +39 -0
  12. data/.github/workflows/rubocop.yaml +31 -0
  13. data/.gitignore +67 -5
  14. data/.kokoro/populate-secrets.sh +77 -0
  15. data/.kokoro/release.cfg +33 -0
  16. data/.kokoro/release.sh +15 -0
  17. data/.kokoro/trampoline_v2.sh +489 -0
  18. data/.rubocop.yml +46 -0
  19. data/.toys/release.rb +18 -0
  20. data/.trampolinerc +48 -0
  21. data/.yardopts +11 -0
  22. data/CHANGELOG.md +55 -0
  23. data/CODE_OF_CONDUCT.md +40 -0
  24. data/CONTRIBUTING.md +79 -0
  25. data/Gemfile +9 -4
  26. data/LICENSE +6 -6
  27. data/README.md +66 -30
  28. data/Rakefile +79 -3
  29. data/SECURITY.md +7 -0
  30. data/acceptance/cases/associations/has_many_associations_test.rb +119 -0
  31. data/acceptance/cases/associations/has_many_through_associations_test.rb +63 -0
  32. data/acceptance/cases/associations/has_one_associations_test.rb +79 -0
  33. data/acceptance/cases/associations/has_one_through_associations_test.rb +98 -0
  34. data/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb +211 -0
  35. data/acceptance/cases/migration/change_schema_test.rb +433 -0
  36. data/acceptance/cases/migration/change_table_test.rb +115 -0
  37. data/acceptance/cases/migration/column_attributes_test.rb +122 -0
  38. data/acceptance/cases/migration/column_positioning_test.rb +48 -0
  39. data/acceptance/cases/migration/columns_test.rb +201 -0
  40. data/acceptance/cases/migration/command_recorder_test.rb +406 -0
  41. data/acceptance/cases/migration/create_join_table_test.rb +216 -0
  42. data/acceptance/cases/migration/ddl_batching_test.rb +80 -0
  43. data/acceptance/cases/migration/foreign_key_test.rb +297 -0
  44. data/acceptance/cases/migration/index_test.rb +211 -0
  45. data/acceptance/cases/migration/references_foreign_key_test.rb +259 -0
  46. data/acceptance/cases/migration/references_index_test.rb +135 -0
  47. data/acceptance/cases/migration/references_statements_test.rb +166 -0
  48. data/acceptance/cases/migration/rename_column_test.rb +96 -0
  49. data/acceptance/cases/models/calculation_query_test.rb +128 -0
  50. data/acceptance/cases/models/generated_column_test.rb +126 -0
  51. data/acceptance/cases/models/mutation_test.rb +122 -0
  52. data/acceptance/cases/models/query_test.rb +171 -0
  53. data/acceptance/cases/sessions/session_not_found_test.rb +121 -0
  54. data/acceptance/cases/transactions/optimistic_locking_test.rb +141 -0
  55. data/acceptance/cases/transactions/read_only_transactions_test.rb +130 -0
  56. data/acceptance/cases/transactions/read_write_transactions_test.rb +248 -0
  57. data/acceptance/cases/type/all_types_test.rb +172 -0
  58. data/acceptance/cases/type/binary_test.rb +59 -0
  59. data/acceptance/cases/type/boolean_test.rb +31 -0
  60. data/acceptance/cases/type/date_test.rb +32 -0
  61. data/acceptance/cases/type/date_time_test.rb +30 -0
  62. data/acceptance/cases/type/float_test.rb +27 -0
  63. data/acceptance/cases/type/integer_test.rb +44 -0
  64. data/acceptance/cases/type/json_test.rb +34 -0
  65. data/acceptance/cases/type/numeric_test.rb +27 -0
  66. data/acceptance/cases/type/string_test.rb +79 -0
  67. data/acceptance/cases/type/text_test.rb +30 -0
  68. data/acceptance/cases/type/time_test.rb +87 -0
  69. data/acceptance/models/account.rb +13 -0
  70. data/acceptance/models/address.rb +9 -0
  71. data/acceptance/models/album.rb +12 -0
  72. data/acceptance/models/all_types.rb +8 -0
  73. data/acceptance/models/author.rb +11 -0
  74. data/acceptance/models/club.rb +12 -0
  75. data/acceptance/models/comment.rb +9 -0
  76. data/acceptance/models/customer.rb +9 -0
  77. data/acceptance/models/department.rb +9 -0
  78. data/acceptance/models/firm.rb +10 -0
  79. data/acceptance/models/member.rb +13 -0
  80. data/acceptance/models/member_type.rb +9 -0
  81. data/acceptance/models/membership.rb +10 -0
  82. data/acceptance/models/organization.rb +9 -0
  83. data/acceptance/models/post.rb +10 -0
  84. data/acceptance/models/singer.rb +10 -0
  85. data/acceptance/models/track.rb +20 -0
  86. data/acceptance/models/transaction.rb +9 -0
  87. data/acceptance/schema/schema.rb +147 -0
  88. data/acceptance/test_helper.rb +261 -0
  89. data/activerecord-spanner-adapter.gemspec +32 -17
  90. data/assets/solidus-db.png +0 -0
  91. data/benchmarks/README.md +17 -0
  92. data/benchmarks/Rakefile +14 -0
  93. data/benchmarks/application.rb +308 -0
  94. data/benchmarks/config/database.yml +8 -0
  95. data/benchmarks/config/environment.rb +12 -0
  96. data/benchmarks/db/migrate/01_create_tables.rb +25 -0
  97. data/benchmarks/db/schema.rb +29 -0
  98. data/benchmarks/models/album.rb +9 -0
  99. data/benchmarks/models/singer.rb +9 -0
  100. data/bin/console +6 -7
  101. data/examples/rails/README.md +262 -0
  102. data/examples/snippets/README.md +29 -0
  103. data/examples/snippets/Rakefile +57 -0
  104. data/examples/snippets/array-data-type/README.md +45 -0
  105. data/examples/snippets/array-data-type/Rakefile +13 -0
  106. data/examples/snippets/array-data-type/application.rb +45 -0
  107. data/examples/snippets/array-data-type/config/database.yml +8 -0
  108. data/examples/snippets/array-data-type/db/migrate/01_create_tables.rb +24 -0
  109. data/examples/snippets/array-data-type/db/schema.rb +26 -0
  110. data/examples/snippets/array-data-type/db/seeds.rb +5 -0
  111. data/examples/snippets/array-data-type/models/entity_with_array_types.rb +18 -0
  112. data/examples/snippets/bin/create_emulator_instance.rb +18 -0
  113. data/examples/snippets/bulk-insert/README.md +21 -0
  114. data/examples/snippets/bulk-insert/Rakefile +13 -0
  115. data/examples/snippets/bulk-insert/application.rb +64 -0
  116. data/examples/snippets/bulk-insert/config/database.yml +8 -0
  117. data/examples/snippets/bulk-insert/db/migrate/01_create_tables.rb +21 -0
  118. data/examples/snippets/bulk-insert/db/schema.rb +26 -0
  119. data/examples/snippets/bulk-insert/db/seeds.rb +5 -0
  120. data/examples/snippets/bulk-insert/models/album.rb +9 -0
  121. data/examples/snippets/bulk-insert/models/singer.rb +9 -0
  122. data/examples/snippets/commit-timestamp/README.md +18 -0
  123. data/examples/snippets/commit-timestamp/Rakefile +13 -0
  124. data/examples/snippets/commit-timestamp/application.rb +53 -0
  125. data/examples/snippets/commit-timestamp/config/database.yml +8 -0
  126. data/examples/snippets/commit-timestamp/db/migrate/01_create_tables.rb +26 -0
  127. data/examples/snippets/commit-timestamp/db/schema.rb +29 -0
  128. data/examples/snippets/commit-timestamp/db/seeds.rb +5 -0
  129. data/examples/snippets/commit-timestamp/models/album.rb +9 -0
  130. data/examples/snippets/commit-timestamp/models/singer.rb +9 -0
  131. data/examples/snippets/config/environment.rb +21 -0
  132. data/examples/snippets/create-records/README.md +12 -0
  133. data/examples/snippets/create-records/Rakefile +13 -0
  134. data/examples/snippets/create-records/application.rb +42 -0
  135. data/examples/snippets/create-records/config/database.yml +8 -0
  136. data/examples/snippets/create-records/db/migrate/01_create_tables.rb +21 -0
  137. data/examples/snippets/create-records/db/schema.rb +26 -0
  138. data/examples/snippets/create-records/db/seeds.rb +5 -0
  139. data/examples/snippets/create-records/models/album.rb +9 -0
  140. data/examples/snippets/create-records/models/singer.rb +9 -0
  141. data/examples/snippets/date-data-type/README.md +19 -0
  142. data/examples/snippets/date-data-type/Rakefile +13 -0
  143. data/examples/snippets/date-data-type/application.rb +35 -0
  144. data/examples/snippets/date-data-type/config/database.yml +8 -0
  145. data/examples/snippets/date-data-type/db/migrate/01_create_tables.rb +20 -0
  146. data/examples/snippets/date-data-type/db/schema.rb +21 -0
  147. data/examples/snippets/date-data-type/db/seeds.rb +16 -0
  148. data/examples/snippets/date-data-type/models/singer.rb +8 -0
  149. data/examples/snippets/generated-column/README.md +41 -0
  150. data/examples/snippets/generated-column/Rakefile +13 -0
  151. data/examples/snippets/generated-column/application.rb +37 -0
  152. data/examples/snippets/generated-column/config/database.yml +8 -0
  153. data/examples/snippets/generated-column/db/migrate/01_create_tables.rb +23 -0
  154. data/examples/snippets/generated-column/db/schema.rb +21 -0
  155. data/examples/snippets/generated-column/db/seeds.rb +18 -0
  156. data/examples/snippets/generated-column/models/singer.rb +8 -0
  157. data/examples/snippets/hints/README.md +19 -0
  158. data/examples/snippets/hints/Rakefile +13 -0
  159. data/examples/snippets/hints/application.rb +47 -0
  160. data/examples/snippets/hints/config/database.yml +8 -0
  161. data/examples/snippets/hints/db/migrate/01_create_tables.rb +23 -0
  162. data/examples/snippets/hints/db/schema.rb +28 -0
  163. data/examples/snippets/hints/db/seeds.rb +29 -0
  164. data/examples/snippets/hints/models/album.rb +9 -0
  165. data/examples/snippets/hints/models/singer.rb +9 -0
  166. data/examples/snippets/migrations/README.md +43 -0
  167. data/examples/snippets/migrations/Rakefile +13 -0
  168. data/examples/snippets/migrations/application.rb +26 -0
  169. data/examples/snippets/migrations/config/database.yml +8 -0
  170. data/examples/snippets/migrations/db/migrate/01_create_tables.rb +28 -0
  171. data/examples/snippets/migrations/db/schema.rb +33 -0
  172. data/examples/snippets/migrations/db/seeds.rb +5 -0
  173. data/examples/snippets/migrations/models/album.rb +10 -0
  174. data/examples/snippets/migrations/models/singer.rb +10 -0
  175. data/examples/snippets/migrations/models/track.rb +9 -0
  176. data/examples/snippets/mutations/README.md +34 -0
  177. data/examples/snippets/mutations/Rakefile +13 -0
  178. data/examples/snippets/mutations/application.rb +47 -0
  179. data/examples/snippets/mutations/config/database.yml +8 -0
  180. data/examples/snippets/mutations/db/migrate/01_create_tables.rb +22 -0
  181. data/examples/snippets/mutations/db/schema.rb +27 -0
  182. data/examples/snippets/mutations/db/seeds.rb +25 -0
  183. data/examples/snippets/mutations/models/album.rb +9 -0
  184. data/examples/snippets/mutations/models/singer.rb +9 -0
  185. data/examples/snippets/optimistic-locking/README.md +12 -0
  186. data/examples/snippets/optimistic-locking/Rakefile +13 -0
  187. data/examples/snippets/optimistic-locking/application.rb +48 -0
  188. data/examples/snippets/optimistic-locking/config/database.yml +8 -0
  189. data/examples/snippets/optimistic-locking/db/migrate/01_create_tables.rb +26 -0
  190. data/examples/snippets/optimistic-locking/db/schema.rb +29 -0
  191. data/examples/snippets/optimistic-locking/db/seeds.rb +25 -0
  192. data/examples/snippets/optimistic-locking/models/album.rb +9 -0
  193. data/examples/snippets/optimistic-locking/models/singer.rb +9 -0
  194. data/examples/snippets/partitioned-dml/README.md +16 -0
  195. data/examples/snippets/partitioned-dml/Rakefile +13 -0
  196. data/examples/snippets/partitioned-dml/application.rb +48 -0
  197. data/examples/snippets/partitioned-dml/config/database.yml +8 -0
  198. data/examples/snippets/partitioned-dml/db/migrate/01_create_tables.rb +21 -0
  199. data/examples/snippets/partitioned-dml/db/schema.rb +26 -0
  200. data/examples/snippets/partitioned-dml/db/seeds.rb +29 -0
  201. data/examples/snippets/partitioned-dml/models/album.rb +9 -0
  202. data/examples/snippets/partitioned-dml/models/singer.rb +9 -0
  203. data/examples/snippets/quickstart/README.md +26 -0
  204. data/examples/snippets/quickstart/Rakefile +13 -0
  205. data/examples/snippets/quickstart/application.rb +51 -0
  206. data/examples/snippets/quickstart/config/database.yml +8 -0
  207. data/examples/snippets/quickstart/db/migrate/01_create_tables.rb +21 -0
  208. data/examples/snippets/quickstart/db/schema.rb +26 -0
  209. data/examples/snippets/quickstart/db/seeds.rb +24 -0
  210. data/examples/snippets/quickstart/models/album.rb +9 -0
  211. data/examples/snippets/quickstart/models/singer.rb +9 -0
  212. data/examples/snippets/read-only-transactions/README.md +13 -0
  213. data/examples/snippets/read-only-transactions/Rakefile +13 -0
  214. data/examples/snippets/read-only-transactions/application.rb +77 -0
  215. data/examples/snippets/read-only-transactions/config/database.yml +8 -0
  216. data/examples/snippets/read-only-transactions/db/migrate/01_create_tables.rb +21 -0
  217. data/examples/snippets/read-only-transactions/db/schema.rb +26 -0
  218. data/examples/snippets/read-only-transactions/db/seeds.rb +24 -0
  219. data/examples/snippets/read-only-transactions/models/album.rb +9 -0
  220. data/examples/snippets/read-only-transactions/models/singer.rb +9 -0
  221. data/examples/snippets/read-write-transactions/README.md +12 -0
  222. data/examples/snippets/read-write-transactions/Rakefile +13 -0
  223. data/examples/snippets/read-write-transactions/application.rb +39 -0
  224. data/examples/snippets/read-write-transactions/config/database.yml +8 -0
  225. data/examples/snippets/read-write-transactions/db/migrate/01_create_tables.rb +22 -0
  226. data/examples/snippets/read-write-transactions/db/schema.rb +27 -0
  227. data/examples/snippets/read-write-transactions/db/seeds.rb +25 -0
  228. data/examples/snippets/read-write-transactions/models/album.rb +9 -0
  229. data/examples/snippets/read-write-transactions/models/singer.rb +9 -0
  230. data/examples/snippets/stale-reads/README.md +27 -0
  231. data/examples/snippets/stale-reads/Rakefile +13 -0
  232. data/examples/snippets/stale-reads/application.rb +63 -0
  233. data/examples/snippets/stale-reads/config/database.yml +8 -0
  234. data/examples/snippets/stale-reads/db/migrate/01_create_tables.rb +21 -0
  235. data/examples/snippets/stale-reads/db/schema.rb +26 -0
  236. data/examples/snippets/stale-reads/db/seeds.rb +24 -0
  237. data/examples/snippets/stale-reads/models/album.rb +9 -0
  238. data/examples/snippets/stale-reads/models/singer.rb +9 -0
  239. data/examples/snippets/timestamp-data-type/README.md +17 -0
  240. data/examples/snippets/timestamp-data-type/Rakefile +13 -0
  241. data/examples/snippets/timestamp-data-type/application.rb +42 -0
  242. data/examples/snippets/timestamp-data-type/config/database.yml +8 -0
  243. data/examples/snippets/timestamp-data-type/db/migrate/01_create_tables.rb +21 -0
  244. data/examples/snippets/timestamp-data-type/db/schema.rb +21 -0
  245. data/examples/snippets/timestamp-data-type/db/seeds.rb +6 -0
  246. data/examples/snippets/timestamp-data-type/models/meeting.rb +19 -0
  247. data/examples/solidus/README.md +172 -0
  248. data/lib/active_record/connection_adapters/spanner/database_statements.rb +244 -266
  249. data/lib/active_record/connection_adapters/spanner/quoting.rb +42 -50
  250. data/lib/active_record/connection_adapters/spanner/schema_cache.rb +43 -0
  251. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +125 -9
  252. data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +122 -0
  253. data/lib/active_record/connection_adapters/spanner/schema_dumper.rb +19 -0
  254. data/lib/active_record/connection_adapters/spanner/schema_statements.rb +553 -139
  255. data/lib/active_record/connection_adapters/spanner/type_metadata.rb +37 -0
  256. data/lib/active_record/connection_adapters/spanner_adapter.rb +185 -78
  257. data/lib/active_record/tasks/spanner_database_tasks.rb +74 -0
  258. data/lib/active_record/type/spanner/array.rb +32 -0
  259. data/lib/active_record/type/spanner/bytes.rb +26 -0
  260. data/lib/active_record/type/spanner/spanner_active_record_converter.rb +33 -0
  261. data/lib/active_record/type/spanner/time.rb +37 -0
  262. data/lib/activerecord-spanner-adapter.rb +23 -0
  263. data/lib/activerecord_spanner_adapter/base.rb +238 -0
  264. data/lib/activerecord_spanner_adapter/connection.rb +350 -0
  265. data/lib/activerecord_spanner_adapter/errors.rb +13 -0
  266. data/lib/activerecord_spanner_adapter/foreign_key.rb +29 -0
  267. data/lib/activerecord_spanner_adapter/index/column.rb +38 -0
  268. data/lib/activerecord_spanner_adapter/index.rb +80 -0
  269. data/lib/activerecord_spanner_adapter/information_schema.rb +262 -0
  270. data/lib/activerecord_spanner_adapter/primary_key.rb +31 -0
  271. data/lib/activerecord_spanner_adapter/table/column.rb +59 -0
  272. data/lib/activerecord_spanner_adapter/table.rb +61 -0
  273. data/lib/activerecord_spanner_adapter/transaction.rb +154 -0
  274. data/lib/activerecord_spanner_adapter/version.rb +9 -0
  275. data/lib/arel/visitors/spanner.rb +111 -0
  276. data/lib/spanner_client_ext.rb +107 -0
  277. data/renovate.json +5 -0
  278. metadata +405 -34
  279. data/.travis.yml +0 -5
  280. data/lib/active_record/connection_adapters/spanner/client.rb +0 -190
  281. data/lib/active_record/connection_adapters/spanner.rb +0 -10
  282. data/lib/activerecord-spanner-adapter/version.rb +0 -3
@@ -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
@@ -0,0 +1,259 @@
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 ReferencesForeignKeyInCreateTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Migration::TestHelper
15
+
16
+ def setup
17
+ skip_test_table_create!
18
+ super
19
+ connection.ddl_batch do
20
+ @connection.create_table(:testing_parents, force: true)
21
+ end
22
+ end
23
+
24
+ def teardown
25
+ @connection.ddl_batch do
26
+ @connection.drop_table "testings", if_exists: true
27
+ @connection.drop_table "testing_parents", if_exists: true
28
+ end
29
+ end
30
+
31
+ def test_create_foreign_key_with_table_create
32
+ connection.ddl_batch do
33
+ connection.create_table :testings do |t|
34
+ t.references :testing_parent, foreign_key: true
35
+ end
36
+ end
37
+
38
+ fk = connection.foreign_keys("testings").first
39
+ assert_equal "testings", fk.from_table
40
+ assert_equal "testing_parents", fk.to_table
41
+ end
42
+
43
+ def test_create_foreign_key_created_by_default
44
+ connection.ddl_batch do
45
+ connection.create_table :testings do |t|
46
+ t.references :testing_parent
47
+ end
48
+ end
49
+
50
+ assert_equal [], @connection.foreign_keys("testings")
51
+ end
52
+
53
+ def test_options_can_be_passed
54
+ connection.ddl_batch do
55
+ connection.change_table :testing_parents do |t|
56
+ t.references :other, index: { unique: true }
57
+ end
58
+ connection.create_table :testings do |t|
59
+ t.references :testing_parent, foreign_key: { primary_key: :other_id }
60
+ end
61
+ end
62
+
63
+ fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" }
64
+ assert_equal "other_id", fk.primary_key
65
+ end
66
+
67
+ def test_to_table_options_can_be_passed
68
+ connection.ddl_batch do
69
+ @connection.create_table :testings do |t|
70
+ t.references :parent, foreign_key: { to_table: :testing_parents }
71
+ end
72
+ end
73
+ fks = @connection.foreign_keys("testings")
74
+ assert_equal([["testings", "testing_parents", "parent_id"]],
75
+ fks.map { |fk| [fk.from_table, fk.to_table, fk.column] })
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ module ActiveRecord
82
+ class Migration
83
+ class ReferencesForeignKeyTest < SpannerAdapter::TestCase
84
+ include SpannerAdapter::Migration::TestHelper
85
+ include ActiveSupport::Testing::Stream
86
+
87
+ def setup
88
+ skip_test_table_create!
89
+ super
90
+ connection = ActiveRecord::Base.connection
91
+ connection.ddl_batch do
92
+ connection.create_table(:testing_parents, force: true)
93
+ end
94
+ end
95
+
96
+ def teardown
97
+ connection.ddl_batch do
98
+ connection.drop_table "testings", if_exists: true
99
+ connection.drop_table "testing_parents", if_exists: true
100
+ end
101
+ end
102
+
103
+ def test_create_foreign_key_with_changing_table
104
+ connection.ddl_batch do
105
+ connection.create_table :testings
106
+ connection.change_table :testings do |t|
107
+ t.references :testing_parent, foreign_key: true
108
+ end
109
+ end
110
+
111
+ fk = connection.foreign_keys("testings").first
112
+ assert_equal "testings", fk.from_table
113
+ assert_equal "testing_parents", fk.to_table
114
+ end
115
+
116
+ def test_foreign_key_not_added_by_default_on_table_change
117
+ connection.create_table :testings
118
+ connection.change_table :testings do |t|
119
+ t.references :testing_parent
120
+ end
121
+
122
+ assert_equal [], connection.foreign_keys("testings")
123
+ end
124
+
125
+ def test_foreign_key_accept_option_on_table_change
126
+ connection.ddl_batch do
127
+ connection.change_table :testing_parents do |t|
128
+ t.references :other, index: { unique: true }
129
+ end
130
+ connection.create_table :testings
131
+ end
132
+ connection.change_table :testings do |t|
133
+ t.references :testing_parent, foreign_key: { primary_key: :other_id }
134
+ end
135
+
136
+ fk = connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" }
137
+ assert_equal "other_id", fk.primary_key
138
+ end
139
+
140
+ def test_foreign_key_column_can_be_removed
141
+ connection.ddl_batch do
142
+ connection.create_table :testings do |t|
143
+ t.references :testing_parent, index: true, foreign_key: true
144
+ end
145
+ end
146
+
147
+ connection.remove_reference :testings, :testing_parent, foreign_key: true
148
+ assert_equal 0, connection.foreign_keys('testings').size
149
+ end
150
+
151
+ def test_remove_column_removes_foreign_key
152
+ connection.ddl_batch do
153
+ connection.create_table :testings do |t|
154
+ t.references :testing_parent, index: true, foreign_key: true
155
+ end
156
+ end
157
+
158
+ connection.ddl_batch do
159
+ connection.remove_column :testings, :testing_parent_id
160
+ end
161
+ assert_equal 0, connection.foreign_keys('testings').size
162
+ end
163
+
164
+ def test_foreign_key_respect_pluralize_table_names
165
+ original_pluralize_table_names = ActiveRecord::Base.pluralize_table_names
166
+ ActiveRecord::Base.pluralize_table_names = false
167
+ connection.create_table :testing
168
+ connection.ddl_batch do
169
+ connection.change_table :testing_parents do |t|
170
+ t.references :testing, foreign_key: true
171
+ end
172
+ end
173
+
174
+ fk = connection.foreign_keys("testing_parents").first
175
+ assert_equal "testing_parents", fk.from_table
176
+ assert_equal "testing", fk.to_table
177
+
178
+ assert_difference "@connection.foreign_keys('testing_parents').size", -1 do
179
+ connection.remove_reference :testing_parents, :testing, foreign_key: true
180
+ end
181
+ ensure
182
+ ActiveRecord::Base.pluralize_table_names = original_pluralize_table_names
183
+ connection.ddl_batch do
184
+ connection.drop_table "testing", if_exists: true
185
+ end
186
+ end
187
+
188
+ class CreateDogsMigration < ActiveRecord::Migration::Current
189
+ def up
190
+ connection.ddl_batch do
191
+ create_table :dog_owners
192
+
193
+ create_table :dogs do |t|
194
+ t.references :dog_owner, foreign_key: true
195
+ end
196
+ end
197
+ end
198
+
199
+ def down
200
+ connection.ddl_batch do
201
+ drop_table :dogs, if_exists: true
202
+ drop_table :dog_owners, if_exists: true
203
+ end
204
+ end
205
+ end
206
+
207
+ def test_references_foreign_key_with_prefix
208
+ ActiveRecord::Base.table_name_prefix = "p_"
209
+ migration = CreateDogsMigration.new
210
+ silence_stream($stdout) { migration.migrate(:up) }
211
+ assert_equal 1, @connection.foreign_keys("p_dogs").size
212
+ ensure
213
+ silence_stream($stdout) { migration.migrate(:down) }
214
+ ActiveRecord::Base.table_name_prefix = nil
215
+ end
216
+
217
+ def test_references_foreign_key_with_suffix
218
+ ActiveRecord::Base.table_name_suffix = "_s"
219
+ migration = CreateDogsMigration.new
220
+ silence_stream($stdout) { migration.migrate(:up) }
221
+ assert_equal 1, @connection.foreign_keys("dogs_s").size
222
+ ensure
223
+ silence_stream($stdout) { migration.migrate(:down) }
224
+ ActiveRecord::Base.table_name_suffix = nil
225
+ end
226
+
227
+ def test_multiple_foreign_keys_can_added_to_same_table
228
+ connection.ddl_batch do
229
+ connection.create_table :testings do |t|
230
+ t.references :parent1, foreign_key: { to_table: :testing_parents }
231
+ t.references :parent2, foreign_key: { to_table: :testing_parents }
232
+ end
233
+ end
234
+
235
+ fks = connection.foreign_keys("testings").sort_by(&:column)
236
+
237
+ fk_definitions = fks.map { |fk| [fk.from_table, fk.to_table, fk.column] }
238
+ assert_equal([["testings", "testing_parents", "parent1_id"],
239
+ ["testings", "testing_parents", "parent2_id"]], fk_definitions)
240
+ end
241
+
242
+ def test_multiple_foreign_keys_removed
243
+ connection.create_table :testings do |t|
244
+ t.references :parent1, foreign_key: { to_table: :testing_parents }
245
+ t.references :parent2, foreign_key: { to_table: :testing_parents }
246
+ end
247
+
248
+ connection.remove_reference :testings, :parent1, foreign_key: { to_table: :testing_parents }
249
+
250
+ assert_equal 1, connection.foreign_keys('testings').size
251
+
252
+ fks = connection.foreign_keys("testings").sort_by(&:column)
253
+
254
+ fk_definitions = fks.map { |fk| [fk.from_table, fk.to_table, fk.column] }
255
+ assert_equal([["testings", "testing_parents", "parent2_id"]], fk_definitions)
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,135 @@
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 ReferencesIndexTest < 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
+ end
24
+
25
+ def teardown
26
+ connection.ddl_batch do
27
+ connection.drop_table :testings
28
+ end rescue nil
29
+ end
30
+
31
+ def test_creates_index
32
+ connection.ddl_batch do
33
+ connection.create_table table_name do |t|
34
+ t.references :foo, index: true
35
+ end
36
+ end
37
+
38
+ assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id)
39
+ end
40
+
41
+ def test_creates_index_by_default_even_if_index_option_is_not_passed
42
+ connection.ddl_batch do
43
+ connection.create_table table_name do |t|
44
+ t.references :foo
45
+ end
46
+ end
47
+
48
+ assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id)
49
+ end
50
+
51
+ def test_does_not_create_index_explicit
52
+ connection.ddl_batch do
53
+ connection.create_table table_name do |t|
54
+ t.references :foo, index: false
55
+ end
56
+ end
57
+
58
+ assert_not connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id)
59
+ end
60
+
61
+ def test_creates_index_with_options
62
+ connection.ddl_batch do
63
+ connection.create_table table_name do |t|
64
+ t.references :foo, index: { name: :index_testings_on_yo_momma }
65
+ t.references :bar, index: { unique: true }
66
+ end
67
+ end
68
+
69
+ assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_yo_momma)
70
+ assert connection.index_exists?(table_name, :bar_id, name: :index_testings_on_bar_id, unique: true)
71
+ end
72
+
73
+ def test_creates_polymorphic_index
74
+ connection.ddl_batch do
75
+ connection.create_table table_name do |t|
76
+ t.references :foo, polymorphic: true, index: true
77
+ end
78
+ end
79
+
80
+ if ActiveRecord::gem_version < Gem::Version.create('6.1.0')
81
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id)
82
+ else
83
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo)
84
+ end
85
+ end
86
+
87
+ def test_creates_index_for_existing_table
88
+ connection.ddl_batch do
89
+ connection.create_table table_name
90
+ connection.change_table table_name do |t|
91
+ t.references :foo, index: true
92
+ end
93
+ end
94
+
95
+ assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id)
96
+ end
97
+
98
+ def test_creates_index_for_existing_table_even_if_index_option_is_not_passed
99
+ connection.ddl_batch do
100
+ connection.create_table table_name
101
+ connection.change_table table_name do |t|
102
+ t.references :foo
103
+ end
104
+ end
105
+
106
+ assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id)
107
+ end
108
+
109
+ def test_does_not_create_index_for_existing_table_explicit
110
+ connection.ddl_batch do
111
+ connection.create_table table_name
112
+ connection.change_table table_name do |t|
113
+ t.references :foo, index: false
114
+ end
115
+ end
116
+ assert_not connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo)
117
+ end
118
+
119
+ def test_creates_polymorphic_index_for_existing_table
120
+ connection.ddl_batch do
121
+ connection.create_table table_name
122
+ connection.change_table table_name do |t|
123
+ t.references :foo, polymorphic: true, index: true
124
+ end
125
+ end
126
+
127
+ if ActiveRecord::gem_version < Gem::Version.create('6.1.0')
128
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id)
129
+ else
130
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end