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.
Files changed (264) 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 +36 -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 +26 -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 +67 -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 +147 -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 +67 -0
  56. data/acceptance/cases/transactions/read_write_transactions_test.rb +248 -0
  57. data/acceptance/cases/type/all_types_test.rb +152 -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/numeric_test.rb +27 -0
  65. data/acceptance/cases/type/string_test.rb +79 -0
  66. data/acceptance/cases/type/text_test.rb +30 -0
  67. data/acceptance/cases/type/time_test.rb +87 -0
  68. data/acceptance/models/account.rb +13 -0
  69. data/acceptance/models/address.rb +9 -0
  70. data/acceptance/models/album.rb +12 -0
  71. data/acceptance/models/all_types.rb +8 -0
  72. data/acceptance/models/author.rb +11 -0
  73. data/acceptance/models/club.rb +12 -0
  74. data/acceptance/models/comment.rb +9 -0
  75. data/acceptance/models/customer.rb +9 -0
  76. data/acceptance/models/department.rb +9 -0
  77. data/acceptance/models/firm.rb +10 -0
  78. data/acceptance/models/member.rb +13 -0
  79. data/acceptance/models/member_type.rb +9 -0
  80. data/acceptance/models/membership.rb +10 -0
  81. data/acceptance/models/organization.rb +9 -0
  82. data/acceptance/models/post.rb +10 -0
  83. data/acceptance/models/singer.rb +10 -0
  84. data/acceptance/models/track.rb +20 -0
  85. data/acceptance/models/transaction.rb +9 -0
  86. data/acceptance/schema/schema.rb +143 -0
  87. data/acceptance/test_helper.rb +260 -0
  88. data/activerecord-spanner-adapter.gemspec +32 -17
  89. data/assets/solidus-db.png +0 -0
  90. data/benchmarks/README.md +17 -0
  91. data/benchmarks/Rakefile +14 -0
  92. data/benchmarks/application.rb +308 -0
  93. data/benchmarks/config/database.yml +8 -0
  94. data/benchmarks/config/environment.rb +12 -0
  95. data/benchmarks/db/migrate/01_create_tables.rb +25 -0
  96. data/benchmarks/db/schema.rb +29 -0
  97. data/benchmarks/models/album.rb +9 -0
  98. data/benchmarks/models/singer.rb +9 -0
  99. data/bin/console +6 -7
  100. data/examples/rails/README.md +262 -0
  101. data/examples/snippets/README.md +29 -0
  102. data/examples/snippets/Rakefile +57 -0
  103. data/examples/snippets/array-data-type/README.md +45 -0
  104. data/examples/snippets/array-data-type/Rakefile +13 -0
  105. data/examples/snippets/array-data-type/application.rb +45 -0
  106. data/examples/snippets/array-data-type/config/database.yml +8 -0
  107. data/examples/snippets/array-data-type/db/migrate/01_create_tables.rb +24 -0
  108. data/examples/snippets/array-data-type/db/schema.rb +26 -0
  109. data/examples/snippets/array-data-type/db/seeds.rb +5 -0
  110. data/examples/snippets/array-data-type/models/entity_with_array_types.rb +18 -0
  111. data/examples/snippets/bin/create_emulator_instance.rb +18 -0
  112. data/examples/snippets/bulk-insert/README.md +21 -0
  113. data/examples/snippets/bulk-insert/Rakefile +13 -0
  114. data/examples/snippets/bulk-insert/application.rb +64 -0
  115. data/examples/snippets/bulk-insert/config/database.yml +8 -0
  116. data/examples/snippets/bulk-insert/db/migrate/01_create_tables.rb +21 -0
  117. data/examples/snippets/bulk-insert/db/schema.rb +26 -0
  118. data/examples/snippets/bulk-insert/db/seeds.rb +5 -0
  119. data/examples/snippets/bulk-insert/models/album.rb +9 -0
  120. data/examples/snippets/bulk-insert/models/singer.rb +9 -0
  121. data/examples/snippets/commit-timestamp/README.md +18 -0
  122. data/examples/snippets/commit-timestamp/Rakefile +13 -0
  123. data/examples/snippets/commit-timestamp/application.rb +53 -0
  124. data/examples/snippets/commit-timestamp/config/database.yml +8 -0
  125. data/examples/snippets/commit-timestamp/db/migrate/01_create_tables.rb +26 -0
  126. data/examples/snippets/commit-timestamp/db/schema.rb +29 -0
  127. data/examples/snippets/commit-timestamp/db/seeds.rb +5 -0
  128. data/examples/snippets/commit-timestamp/models/album.rb +9 -0
  129. data/examples/snippets/commit-timestamp/models/singer.rb +9 -0
  130. data/examples/snippets/config/environment.rb +21 -0
  131. data/examples/snippets/create-records/README.md +12 -0
  132. data/examples/snippets/create-records/Rakefile +13 -0
  133. data/examples/snippets/create-records/application.rb +42 -0
  134. data/examples/snippets/create-records/config/database.yml +8 -0
  135. data/examples/snippets/create-records/db/migrate/01_create_tables.rb +21 -0
  136. data/examples/snippets/create-records/db/schema.rb +26 -0
  137. data/examples/snippets/create-records/db/seeds.rb +5 -0
  138. data/examples/snippets/create-records/models/album.rb +9 -0
  139. data/examples/snippets/create-records/models/singer.rb +9 -0
  140. data/examples/snippets/date-data-type/README.md +19 -0
  141. data/examples/snippets/date-data-type/Rakefile +13 -0
  142. data/examples/snippets/date-data-type/application.rb +35 -0
  143. data/examples/snippets/date-data-type/config/database.yml +8 -0
  144. data/examples/snippets/date-data-type/db/migrate/01_create_tables.rb +20 -0
  145. data/examples/snippets/date-data-type/db/schema.rb +21 -0
  146. data/examples/snippets/date-data-type/db/seeds.rb +16 -0
  147. data/examples/snippets/date-data-type/models/singer.rb +8 -0
  148. data/examples/snippets/generated-column/README.md +41 -0
  149. data/examples/snippets/generated-column/Rakefile +13 -0
  150. data/examples/snippets/generated-column/application.rb +37 -0
  151. data/examples/snippets/generated-column/config/database.yml +8 -0
  152. data/examples/snippets/generated-column/db/migrate/01_create_tables.rb +23 -0
  153. data/examples/snippets/generated-column/db/schema.rb +21 -0
  154. data/examples/snippets/generated-column/db/seeds.rb +18 -0
  155. data/examples/snippets/generated-column/models/singer.rb +8 -0
  156. data/examples/snippets/interleaved-tables/README.md +152 -0
  157. data/examples/snippets/interleaved-tables/Rakefile +13 -0
  158. data/examples/snippets/interleaved-tables/application.rb +109 -0
  159. data/examples/snippets/interleaved-tables/config/database.yml +8 -0
  160. data/examples/snippets/interleaved-tables/db/migrate/01_create_tables.rb +44 -0
  161. data/examples/snippets/interleaved-tables/db/schema.rb +32 -0
  162. data/examples/snippets/interleaved-tables/db/seeds.rb +40 -0
  163. data/examples/snippets/interleaved-tables/models/album.rb +15 -0
  164. data/examples/snippets/interleaved-tables/models/singer.rb +20 -0
  165. data/examples/snippets/interleaved-tables/models/track.rb +25 -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/quickstart/README.md +26 -0
  195. data/examples/snippets/quickstart/Rakefile +13 -0
  196. data/examples/snippets/quickstart/application.rb +51 -0
  197. data/examples/snippets/quickstart/config/database.yml +8 -0
  198. data/examples/snippets/quickstart/db/migrate/01_create_tables.rb +21 -0
  199. data/examples/snippets/quickstart/db/schema.rb +26 -0
  200. data/examples/snippets/quickstart/db/seeds.rb +24 -0
  201. data/examples/snippets/quickstart/models/album.rb +9 -0
  202. data/examples/snippets/quickstart/models/singer.rb +9 -0
  203. data/examples/snippets/read-only-transactions/README.md +13 -0
  204. data/examples/snippets/read-only-transactions/Rakefile +13 -0
  205. data/examples/snippets/read-only-transactions/application.rb +49 -0
  206. data/examples/snippets/read-only-transactions/config/database.yml +8 -0
  207. data/examples/snippets/read-only-transactions/db/migrate/01_create_tables.rb +21 -0
  208. data/examples/snippets/read-only-transactions/db/schema.rb +26 -0
  209. data/examples/snippets/read-only-transactions/db/seeds.rb +24 -0
  210. data/examples/snippets/read-only-transactions/models/album.rb +9 -0
  211. data/examples/snippets/read-only-transactions/models/singer.rb +9 -0
  212. data/examples/snippets/read-write-transactions/README.md +12 -0
  213. data/examples/snippets/read-write-transactions/Rakefile +13 -0
  214. data/examples/snippets/read-write-transactions/application.rb +39 -0
  215. data/examples/snippets/read-write-transactions/config/database.yml +8 -0
  216. data/examples/snippets/read-write-transactions/db/migrate/01_create_tables.rb +22 -0
  217. data/examples/snippets/read-write-transactions/db/schema.rb +27 -0
  218. data/examples/snippets/read-write-transactions/db/seeds.rb +25 -0
  219. data/examples/snippets/read-write-transactions/models/album.rb +9 -0
  220. data/examples/snippets/read-write-transactions/models/singer.rb +9 -0
  221. data/examples/snippets/timestamp-data-type/README.md +17 -0
  222. data/examples/snippets/timestamp-data-type/Rakefile +13 -0
  223. data/examples/snippets/timestamp-data-type/application.rb +42 -0
  224. data/examples/snippets/timestamp-data-type/config/database.yml +8 -0
  225. data/examples/snippets/timestamp-data-type/db/migrate/01_create_tables.rb +21 -0
  226. data/examples/snippets/timestamp-data-type/db/schema.rb +21 -0
  227. data/examples/snippets/timestamp-data-type/db/seeds.rb +6 -0
  228. data/examples/snippets/timestamp-data-type/models/meeting.rb +19 -0
  229. data/examples/solidus/README.md +172 -0
  230. data/lib/active_record/connection_adapters/spanner/database_statements.rb +224 -269
  231. data/lib/active_record/connection_adapters/spanner/quoting.rb +42 -50
  232. data/lib/active_record/connection_adapters/spanner/schema_cache.rb +43 -0
  233. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +125 -9
  234. data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +122 -0
  235. data/lib/active_record/connection_adapters/spanner/schema_dumper.rb +19 -0
  236. data/lib/active_record/connection_adapters/spanner/schema_statements.rb +553 -139
  237. data/lib/active_record/connection_adapters/spanner/type_metadata.rb +37 -0
  238. data/lib/active_record/connection_adapters/spanner_adapter.rb +182 -78
  239. data/lib/active_record/tasks/spanner_database_tasks.rb +74 -0
  240. data/lib/active_record/type/spanner/array.rb +32 -0
  241. data/lib/active_record/type/spanner/bytes.rb +26 -0
  242. data/lib/active_record/type/spanner/spanner_active_record_converter.rb +32 -0
  243. data/lib/active_record/type/spanner/time.rb +37 -0
  244. data/lib/activerecord-spanner-adapter.rb +23 -0
  245. data/lib/activerecord_spanner_adapter/base.rb +217 -0
  246. data/lib/activerecord_spanner_adapter/connection.rb +324 -0
  247. data/lib/activerecord_spanner_adapter/errors.rb +13 -0
  248. data/lib/activerecord_spanner_adapter/foreign_key.rb +29 -0
  249. data/lib/activerecord_spanner_adapter/index/column.rb +38 -0
  250. data/lib/activerecord_spanner_adapter/index.rb +80 -0
  251. data/lib/activerecord_spanner_adapter/information_schema.rb +261 -0
  252. data/lib/activerecord_spanner_adapter/primary_key.rb +31 -0
  253. data/lib/activerecord_spanner_adapter/table/column.rb +59 -0
  254. data/lib/activerecord_spanner_adapter/table.rb +61 -0
  255. data/lib/activerecord_spanner_adapter/transaction.rb +113 -0
  256. data/lib/activerecord_spanner_adapter/version.rb +9 -0
  257. data/lib/arel/visitors/spanner.rb +35 -0
  258. data/lib/spanner_client_ext.rb +82 -0
  259. data/renovate.json +5 -0
  260. metadata +387 -34
  261. data/.travis.yml +0 -5
  262. data/lib/active_record/connection_adapters/spanner/client.rb +0 -190
  263. data/lib/active_record/connection_adapters/spanner.rb +0 -10
  264. data/lib/activerecord-spanner-adapter/version.rb +0 -3
