activerecord-spanner-adapter 1.2.1 → 1.3.1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/.github/blunderbuss.yml +1 -1
  4. data/.release-please-manifest.json +1 -1
  5. data/CHANGELOG.md +29 -0
  6. data/README.md +7 -2
  7. data/acceptance/cases/migration/schema_dumper_test.rb +69 -0
  8. data/acceptance/cases/models/generated_column_test.rb +21 -7
  9. data/acceptance/cases/models/interleave_test.rb +36 -0
  10. data/acceptance/cases/models/logging_test.rb +53 -0
  11. data/acceptance/cases/models/query_test.rb +6 -1
  12. data/acceptance/cases/tasks/database_tasks_test.rb +407 -0
  13. data/acceptance/models/album_partial_disabled.rb +17 -0
  14. data/acceptance/schema/schema.rb +139 -134
  15. data/acceptance/test_helper.rb +2 -0
  16. data/examples/snippets/array-data-type/db/schema.rb +8 -3
  17. data/examples/snippets/bulk-insert/db/schema.rb +9 -4
  18. data/examples/snippets/commit-timestamp/db/schema.rb +11 -6
  19. data/examples/snippets/create-records/db/schema.rb +9 -4
  20. data/examples/snippets/date-data-type/db/schema.rb +8 -3
  21. data/examples/snippets/generated-column/db/schema.rb +6 -1
  22. data/examples/snippets/hints/db/schema.rb +6 -1
  23. data/examples/snippets/interleaved-tables/README.md +2 -2
  24. data/examples/snippets/interleaved-tables/db/schema.rb +5 -0
  25. data/examples/snippets/migrations/db/schema.rb +10 -5
  26. data/examples/snippets/mutations/db/schema.rb +9 -4
  27. data/examples/snippets/optimistic-locking/db/schema.rb +9 -4
  28. data/examples/snippets/partitioned-dml/db/schema.rb +5 -0
  29. data/examples/snippets/quickstart/db/schema.rb +9 -4
  30. data/examples/snippets/read-only-transactions/db/schema.rb +5 -0
  31. data/examples/snippets/read-write-transactions/db/schema.rb +9 -4
  32. data/examples/snippets/stale-reads/db/schema.rb +5 -0
  33. data/examples/snippets/timestamp-data-type/db/schema.rb +8 -3
  34. data/lib/active_record/connection_adapters/spanner/column.rb +23 -0
  35. data/lib/active_record/connection_adapters/spanner/database_statements.rb +7 -4
  36. data/lib/active_record/connection_adapters/spanner/quoting.rb +9 -0
  37. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +17 -4
  38. data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +11 -2
  39. data/lib/active_record/connection_adapters/spanner/schema_dumper.rb +56 -0
  40. data/lib/active_record/connection_adapters/spanner/schema_statements.rb +56 -9
  41. data/lib/active_record/connection_adapters/spanner/type_metadata.rb +19 -4
  42. data/lib/active_record/connection_adapters/spanner_adapter.rb +11 -0
  43. data/lib/active_record/tasks/spanner_database_tasks.rb +18 -4
  44. data/lib/active_record/type/spanner/spanner_active_record_converter.rb +10 -0
  45. data/lib/active_record/type/spanner/time.rb +10 -3
  46. data/lib/activerecord_spanner_adapter/base.rb +41 -27
  47. data/lib/activerecord_spanner_adapter/connection.rb +8 -3
  48. data/lib/activerecord_spanner_adapter/information_schema.rb +52 -3
  49. data/lib/activerecord_spanner_adapter/table/column.rb +7 -2
  50. data/lib/activerecord_spanner_adapter/version.rb +1 -1
  51. data/lib/arel/visitors/spanner.rb +8 -2
  52. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f8199e1af804baf47d382e53404f88329478d35958f71fcaec34f73921de987
4
- data.tar.gz: b2bc3919e5cc4d675d539806c27e0dda7b16d676ca349aa95a11370c4ec145b7
3
+ metadata.gz: 0b6dba891089af7c51b13f3b80ce8342b691d31cd0e31181dbd5799c240a2e9c
4
+ data.tar.gz: 54a6079aa300d4e31bb8f47630857e624e94995dc713aae60aa848ac3da41ca0
5
5
  SHA512:
