activerecord-spanner-adapter 0.3.0 → 1.0.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 (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,27 @@
1
+ # Copyright 2021 Google LLC
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require "test_helper"
10
+
11
+ module ActiveRecord
12
+ module Type
13
+ class NumericTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Types::TestHelper
15
+
16
+ def test_convert_to_sql_type
17
+ assert_equal "NUMERIC", connection.type_to_sql(:numeric)
18
+ end
19
+
20
+ def test_set_numeric_value_in_create
21
+ record = TestTypeModel.create(price: 9750.99)
22
+ record.reload
23
+ assert_equal 9750.99, record.price
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,79 @@
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
+ module Type
13
+ class StringTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Types::TestHelper
15
+
16
+ def test_convert_to_sql_type
17
+ assert_equal "STRING(MAX)", connection.type_to_sql(:string)
18
+ assert_equal "STRING(1024)", connection.type_to_sql(:string, limit: 1024)
19
+ end
20
+
21
+ def test_set_string_in_create
22
+ description = "a" * 1000
23
+ name = "Test name"
24
+ record = TestTypeModel.create(description: description, name: name)
25
+ record.reload
26
+
27
+ assert_equal description, record.description
28
+ assert_equal name, record.name
29
+ end
30
+
31
+ def test_set_string_with_max_limit_in_create
32
+ str = "a" * 256
33
+
34
+ assert_raise(ActiveRecord::StatementInvalid) {
35
+ TestTypeModel.create(name: str)
36
+ }
37
+ end
38
+
39
+ def test_escape_special_charaters_and_save
40
+ str = [
41
+ "Newline \n",
42
+ "`Backtick`",
43
+ "'Quote'",
44
+ "Bell \a",
45
+ "Backspace \b",
46
+ "Formfeed \f",
47
+ "Carriage Return \r",
48
+ "Tab \t",
49
+ "Vertical Tab \v",
50
+ "Backslash \\",
51
+ "Question Mark \?",
52
+ "Double Quote \"",
53
+ ].join (" ")
54
+
55
+ record = TestTypeModel.new(description: str)
56
+ assert_equal str, record.description
57
+
58
+ record.save!
59
+ assert_equal str, record.description
60
+
61
+ record.reload
62
+ assert_equal str, record.description
63
+ end
64
+
65
+ def test_save_special_charaters
66
+ str = "Hello Seocial Chars : € à ö ¿ © 😎"
67
+
68
+ record = TestTypeModel.new(description: str)
69
+ assert_equal str, record.description
70
+
71
+ record.save!
72
+ assert_equal str, record.description
73
+
74
+ record.reload
75
+ assert_equal str, record.description
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,30 @@
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
+ module Type
13
+ class TextTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Types::TestHelper
15
+
16
+ def test_convert_to_sql_type
17
+ assert_equal "STRING(MAX)", connection.type_to_sql(:text)
18
+ assert_equal "STRING(1024)", connection.type_to_sql(:text, limit: 1024)
19
+ end
20
+
21
+ def test_set_text_in_create
22
+ text = "a" * 1000
23
+ record = TestTypeModel.create(bio: text)
24
+ record.reload
25
+
26
+ assert_equal text, record.bio
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,87 @@
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
+ module Type
13
+ class TimeTest < SpannerAdapter::TestCase
14
+ include SpannerAdapter::Types::TestHelper
15
+
16
+ def test_convert_to_sql_type
17
+ assert_equal "TIMESTAMP", connection.type_to_sql(:time)
18
+ end
19
+
20
+ def test_assign_time
21
+ expected_time = ::Time.now
22
+ record = TestTypeModel.new start_time: expected_time
23
+
24
+ assert_equal expected_time, record.start_time
25
+ end
26
+
27
+ def test_assign_empty_time
28
+ record = TestTypeModel.new start_time: ""
29
+ assert_nil record.start_time
30
+ end
31
+
32
+ def test_assign_nil_time
33
+ record = TestTypeModel.new start_time: nil
34
+ assert_nil record.start_time
35
+ end
36
+
37
+ def test_set_and_save_time
38
+ expected_time = ::Time.now.utc
39
+ record = TestTypeModel.create! start_time: expected_time
40
+
41
+ assert_equal expected_time, record.start_time
42
+
43
+ record.reload
44
+ assert_equal expected_time, record.start_time
45
+ end
46
+
47
+ def test_date_time_string_value_with_subsecond_precision
48
+ expected_time = ::Time.local 2017, 07, 4, 14, 19, 10, 897761
49
+
50
+ string_value = "2017-07-04 14:19:10.897761"
51
+
52
+ record = TestTypeModel.new start_time: string_value
53
+ assert_equal expected_time, record.start_time.utc
54
+
55
+ record.save!
56
+ assert_equal expected_time, record.start_time.utc
57
+
58
+ assert_equal record, TestTypeModel.find_by(start_time: string_value)
59
+ end
60
+
61
+ def test_date_time_with_string_value_with_non_iso_format
62
+ string_value = "04/07/2017 2:19pm"
63
+ expected_time = ::Time.local 2017, 07, 4, 14, 19
64
+
65
+ record = TestTypeModel.new start_time: string_value
66
+ assert_equal expected_time, record.start_time
67
+
68
+ record.save!
69
+ assert_equal expected_time, record.start_time.utc
70
+
71
+ assert_equal record, TestTypeModel.find_by(start_time: string_value)
72
+ end
73
+
74
+ def test_default_year_is_correct
75
+ expected_time = ::Time.utc(2000, 1, 1, 10, 30, 0)
76
+ record = TestTypeModel.new start_time: { 4 => 10, 5 => 30 }
77
+
78
+ assert_equal expected_time, record.start_time
79
+
80
+ record.save!
81
+ record.reload
82
+
83
+ assert_equal expected_time, record.start_time
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,13 @@
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
+ class Account < ActiveRecord::Base
8
+ belongs_to :firm
9
+ belongs_to :customer
10
+ has_many :transactions
11
+
12
+ alias_attribute :available_credit, :credit_limit
13
+ end
@@ -0,0 +1,9 @@
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
+ class Address < ActiveRecord::Base
8
+ has_one :author
9
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright 2021 Google LLC
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+
7
+ class Album < ActiveRecord::Base
8
+ # The relationship with singer is not really a foreign key, but an INTERLEAVE IN relationship. We still need to
9
+ # use the `foreign_key` attribute to indicate which column to use for the relationship.
10
+ belongs_to :singer, foreign_key: "singerid"
11
+ has_many :tracks, foreign_key: "albumid", dependent: :delete_all
12
+ end
@@ -0,0 +1,8 @@
1
+ # Copyright 2021 Google LLC
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+
7
+ class AllTypes < ActiveRecord::Base
8
+ end
@@ -0,0 +1,11 @@
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
+ class Author < ActiveRecord::Base
8
+ has_many :posts
9
+ has_many :comments, through: :posts
10
+ belongs_to :organization
11
+ end
@@ -0,0 +1,12 @@
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
+ class Club < ActiveRecord::Base
8
+ has_many :memberships
9
+ has_many :members, through: :memberships
10
+ has_many :favourites, -> { where(memberships: { favourite: true }) },
11
+ through: :memberships, source: :member
12
+ end
@@ -0,0 +1,9 @@
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
+ class Comment < ActiveRecord::Base
8
+ belongs_to :post, counter_cache: true
9
+ end
@@ -0,0 +1,9 @@
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
+ class Customer < ActiveRecord::Base
8
+ has_many :accounts
9
+ end
@@ -0,0 +1,9 @@
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
+ class Department < ActiveRecord::Base
8
+ belongs_to :resource, polymorphic: true
9
+ end
@@ -0,0 +1,10 @@
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
+ class Firm < ActiveRecord::Base
8
+ has_one :account
9
+ has_many :departments, as: :resource
10
+ end
@@ -0,0 +1,13 @@
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
+ class Member < ActiveRecord::Base
8
+ has_one :membership
9
+ has_one :club, through: :membership
10
+ has_one :favourite_club, -> { where "memberships.favourite = ?", true },
11
+ through: :membership, source: :club
12
+ belongs_to :member_type
13
+ end
@@ -0,0 +1,9 @@
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
+ class MemberType < ActiveRecord::Base
8
+ has_many :members
9
+ end
@@ -0,0 +1,10 @@
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
+ class Membership < ActiveRecord::Base
8
+ belongs_to :member
9
+ belongs_to :club
10
+ end
@@ -0,0 +1,9 @@
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
+ class Organization < ActiveRecord::Base
8
+ has_many :authors, dependent: :destroy
9
+ end
@@ -0,0 +1,10 @@
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
+ class Post < ActiveRecord::Base
8
+ belongs_to :author
9
+ has_many :comments
10
+ end
@@ -0,0 +1,10 @@
1
+ # Copyright 2021 Google LLC
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+
7
+ class Singer < ActiveRecord::Base
8
+ has_many :albums, foreign_key: "singerid", dependent: :delete_all
9
+ has_many :tracks, foreign_key: "singerid"
10
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2021 Google LLC
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+
7
+ class Track < ActiveRecord::Base
8
+ belongs_to :album, foreign_key: "albumid"
9
+ belongs_to :singer, foreign_key: "singerid", counter_cache: true
10
+
11
+ def initialize attributes = nil
12
+ super
13
+ self.singer ||= self.album&.singer
14
+ end
15
+
16
+ def album=value
17
+ super
18
+ self.singer = value&.singer
19
+ end
20
+ end
@@ -0,0 +1,9 @@
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
+ class Transaction < ActiveRecord::Base
8
+ belongs_to :account, counter_cache: true
9
+ end
@@ -0,0 +1,147 @@
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
+ ActiveRecord::Schema.define do
10
+ ActiveRecord::Base.connection.ddl_batch do
11
+ create_table :all_types do |t|
12
+ t.column :col_string, :string
13
+ t.column :col_int64, :bigint
14
+ t.column :col_float64, :float
15
+ t.column :col_numeric, :numeric
16
+ t.column :col_bool, :boolean
17
+ t.column :col_bytes, :binary
18
+ t.column :col_date, :date
19
+ t.column :col_timestamp, :datetime
20
+ t.column :col_json, :json unless ENV["SPANNER_EMULATOR_HOST"]
21
+ t.column :col_json, :string if ENV["SPANNER_EMULATOR_HOST"]
22
+
23
+ t.column :col_array_string, :string, array: true
24
+ t.column :col_array_int64, :bigint, array: true
25
+ t.column :col_array_float64, :float, array: true
26
+ t.column :col_array_numeric, :numeric, array: true
27
+ t.column :col_array_bool, :boolean, array: true
28
+ t.column :col_array_bytes, :binary, array: true
29
+ t.column :col_array_date, :date, array: true
30
+ t.column :col_array_timestamp, :datetime, array: true
31
+ t.column :col_array_json, :json, array: true unless ENV["SPANNER_EMULATOR_HOST"]
32
+ t.column :col_array_json, :string, array: true if ENV["SPANNER_EMULATOR_HOST"]
33
+ end
34
+
35
+ create_table :firms do |t|
36
+ t.string :name
37
+ t.integer :rating
38
+ t.string :description
39
+ t.references :account
40
+ end
41
+
42
+ create_table :customers do |t|
43
+ t.string :name
44
+ end
45
+
46
+ create_table :accounts do |t|
47
+ t.references :customer, index: false
48
+ t.references :firm, index: false
49
+ t.string :name
50
+ t.integer :credit_limit
51
+ t.integer :transactions_count
52
+ end
53
+
54
+ create_table :transactions do |t|
55
+ t.float :amount
56
+ t.references :account, index: false
57
+ end
58
+
59
+ create_table :departments do |t|
60
+ t.string :name
61
+ t.references :resource, polymorphic: true
62
+ end
63
+
64
+ create_table :member_types do |t|
65
+ t.string :name
66
+ end
67
+
68
+ create_table :members do |t|
69
+ t.string :name
70
+ t.references :member_type, index: false
71
+ t.references :admittable, polymorphic: true, index: false
72
+ end
73
+
74
+ create_table :memberships do |t|
75
+ t.datetime :joined_on
76
+ t.references :club, index: false
77
+ t.references :member, index: false
78
+ t.boolean :favourite
79
+ end
80
+
81
+ create_table :clubs do |t|
82
+ t.string :name
83
+ end
84
+
85
+ create_table :authors do |t|
86
+ t.string :name, null: false
87
+ t.date :registered_date
88
+ t.references :organization, index: false
89
+ end
90
+
91
+ create_table :posts do |t|
92
+ t.string :title
93
+ t.string :content
94
+ t.references :author
95
+ t.integer :comments_count
96
+ t.date :post_date
97
+ t.time :published_time
98
+ end
99
+
100
+ create_table :comments do |t|
101
+ t.string :comment
102
+ t.references :post, index: false, foreign_key: true
103
+ end
104
+
105
+ create_table :addresses do |t|
106
+ t.string :line1
107
+ t.string :postal_code
108
+ t.string :city
109
+ t.references :author, index: false
110
+ end
111
+
112
+ create_table :organizations do |t|
113
+ t.string :name
114
+ t.datetime :last_updated, allow_commit_timestamp: true
115
+ end
116
+
117
+ create_table :singers, id: false do |t|
118
+ t.primary_key :singerid
119
+ t.column :first_name, :string, limit: 200
120
+ t.string :last_name
121
+ t.integer :tracks_count
122
+ t.integer :lock_version
123
+ t.string :full_name, as: "COALESCE(first_name || ' ', '') || last_name", stored: true
124
+ end
125
+
126
+ create_table :albums, id: false do |t|
127
+ t.interleave_in :singers
128
+ t.primary_key :albumid
129
+ # `singerid` is part of the primary key in the table definition, but it is not visible to ActiveRecord as part of
130
+ # the primary key, to prevent ActiveRecord from considering this to be an entity with a composite primary key.
131
+ t.parent_key :singerid
132
+ t.string :title
133
+ t.integer :lock_version
134
+ end
135
+
136
+ create_table :tracks, id: false do |t|
137
+ # `:cascade` causes all tracks that belong to an album to automatically be deleted when an album is deleted.
138
+ t.interleave_in :albums, :cascade
139
+ t.primary_key :trackid
140
+ t.parent_key :singerid
141
+ t.parent_key :albumid
142
+ t.string :title
143
+ t.numeric :duration
144
+ t.integer :lock_version
145
+ end
146
+ end
147
+ end