@@ -0,0 +1,115 @@
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 TableTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Migration::TestHelper
15
+
16
+ def setup
17
+ skip_test_table_create!
18
+
19
+ super
20
+ @connection = Minitest::Mock.new
21
+ end
22
+
23
+ def teardown
24
+ assert @connection.verify
25
+ end
26
+
27
+ def with_change_table
28
+ yield ActiveRecord::Base.connection.update_table_definition(:delete_me, @connection)
29
+ end
30
+
31
+ def test_remove_references_column_type_with_polymorphic_removes_type
32
+ with_change_table do |t|
33
+ @connection.expect :remove_reference, nil, [:delete_me, :taggable, polymorphic: true]
34
+ t.remove_references :taggable, polymorphic: true
35
+ end
36
+ end
37
+
38
+ def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
39
+ with_change_table do |t|
40
+ @connection.expect :add_reference, nil, [:delete_me, :taggable, polymorphic: true, null: false]
41
+ t.references :taggable, polymorphic: true, null: false
42
+ end
43
+ end
44
+
45
+ def test_remove_references_column_type_with_polymorphic_and_options_null_is_false_removes_table_flag
46
+ with_change_table do |t|
47
+ @connection.expect :remove_reference, nil, [:delete_me, :taggable, polymorphic: true, null: false]
48
+ t.remove_references :taggable, polymorphic: true, null: false
49
+ end
50
+ end
51
+
52
+ def test_references_column_type_with_polymorphic_and_type
53
+ with_change_table do |t|
54
+ @connection.expect :add_reference, nil, [:delete_me, :taggable, polymorphic: true, type: :string]
55
+ t.references :taggable, polymorphic: true, type: :string
56
+ end
57
+ end
58
+
59
+ def test_remove_references_column_type_with_polymorphic_and_type
60
+ with_change_table do |t|
61
+ @connection.expect :remove_reference, nil, [:delete_me, :taggable, polymorphic: true, type: :string]
62
+ t.remove_references :taggable, polymorphic: true, type: :string
63
+ end
64
+ end
65
+
66
+ def test_timestamps_creates_updated_at_and_created_at
67
+ with_change_table do |t|
68
+ @connection.expect :add_timestamps, nil, [:delete_me, null: true]
69
+ t.timestamps null: true
70
+ end
71
+ end
72
+
73
+ def test_remove_timestamps_creates_updated_at_and_created_at
74
+ with_change_table do |t|
75
+ @connection.expect :remove_timestamps, nil, [:delete_me, { null: true }]
76
+ t.remove_timestamps(null: true)
77
+ end
78
+ end
79
+
80
+ def test_primary_key_creates_primary_key_column
81
+ with_change_table do |t|
82
+ @connection.expect :add_column, nil, [:delete_me, :id, :primary_key, primary_key: true, first: true]
83
+ t.primary_key :id, first: true
84
+ end
85
+ end
86
+
87
+ def test_index_exists
88
+ with_change_table do |t|
89
+ @connection.expect :index_exists?, nil, [:delete_me, :bar, {}]
90
+ t.index_exists?(:bar)
91
+ end
92
+ end
93
+
94
+ def test_index_exists_with_options
95
+ with_change_table do |t|
96
+ @connection.expect :index_exists?, nil, [:delete_me, :bar, { unique: true }]
97
+ t.index_exists?(:bar, unique: true)
98
+ end
99
+ end
100
+
101
+ def test_remove_drops_multiple_columns_when_column_options_are_given
102
+ with_change_table do |t|
103
+ @connection.expect :remove_columns, nil, [:delete_me, :bar, :baz, type: :string, null: false]
104
+ t.remove :bar, :baz, type: :string, null: false
105
+ end
106
+ end
107
+
108
+ def test_table_name_set
109
+ with_change_table do |t|
110
+ assert_equal :delete_me, t.name
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,122 @@
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
+ require "bigdecimal"
11
+
12
+ module ActiveRecord
13
+ class Migration
14
+ class ColumnAttributesTest < SpannerAdapter::TestCase
15
+ include SpannerAdapter::Migration::TestHelper
16
+
17
+ def test_add_remove_single_field_using_string_arguments
18
+ assert_no_column TestModel, :last_name
19
+
20
+ add_column "test_models", "last_name", :string
21
+ assert_column TestModel, :last_name
22
+
23
+ remove_column "test_models", "last_name"
24
+ assert_no_column TestModel, :last_name
25
+ end
26
+
27
+ def test_add_remove_single_field_using_symbol_arguments
28
+ assert_no_column TestModel, :last_name
29
+
30
+ add_column :test_models, :last_name, :string
31
+ assert_column TestModel, :last_name
32
+
33
+ remove_column :test_models, :last_name
34
+ assert_no_column TestModel, :last_name
35
+ end
36
+
37
+ def test_add_column_without_limit
38
+ add_column :test_models, :description, :string, limit: nil
39
+ TestModel.reset_column_information
40
+ assert_equal "MAX", TestModel.columns_hash["description"].limit
41
+ end
42
+
43
+ # We specifically do a manual INSERT here, and then test only the SELECT
44
+ # functionality. This allows us to more easily catch INSERT being broken,
45
+ # but SELECT actually working fine.
46
+ def test_native_float_insert_manual_vs_automatic
47
+ correct_value = "0012345678901234567890.0123456789".to_f
48
+
49
+ connection.add_column "test_models", "wealth", :float
50
+
51
+ # Do a manual insertion
52
+ connection.transaction {
53
+ connection.execute "insert into test_models (id, wealth) values (#{generate_id}, 12345678901234567890.0123456789)"
54
+ }
55
+
56
+ # SELECT
57
+ row = TestModel.first
58
+ assert_kind_of Float, row.wealth
59
+
60
+ # If this assert fails, that means the SELECT is broken!
61
+ assert_equal correct_value, row.wealth
62
+
63
+ # Reset to old state
64
+ TestModel.delete_all
65
+
66
+ # Now use the Rails insertion
67
+ TestModel.create wealth: BigDecimal("12345678901234567890.0123456789")
68
+
69
+ # SELECT
70
+ row = TestModel.first
71
+ assert_kind_of Float, row.wealth
72
+
73
+ # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
74
+ assert_equal correct_value, row.wealth
75
+ end
76
+
77
+ def test_native_types
78
+ connection.ddl_batch do
79
+ add_column "test_models", "first_name", :string
80
+ add_column "test_models", "last_name", :string
81
+ add_column "test_models", "bio", :text
82
+ add_column "test_models", "age", :integer
83
+ add_column "test_models", "height", :float
84
+ add_column "test_models", "birthday", :datetime
85
+ add_column "test_models", "favorite_day", :date
86
+ add_column "test_models", "moment_of_truth", :datetime
87
+ add_column "test_models", "male", :boolean
88
+ add_column "test_models", "weight", :decimal
89
+ end
90
+
91
+ TestModel.create first_name: "bob", last_name: "bobsen",
92
+ bio: "I was born ....", age: 18, height: 1.78,
93
+ birthday: 18.years.ago, favorite_day: 10.days.ago,
94
+ moment_of_truth: "1782-10-10 21:40:18", male: true, weight: BigDecimal("75.6", 1)
95
+
96
+ bob = TestModel.first
97
+ assert_equal "bob", bob.first_name
98
+ assert_equal "bobsen", bob.last_name
99
+ assert_equal "I was born ....", bob.bio
100
+ assert_equal 18, bob.age
101
+ assert_equal 1.78, bob.height
102
+ assert_equal true, bob.male?
103
+ assert_equal BigDecimal("75.6", 1), bob.weight
104
+
105
+ assert_equal String, bob.first_name.class
106
+ assert_equal String, bob.last_name.class
107
+ assert_equal String, bob.bio.class
108
+ assert_kind_of Integer, bob.age
109
+ assert_equal Float, bob.height.class
110
+ assert_equal Time, bob.birthday.class
111
+ assert_equal Date, bob.favorite_day.class
112
+ assert_instance_of TrueClass, bob.male?
113
+ assert_equal BigDecimal, bob.weight.class
114
+ end
115
+
116
+ def test_add_column_and_ignore_limit
117
+ add_column :test_models, :integer_ignore_limit, :integer, limit: 10
118
+ assert_column TestModel, :integer_ignore_limit
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,48 @@
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 ColumnPositioningTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Migration::TestHelper
15
+
16
+ def setup
17
+ skip_test_table_create!
18
+ super
19
+
20
+ connection.ddl_batch do
21
+ connection.create_table :testing_columns_position, id: false, force: true do |t|
22
+ t.column :first, :integer
23
+ t.column :second, :integer
24
+ t.column :third, :integer
25
+ end
26
+ end
27
+ end
28
+
29
+ def teardown
30
+ connection.ddl_batch do
31
+ connection.drop_table :testing_columns_position
32
+ end rescue nil
33
+ ActiveRecord::Base.primary_key_prefix_type = nil
34
+ end
35
+
36
+ def test_column_positioning
37
+ assert_equal %w(first second third), connection.columns(:testing_columns_position).map(&:name)
38
+ end
39
+
40
+ def test_add_column_with_positioning
41
+ connection.ddl_batch do
42
+ connection.add_column :testing_columns_position, :fourth, :integer
43
+ end
44
+ assert_equal %w(first second third fourth), connection.columns(:testing_columns_position).map(&:name)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,201 @@
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 ColumnsTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Migration::TestHelper
15
+
16
+ def test_rename_column
17
+ connection.ddl_batch do
18
+ add_column "test_models", :hat_name, :string
19
+ end
20
+ assert_column TestModel, :hat_name
21
+
22
+ rename_column "test_models", :hat_name, :cap_name
23
+ assert_column TestModel, :cap_name
24
+ end
25
+
26
+ def test_change_column_default_value
27
+ error = assert_raise ActiveRecordSpannerAdapter::NotSupportedError do
28
+ change_column_default "test_models", :hat_name, "hat"
29
+ end
30
+
31
+ assert_equal "change column with default value not supported.", error.message
32
+ end
33
+
34
+ def test_remove_column_with_index
35
+ connection.ddl_batch do
36
+ add_column "test_models", :hat_name, :string
37
+ add_index :test_models, :hat_name
38
+ end
39
+
40
+ assert_equal 1, connection.indexes("test_models").size
41
+ connection.ddl_batch do
42
+ remove_column "test_models", "hat_name"
43
+ end
44
+ assert_equal 0, connection.indexes("test_models").size
45
+ end
46
+
47
+ def test_remove_column_with_multi_column_index
48
+ connection.ddl_batch do
49
+ add_column "test_models", :hat_size, :integer
50
+ add_column "test_models", :hat_style, :string, limit: 100
51
+ add_index "test_models", ["hat_style", "hat_size"], unique: true
52
+ end
53
+
54
+ assert_equal 1, connection.indexes("test_models").size
55
+ connection.ddl_batch do
56
+ remove_column "test_models", "hat_size"
57
+ end
58
+
59
+ assert_equal [], connection.indexes("test_models").map(&:name)
60
+ end
61
+
62
+ def test_change_type_of_not_null_column
63
+ connection.ddl_batch do
64
+ change_column "test_models", "updated_at", :datetime, null: false
65
+ change_column "test_models", "updated_at", :datetime, null: false
66
+ end
67
+
68
+ TestModel.reset_column_information
69
+ assert_equal false, TestModel.columns_hash["updated_at"].null
70
+ ensure
71
+ connection.ddl_batch do
72
+ change_column "test_models", "updated_at", :datetime, null: true
73
+ end
74
+ end
75
+
76
+ def test_change_column_nullability
77
+ connection.ddl_batch do
78
+ add_column "test_models", "funny", :boolean
79
+ end
80
+ assert TestModel.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
81
+
82
+ connection.ddl_batch do
83
+ change_column "test_models", "funny", :boolean, null: false
84
+ end
85
+
86
+ TestModel.reset_column_information
87
+ assert_not TestModel.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
88
+
89
+ connection.ddl_batch do
90
+ change_column "test_models", "funny", :boolean, null: true
91
+ end
92
+ TestModel.reset_column_information
93
+ assert TestModel.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
94
+ end
95
+
96
+ def test_change_column
97
+ # Only string and binary allows to change types
98
+ connection.ddl_batch do
99
+ add_column "test_models", "name", :string
100
+ end
101
+
102
+ old_columns = connection.columns TestModel.table_name
103
+
104
+ assert old_columns.find { |c| c.name == "name" && c.type == :string }
105
+
106
+ connection.ddl_batch do
107
+ change_column "test_models", "name", :binary
108
+ end
109
+
110
+ new_columns = connection.columns TestModel.table_name
111
+
112
+ assert_not new_columns.find { |c| c.name == "name" && c.type == :string }
113
+ assert new_columns.find { |c| c.name == "name" && c.type == :binary }
114
+ end
115
+
116
+ def test_change_column_with_custom_index_name
117
+ connection.ddl_batch do
118
+ add_column :test_models, :category, :string
119
+ add_index :test_models, :category, name: "test_models_categories_idx", order: { category: :desc}
120
+ end
121
+
122
+ assert_equal ["test_models_categories_idx"], connection.indexes("test_models").map(&:name)
123
+ connection.ddl_batch do
124
+ change_column "test_models", "category", :string, null: false
125
+ end
126
+
127
+ assert column_exists?(:test_models, :category, :string, null: false)
128
+ indexes = connection.indexes("test_models")
129
+ assert_equal ["test_models_categories_idx"], indexes.map(&:name)
130
+ assert_equal({ category: :desc }, indexes.first.orders)
131
+ end
132
+
133
+ def test_change_column_with_long_index_name
134
+ table_name_prefix = "test_models_"
135
+ long_index_name = table_name_prefix + ("x" * (connection.index_name_length - table_name_prefix.length))
136
+ connection.ddl_batch do
137
+ add_column "test_models", "category", :string
138
+ add_index :test_models, :category, name: long_index_name
139
+ end
140
+
141
+ connection.ddl_batch do
142
+ change_column "test_models", "category", :string, null: false
143
+ end
144
+
145
+ assert_equal [long_index_name], connection.indexes("test_models").map(&:name)
146
+ end
147
+
148
+ def test_remove_column_no_second_parameter_raises_exception
149
+ assert_raise(ArgumentError) { connection.remove_column("funny") }
150
+ end
151
+
152
+ def test_removing_column_preserves_custom_primary_key
153
+ connection.ddl_batch do
154
+ connection.create_table "my_table", primary_key: "my_table_id", force: true do |t|
155
+ t.integer "col_one"
156
+ t.string "col_two", limit: 128, null: false
157
+ end
158
+ end
159
+
160
+ connection.ddl_batch do
161
+ remove_column "my_table", "col_two"
162
+ end
163
+
164
+ assert_equal "my_table_id", connection.primary_key("my_table")
165
+
166
+ columns = connection.columns "my_table"
167
+ my_table_id = columns.detect { |c| c.name == "my_table_id" }
168
+ assert_equal "INT64", my_table_id.sql_type
169
+ ensure
170
+ connection.ddl_batch do
171
+ connection.drop_table :my_table rescue nil
172
+ end
173
+ end
174
+
175
+ def test_column_with_index
176
+ connection.ddl_batch do
177
+ connection.create_table "my_table", force: true do |t|
178
+ t.string :item_number, index: true
179
+ end
180
+ end
181
+
182
+ assert connection.index_exists?("my_table", :item_number, name: :index_my_table_on_item_number)
183
+ ensure
184
+ connection.ddl_batch do
185
+ connection.drop_table :my_table rescue nil
186
+ end
187
+ end
188
+
189
+ def test_add_column_without_column_name
190
+ e = assert_raise ArgumentError do
191
+ connection.create_table "my_table", force: true do |t|
192
+ t.timestamp
193
+ end
194
+ end
195
+ assert_equal "Missing column name(s) for timestamp", e.message
196
+ ensure
197
+ connection.drop_table :my_table, if_exists: true
198
+ end
199
+ end
200
+ end
201
+ end