6
- metadata.gz: 22ed1bd5840aa615681a7af2a4f87ceb31a5ec5a772d3260740ed520f99269b1ecdc0022aa1bcbf703afe01d99a04bb6181d546c5d6690bef20c17142281eb47
7
- data.tar.gz: b9d65faf249175397de04b003a612ed10f89302ba545ffe09208b43414e9e8291feb9240aae3850f5f97d6f6b0bfd9c6134176316ebf6cc520d487e8d9700447
6
+ metadata.gz: d5f05cd6a79976d974d3d5aa472d514146b5367dae7a4c334913627acc0c98154c8a247c0225a42f235c976b9d3e28cd8c29c46a3c1e876eda6c181619e11617
7
+ data.tar.gz: b943df790fa40955c31b5e9df89396a84d5f9b0499e8d610758238a249de1cc693b53f87f9b5d134b6595be5677222b04685206b8ca5d28472e6f9fbdac20ad9
data/.github/CODEOWNERS CHANGED
@@ -4,4 +4,4 @@
4
4
  # For syntax help see:
5
5
  # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
6
6
 
7
- * @googleapis/ruby-team @skuruppu @hengfengli @olavloite @xiangshen-dk
7
+ * @googleapis/ruby-team @olavloite @rahul2393 @ansh0l
@@ -1,2 +1,2 @@
1
1
  assign_issues:
2
- - hengfengli
2
+ - olavloite
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.2.1"
2
+ ".": "1.3.1"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ### 1.3.1 (2022-12-15)
4
+
5
+ #### Bug Fixes
6
+
7
+ * build error for ruby 2.5 ([#216](https://github.com/googleapis/ruby-spanner-activerecord/issues/216))
8
+
9
+ ### 1.3.0 (2022-12-08)
10
+
11
+ #### Features
12
+
13
+ * add check constraint support to migrations ([#205](https://github.com/googleapis/ruby-spanner-activerecord/issues/205))
14
+ * allows passing of type parameter when creating parent_key column ([#195](https://github.com/googleapis/ruby-spanner-activerecord/issues/195))
15
+ * include index options in the output of SchemaDumper ([#203](https://github.com/googleapis/ruby-spanner-activerecord/issues/203))
16
+ * schema_dumper should use DDL batch ([#207](https://github.com/googleapis/ruby-spanner-activerecord/issues/207))
17
+ * support column DEFAULT expressions in migrations ([#196](https://github.com/googleapis/ruby-spanner-activerecord/issues/196))
18
+ #### Bug Fixes
19
+
20
+ * ignore no database when recreating ([#208](https://github.com/googleapis/ruby-spanner-activerecord/issues/208))
21
+ #### Documentation
22
+
23
+ * fix typo in example of interleaved-tables ([#209](https://github.com/googleapis/ruby-spanner-activerecord/issues/209))
24
+
25
+ ### 1.2.2 (2022-08-29)
26
+
27
+ #### Documentation
28
+
29
+ * add ActiveRecord 7 as a supported version to the README ([#189](https://github.com/googleapis/ruby-spanner-activerecord/issues/189))
30
+ * update limitation on interleaved tables and default column values ([#190](https://github.com/googleapis/ruby-spanner-activerecord/issues/190))
31
+
3
32
  ### 1.2.1 (2022-08-28)
4
33
 
5
34
  #### Bug Fixes
data/README.md CHANGED
@@ -8,10 +8,14 @@ This project provides a Cloud Spanner adapter for ActiveRecord. It supports the
8
8
 
9
9
  - ActiveRecord 6.0.x with Ruby 2.6 and 2.7.
10
10
  - ActiveRecord 6.1.x with Ruby 2.6 and higher.
11
+ - ActiveRecord 7.0.x with Ruby 2.7 and higher.
11
12
 
12
13
  Known limitations are listed in the [Limitations](#limitations) section.
13
14
  Please report any problems that you might encounter by [creating a new issue](https://github.com/googleapis/ruby-spanner-activerecord/issues/new).
14
15
 
16
+ This adapter only supports GoogleSQL-dialect Cloud Spanner databases. PostgreSQL-dialect
17
+ databases are not supported.
18
+
15
19
  ## Installation
16
20
 
17
21
  Add this line to your application's Gemfile:
@@ -70,18 +74,19 @@ Some noteworthy examples in the snippets directory:
70
74
  for inserting, updating and deleting data in a Cloud Spanner database. Mutations can have a significant performance
71
75
  advantage compared to DML statements, but do not allow read-your-writes semantics during a transaction.
72
76
  - [array-data-type](examples/snippets/array-data-type): Shows how to work with `ARRAY` data types.
77
+ - [interleaved-tables](examples/snippets/interleaved-tables): Shows how to work with [Interleaved Tables](https://cloud.google.com/spanner/docs/schema-and-data-model#create-interleaved-tables).
73
78
 
74
79
  ## Limitations
75
80
 
76
81
  Limitation|Comment|Resolution
77
82
  ---|---|---
78
- Interleaved tables are not supported|Cloud Spanner requires to use composite primary keys for interleaved tables, but Active Record does not support composite primary keys. More details: [#160](https://github.com/googleapis/ruby-spanner-activerecord/issues/160) |Use non-interleaved tables.
79
- Lack of DEFAULT for columns [change_column_default](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_default)|Cloud Spanner does not support DEFAULT values for columns. The use of default must be enforced in your controller logic| Always set a value in your model or controller logic.
83
+ Interleaved tables require composite primary keys| Cloud Spanner requires composite primary keys for interleaved tables. See {file:examples/snippets/interleaved-tables/README.md this example} for an example on how to use interleaved tables with ActiveRecord |Use composite primary keys.
80
84
  Lack of sequential and auto-assigned IDs|Cloud Spanner doesn't autogenerate IDs and this integration instead creates UUID4 to avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key) so you SHOULD NOT rely on IDs being sorted| UUID4s are automatically generated for primary keys.
81
85
  Table without Primary Key| Cloud Spanner support does not support tables without a primary key.| Always define a primary key for your table.
82
86
  Table names CANNOT have spaces within them whether back-ticked or not|Cloud Spanner DOES NOT support tables with spaces in them for example `Entity ID`|Ensure that your table names don't contain spaces.
83
87
  Table names CANNOT have punctuation marks and MUST contain valid UTF-8|Cloud Spanner DOES NOT support punctuation marks e.g. periods ".", question marks "?" in table names|Ensure that your table names don't contain punctuation marks.
84
88
  Index with fields length [add_index](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index)|Cloud Spanner does not support index with fields length | Ensure that your database definition does not include index definitions with field lengths.
89
+ Only GoogleSQL-dialect databases| Cloud Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases. | Ensure that your database uses the GoogleSQL dialect.
85
90
 
86
91
  ## Contributing
87
92
 
@@ -0,0 +1,69 @@
1
+ # Copyright 2022 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
+ def test_dump_schema_contains_start_batch_ddl
17
+ connection = ActiveRecord::Base.connection
18
+ schema = StringIO.new
19
+ ActiveRecord::SchemaDumper.dump connection, schema
20
+ assert schema.string.include?("connection.start_batch_ddl")
21
+ end
22
+
23
+ def test_dump_schema_contains_run_batch
24
+ connection = ActiveRecord::Base.connection
25
+ schema = StringIO.new
26
+ ActiveRecord::SchemaDumper.dump connection, schema
27
+ assert schema.string.include?(" connection.run_batch\n"\
28
+ "rescue\n"\
29
+ " abort_batch\n"\
30
+ " raise")
31
+ end
32
+
33
+ def test_dump_schema_contains_albums_table
34
+ connection = ActiveRecord::Base.connection
35
+ schema = StringIO.new
36
+ ActiveRecord::SchemaDumper.dump connection, schema
37
+ assert schema.string.include?("create_table \"albums\", primary_key: \"albumid\"")
38
+ end
39
+
40
+ def test_dump_schema_contains_interleaved_index
41
+ connection = ActiveRecord::Base.connection
42
+ schema = StringIO.new
43
+ ActiveRecord::SchemaDumper.dump connection, schema
44
+ assert schema.string.include?("t.index [\"singerid\", \"albumid\", \"title\"], name: \"index_tracks_on_singerid_and_albumid_and_title\", order: { singerid: :asc, albumid: :asc, title: :asc }, null_filtered: true, interleave_in: \"albums\""), schema.string
45
+ end
46
+
47
+ def test_dump_schema_should_not_contain_id_limit
48
+ connection = ActiveRecord::Base.connection
49
+ schema = StringIO.new
50
+ ActiveRecord::SchemaDumper.dump connection, schema
51
+ assert !schema.string.include?("id: { limit: 8 }")
52
+ end
53
+
54
+ def test_dump_schema_contains_commit_timestamp
55
+ connection = ActiveRecord::Base.connection
56
+ schema = StringIO.new
57
+ ActiveRecord::SchemaDumper.dump connection, schema
58
+ assert schema.string.include?("t.time \"last_updated\", allow_commit_timestamp: true"), schema.string
59
+ end
60
+
61
+ def test_dump_schema_contains_virtual_column
62
+ connection = ActiveRecord::Base.connection
63
+ schema = StringIO.new
64
+ ActiveRecord::SchemaDumper.dump connection, schema
65
+ assert schema.string.include?("t.virtual \"full_name\", type: :string, as: \"COALESCE(first_name || ' ', '') || last_name\", stored: true"), schema.string
66
+ end
67
+ end
68
+ end
69
+ end
@@ -76,13 +76,24 @@ module ActiveRecord
76
76
  end
77
77
  end
78
78
 
79
+ VERSION_7 = ActiveRecord.gem_version >= Gem::Version.create("7.0.0")
80
+
81
+ def assert_raises_below_ar_7(ex, &test)
82
+ if VERSION_7
83
+ assert_nothing_raised &test
84
+ else
85
+ assert_raises ex, &test
86
+ end
87
+ end
88
+
79
89
  def test_create_with_value_for_generated_column
80
90
  # Note: The statement itself will not fail for an explicit transaction that uses buffered transactions.
81
91
  # Instead, the commit will fail. That is tested in a separate test case.
82
92
  [nil, :serializable].each do |isolation|
83
93
  run_in_transaction isolation do
84
- assert_raises ActiveRecord::StatementInvalid do
85
- Singer.create first_name: "Pete", last_name: "Allison", full_name: "Alice Peterson"
94
+ assert_raises_below_ar_7 ActiveRecord::StatementInvalid do
95
+ singer = Singer.create first_name: "Pete", last_name: "Allison", full_name: "Alice Peterson"
96
+ assert_equal "Pete Allison", singer.reload.full_name
86
97
  end
87
98
  end
88
99
  end
@@ -90,10 +101,11 @@ module ActiveRecord
90
101
 
91
102
  def test_create_with_value_for_generated_column_buffered_mutations
92
103
  # The transaction itself will raise an error, as the failure occurs during the commit.
93
- assert_raises ActiveRecord::StatementInvalid do
94
- Singer.transaction isolation: :buffered_mutations do
104
+ assert_raises_below_ar_7 ActiveRecord::StatementInvalid do
105
+ singer = run_in_transaction :buffered_mutations do
95
106
  Singer.create first_name: "Pete", last_name: "Allison", full_name: "Alice Peterson"
96
107
  end
108
+ assert_equal "Pete Allison", singer.reload.full_name
97
109
  end
98
110
  end
99
111
 
@@ -104,10 +116,11 @@ module ActiveRecord
104
116
  singer = Singer.create first_name: "Pete", last_name: "Allison"
105
117
  singer.reload # reload to ensure the full_name attribute is populated.
106
118
  run_in_transaction isolation do
107
- assert_raises ActiveRecord::StatementInvalid do
119
+ assert_raises_below_ar_7 ActiveRecord::StatementInvalid do
108
120
  Singer.update full_name: "Alice Peterson"
109
121
  end
110
122
  end
123
+ assert_equal "Pete Allison", singer.reload.full_name
111
124
  end
112
125
  end
113
126
 
@@ -115,11 +128,12 @@ module ActiveRecord
115
128
  singer = Singer.create first_name: "Pete", last_name: "Allison"
116
129
  singer.reload # reload to ensure the full_name attribute is populated.
117
130
  # The transaction itself will raise an error, as the failure occurs during the commit.
118
- assert_raises ActiveRecord::StatementInvalid do
119
- Singer.transaction isolation: :buffered_mutations do
131
+ assert_raises_below_ar_7 ActiveRecord::StatementInvalid do
132
+ run_in_transaction :buffered_mutations do
120
133
  Singer.update full_name: "Alice Peterson"
121
134
  end
122
135
  end
136
+ assert_equal "Pete Allison", singer.reload.full_name
123
137
  end
124
138
  end
125
139
  end
@@ -0,0 +1,36 @@
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
+ require "models/singer"
11
+ require "models/album_partial_disabled"
12
+
13
+ module ActiveRecord
14
+ module Model
15
+ class InterleaveTest < SpannerAdapter::TestCase
16
+ include SpannerAdapter::Associations::TestHelper
17
+
18
+ attr_accessor :singer
19
+
20
+ def setup
21
+ super
22
+
23
+ @singer = Singer.create first_name: "FirstName", last_name: "LastName"
24
+ end
25
+
26
+ def teardown
27
+ Album.destroy_all
28
+ Singer.destroy_all
29
+ end
30
+
31
+ def test_with_partial_inserts_disabled
32
+ AlbumPartialDisabled.create! title: "Title3", singer: singer
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,53 @@
1
+ # Copyright 2022 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 "active_support/log_subscriber/test_helper"
10
+ require "test_helper"
11
+ require "models/post"
12
+
13
+ module ActiveRecord
14
+ module Model
15
+ class LoggingTest < SpannerAdapter::TestCase
16
+ include ActiveSupport::LogSubscriber::TestHelper
17
+
18
+ setup do
19
+ ActiveRecord::LogSubscriber.attach_to(:active_record)
20
+ end
21
+
22
+ def test_logs_without_binds
23
+ published_time = Time.new(2016, 05, 11, 19, 0, 0)
24
+ Post.where(published_time: published_time, title: 'Title - 1').first
25
+
26
+ wait
27
+ assert @logger.logged(:debug).length >= 1
28
+ assert_no_match "[[\"published_time\", \"#{published_time.utc.iso8601(9)}\"], [\"title\", \"Title - 1\"]",
29
+ @logger.logged(:debug).last
30
+ end
31
+
32
+ def test_logs_with_binds
33
+ ActiveRecord::ConnectionAdapters::SpannerAdapter.log_statement_binds = true
34
+
35
+ published_time = Time.new(2016, 05, 11, 19, 0, 0)
36
+ Post.where(published_time: published_time, title: 'Title - 1').first
37
+
38
+ wait
39
+ assert @logger.logged(:debug).length >= 1
40
+ assert_match "[[\"published_time\", \"#{published_time.utc.iso8601(9)}\"], [\"title\", \"Title - 1\"]",
41
+ @logger.logged(:debug).last
42
+ ensure
43
+ ActiveRecord::ConnectionAdapters::SpannerAdapter.log_statement_binds = false
44
+ end
45
+
46
+ private
47
+
48
+ def set_logger(logger)
49
+ ActiveRecord::Base.logger = logger
50
+ end
51
+ end
52
+ end
53
+ end
@@ -166,6 +166,11 @@ module ActiveRecord
166
166
  assert_nil post.id
167
167
  assert_equal "Title - 1", post.title
168
168
  end
169
+
170
+ def test_to_sql
171
+ assert_equal "SELECT `comments`.* FROM `comments` WHERE `comments`.`comment` = 'Comment - 2'",
172
+ Comment.where(comment: 'Comment - 2').to_sql
173
+ end
169
174
  end
170
175
  end
171
- end
176
+ end