activerecord-spanner-adapter 1.8.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/acceptance-tests-on-emulator.yaml +4 -6
- data/.github/workflows/ci.yaml +4 -6
- data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +4 -6
- data/.github/workflows/nightly-unit-tests.yaml +4 -6
- data/.github/workflows/rubocop.yaml +1 -1
- data/.github/workflows/samples.yaml +30 -0
- data/.kokoro/release.cfg +2 -2
- data/.kokoro/release.sh +1 -4
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +2 -2
- data/CHANGELOG.md +28 -0
- data/Gemfile +6 -5
- data/README.md +26 -22
- data/acceptance/cases/migration/command_recorder_test.rb +7 -38
- data/acceptance/cases/migration/references_index_test.rb +2 -11
- data/acceptance/cases/models/binary_identifiers.rb +97 -0
- data/acceptance/cases/models/default_value_test.rb +2 -2
- data/acceptance/cases/tasks/database_tasks_test.rb +71 -74
- data/acceptance/cases/transactions/read_write_transactions_test.rb +10 -4
- data/acceptance/models/binary_project.rb +20 -0
- data/acceptance/models/string_io.rb +28 -0
- data/acceptance/models/user.rb +20 -0
- data/acceptance/test_helper.rb +22 -8
- data/activerecord-spanner-adapter.gemspec +3 -3
- data/benchmarks/application.rb +3 -7
- data/examples/snippets/Rakefile +28 -5
- data/examples/snippets/array-data-type/application.rb +1 -5
- data/examples/snippets/array-data-type/config/database.yml +1 -0
- data/examples/snippets/auto-generated-primary-key/README.md +140 -0
- data/examples/snippets/auto-generated-primary-key/Rakefile +13 -0
- data/examples/snippets/auto-generated-primary-key/application.rb +86 -0
- data/examples/snippets/auto-generated-primary-key/config/database.yml +10 -0
- data/examples/snippets/auto-generated-primary-key/db/migrate/01_create_tables.rb +29 -0
- data/examples/snippets/auto-generated-primary-key/db/seeds.rb +31 -0
- data/examples/snippets/auto-generated-primary-key/models/album.rb +11 -0
- data/examples/snippets/auto-generated-primary-key/models/singer.rb +11 -0
- data/examples/snippets/bit-reversed-sequence/application.rb +0 -4
- data/examples/snippets/bit-reversed-sequence/config/database.yml +1 -0
- data/examples/snippets/bit-reversed-sequence/db/seeds.rb +2 -2
- data/examples/snippets/bulk-insert/application.rb +1 -5
- data/examples/snippets/bulk-insert/config/database.yml +1 -0
- data/examples/snippets/commit-timestamp/application.rb +0 -4
- data/examples/snippets/commit-timestamp/config/database.yml +1 -0
- data/examples/snippets/config/environment.rb +5 -0
- data/examples/snippets/create-records/application.rb +1 -5
- data/examples/snippets/create-records/config/database.yml +1 -0
- data/examples/snippets/date-data-type/application.rb +1 -5
- data/examples/snippets/date-data-type/config/database.yml +1 -0
- data/examples/snippets/date-data-type/db/seeds.rb +1 -1
- data/examples/snippets/generated-column/application.rb +0 -4
- data/examples/snippets/generated-column/config/database.yml +1 -0
- data/examples/snippets/generated-column/db/seeds.rb +1 -1
- data/examples/snippets/hints/application.rb +0 -4
- data/examples/snippets/hints/config/database.yml +1 -0
- data/examples/snippets/hints/db/seeds.rb +1 -1
- data/examples/snippets/interleaved-tables/application.rb +1 -5
- data/examples/snippets/interleaved-tables/config/database.yml +1 -0
- data/examples/snippets/interleaved-tables/db/seeds.rb +1 -1
- data/examples/snippets/interleaved-tables/models/album.rb +6 -2
- data/examples/snippets/interleaved-tables/models/track.rb +5 -1
- data/examples/snippets/interleaved-tables-before-7.1/application.rb +1 -5
- data/examples/snippets/interleaved-tables-before-7.1/config/database.yml +1 -0
- data/examples/snippets/interleaved-tables-before-7.1/db/seeds.rb +1 -1
- data/examples/snippets/migrations/application.rb +0 -4
- data/examples/snippets/migrations/config/database.yml +1 -0
- data/examples/snippets/mutations/application.rb +1 -5
- data/examples/snippets/mutations/config/database.yml +1 -0
- data/examples/snippets/mutations/db/seeds.rb +1 -1
- data/examples/snippets/optimistic-locking/application.rb +0 -4
- data/examples/snippets/optimistic-locking/config/database.yml +1 -0
- data/examples/snippets/optimistic-locking/db/seeds.rb +1 -1
- data/examples/snippets/partitioned-dml/application.rb +0 -4
- data/examples/snippets/partitioned-dml/config/database.yml +1 -0
- data/examples/snippets/partitioned-dml/db/seeds.rb +1 -1
- data/examples/snippets/query-logs/application.rb +15 -13
- data/examples/snippets/query-logs/config/database.yml +1 -0
- data/examples/snippets/query-logs/db/seeds.rb +1 -1
- data/examples/snippets/quickstart/application.rb +0 -4
- data/examples/snippets/quickstart/config/database.yml +1 -0
- data/examples/snippets/quickstart/db/seeds.rb +1 -1
- data/examples/snippets/read-only-transactions/application.rb +0 -4
- data/examples/snippets/read-only-transactions/config/database.yml +1 -0
- data/examples/snippets/read-only-transactions/db/seeds.rb +1 -1
- data/examples/snippets/read-write-transactions/application.rb +2 -6
- data/examples/snippets/read-write-transactions/config/database.yml +1 -0
- data/examples/snippets/read-write-transactions/db/seeds.rb +1 -1
- data/examples/snippets/stale-reads/application.rb +0 -4
- data/examples/snippets/stale-reads/config/database.yml +1 -0
- data/examples/snippets/stale-reads/db/seeds.rb +1 -1
- data/examples/snippets/tags/application.rb +0 -4
- data/examples/snippets/tags/config/database.yml +1 -0
- data/examples/snippets/tags/db/seeds.rb +1 -1
- data/examples/snippets/timestamp-data-type/application.rb +0 -4
- data/examples/snippets/timestamp-data-type/config/database.yml +1 -0
- data/lib/active_record/connection_adapters/spanner/column.rb +7 -3
- data/lib/active_record/connection_adapters/spanner/database_statements.rb +34 -22
- data/lib/active_record/connection_adapters/spanner/quoting.rb +2 -1
- data/lib/active_record/connection_adapters/spanner/schema_creation.rb +20 -11
- data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +12 -2
- data/lib/active_record/connection_adapters/spanner/schema_statements.rb +22 -51
- data/lib/active_record/connection_adapters/spanner/type_metadata.rb +10 -8
- data/lib/active_record/connection_adapters/spanner_adapter.rb +42 -7
- data/lib/active_record/tasks/spanner_database_tasks.rb +4 -4
- data/lib/active_record/type/spanner/array.rb +4 -0
- data/lib/active_record/type/spanner/bytes.rb +10 -0
- data/lib/activerecord_spanner_adapter/base.rb +59 -32
- data/lib/activerecord_spanner_adapter/connection.rb +9 -5
- data/lib/activerecord_spanner_adapter/foreign_key.rb +9 -2
- data/lib/activerecord_spanner_adapter/index/column.rb +6 -1
- data/lib/activerecord_spanner_adapter/index.rb +10 -2
- data/lib/activerecord_spanner_adapter/information_schema.rb +5 -3
- data/lib/activerecord_spanner_adapter/primary_key.rb +2 -2
- data/lib/activerecord_spanner_adapter/table/column.rb +16 -4
- data/lib/activerecord_spanner_adapter/table.rb +8 -2
- data/lib/activerecord_spanner_adapter/transaction.rb +1 -1
- data/lib/activerecord_spanner_adapter/version.rb +1 -1
- data/lib/arel/visitors/spanner.rb +16 -11
- data/lib/spanner_client_ext.rb +4 -3
- metadata +23 -34
- data/examples/snippets/array-data-type/db/schema.rb +0 -31
- data/examples/snippets/bit-reversed-sequence/db/schema.rb +0 -31
- data/examples/snippets/bulk-insert/db/schema.rb +0 -31
- data/examples/snippets/commit-timestamp/db/schema.rb +0 -34
- data/examples/snippets/create-records/db/schema.rb +0 -31
- data/examples/snippets/date-data-type/db/schema.rb +0 -26
- data/examples/snippets/generated-column/db/schema.rb +0 -26
- data/examples/snippets/hints/db/schema.rb +0 -33
- data/examples/snippets/interleaved-tables/db/schema.rb +0 -39
- data/examples/snippets/interleaved-tables-before-7.1/db/schema.rb +0 -37
- data/examples/snippets/migrations/db/schema.rb +0 -38
- data/examples/snippets/mutations/db/schema.rb +0 -32
- data/examples/snippets/optimistic-locking/db/schema.rb +0 -34
- data/examples/snippets/partitioned-dml/db/schema.rb +0 -31
- data/examples/snippets/query-logs/db/schema.rb +0 -31
- data/examples/snippets/quickstart/db/schema.rb +0 -31
- data/examples/snippets/read-only-transactions/db/schema.rb +0 -31
- data/examples/snippets/read-write-transactions/db/schema.rb +0 -32
- data/examples/snippets/stale-reads/db/schema.rb +0 -31
- data/examples/snippets/tags/db/schema.rb +0 -31
- data/examples/snippets/timestamp-data-type/db/schema.rb +0 -26
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -13,7 +13,7 @@ require_relative "models/track"
|
|
13
13
|
class Application
|
14
14
|
def self.run
|
15
15
|
# List all singers, albums and tracks.
|
16
|
-
|
16
|
+
list_singers_albums
|
17
17
|
|
18
18
|
# Create a new album with some tracks.
|
19
19
|
create_new_album
|
@@ -28,10 +28,6 @@ class Application
|
|
28
28
|
# Try to delete an album that has at least one track. This IS possible as tracks IS marked with
|
29
29
|
# ON DELETE CASCADE.
|
30
30
|
delete_album_with_tracks
|
31
|
-
|
32
|
-
puts ""
|
33
|
-
puts "Press any key to end the application"
|
34
|
-
STDIN.getch
|
35
31
|
end
|
36
32
|
|
37
33
|
def self.find_singer
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
require_relative "../models/track"
|
@@ -11,6 +11,10 @@ class Album < ActiveRecord::Base
|
|
11
11
|
|
12
12
|
# `tracks` is defined as INTERLEAVE IN PARENT `albums`.
|
13
13
|
# The primary key of `albums` is (`singerid`, `albumid`).
|
14
|
-
|
15
|
-
|
14
|
+
if ActiveRecord::VERSION::MAJOR >= 8
|
15
|
+
has_many :tracks, foreign_key: [:singerid, :albumid]
|
16
|
+
else
|
17
|
+
# Rails 7.1 requires using query_constraints to define a composite foreign key.
|
18
|
+
has_many :tracks, query_constraints: [:singerid, :albumid]
|
19
|
+
end
|
16
20
|
end
|
@@ -8,7 +8,11 @@ class Track < ActiveRecord::Base
|
|
8
8
|
# `tracks` is defined as INTERLEAVE IN PARENT `albums`.
|
9
9
|
# The primary key of `albums` is (`singerid`, `albumid`).
|
10
10
|
# Rails 7.1 requires a composite primary key in a belongs_to relationship to be specified as query_constraints.
|
11
|
-
|
11
|
+
if ActiveRecord::VERSION::MAJOR >= 8
|
12
|
+
belongs_to :album, foreign_key: [:singerid, :albumid]
|
13
|
+
else
|
14
|
+
belongs_to :album, query_constraints: [:singerid, :albumid]
|
15
|
+
end
|
12
16
|
|
13
17
|
# `tracks` also has a `singerid` column that can be used to associate a Track with a Singer.
|
14
18
|
belongs_to :singer, foreign_key: :singerid
|
@@ -13,7 +13,7 @@ require_relative "models/track"
|
|
13
13
|
class Application
|
14
14
|
def self.run
|
15
15
|
# List all singers, albums and tracks.
|
16
|
-
|
16
|
+
list_singers_albums
|
17
17
|
|
18
18
|
# Create a new album with some tracks.
|
19
19
|
create_new_album
|
@@ -28,10 +28,6 @@ class Application
|
|
28
28
|
# Try to delete an album that has at least one track. This IS possible as tracks IS marked with
|
29
29
|
# ON DELETE CASCADE.
|
30
30
|
delete_album_with_tracks
|
31
|
-
|
32
|
-
puts ""
|
33
|
-
puts "Press any key to end the application"
|
34
|
-
STDIN.getch
|
35
31
|
end
|
36
32
|
|
37
33
|
def self.find_singer
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
require_relative "../models/track"
|
@@ -22,7 +22,7 @@ class Application
|
|
22
22
|
to_album = Album.where.not(id: from_album.id).sample
|
23
23
|
|
24
24
|
puts ""
|
25
|
-
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) "\
|
25
|
+
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) " \
|
26
26
|
"to #{to_album.title} (#{to_album.marketing_budget})"
|
27
27
|
from_album.update marketing_budget: from_album.marketing_budget - 10000
|
28
28
|
to_album.update marketing_budget: to_album.marketing_budget + 10000
|
@@ -37,10 +37,6 @@ class Application
|
|
37
37
|
puts "Budgets after commit:"
|
38
38
|
puts "Marketing budget #{from_album.title}: #{from_album.reload.marketing_budget}"
|
39
39
|
puts "Marketing budget #{to_album.title}: #{to_album.reload.marketing_budget}"
|
40
|
-
|
41
|
-
puts ""
|
42
|
-
puts "Press any key to end the application"
|
43
|
-
STDIN.getch
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -17,10 +17,6 @@ class Application
|
|
17
17
|
puts "Query all Albums and include an automatically generated request tag"
|
18
18
|
albums = Album.all
|
19
19
|
puts "Queried #{albums.length} albums using an automatically generated request tag"
|
20
|
-
|
21
|
-
puts ""
|
22
|
-
puts "Press any key to end the application"
|
23
|
-
STDIN.getch
|
24
20
|
end
|
25
21
|
|
26
22
|
def self.enable_query_logs
|
@@ -31,16 +27,9 @@ class Application
|
|
31
27
|
# Query log comments *MUST* be prepended to be included as a request tag.
|
32
28
|
ActiveRecord::QueryLogs.prepend_comment = true
|
33
29
|
|
34
|
-
#
|
30
|
+
# Enable query logs in a non-Rails application.
|
35
31
|
# This should normally not be needed in your application.
|
36
|
-
|
37
|
-
application: "example-app",
|
38
|
-
action: "run-test-application",
|
39
|
-
pid: -> { Process.pid.to_s },
|
40
|
-
socket: ->(context) { context[:connection].pool.db_config.socket },
|
41
|
-
db_host: ->(context) { context[:connection].pool.db_config.host },
|
42
|
-
database: ->(context) { context[:connection].pool.db_config.database }
|
43
|
-
)
|
32
|
+
enable_query_logs_without_rails
|
44
33
|
|
45
34
|
ActiveRecord::QueryLogs.tags = [
|
46
35
|
# The first tag *MUST* be the fixed value 'request_tag:true'.
|
@@ -58,6 +47,19 @@ class Application
|
|
58
47
|
:database
|
59
48
|
]
|
60
49
|
end
|
50
|
+
|
51
|
+
def self.enable_query_logs_without_rails
|
52
|
+
# This block manually enables Query Logs without a full Rails application.
|
53
|
+
# This should normally not be needed in your application.
|
54
|
+
ActiveRecord::QueryLogs.taggings = {
|
55
|
+
application: "example-app",
|
56
|
+
action: "run-test-application",
|
57
|
+
pid: -> { Process.pid.to_s },
|
58
|
+
socket: ->(context) { context[:connection].pool.db_config.socket },
|
59
|
+
db_host: ->(context) { context[:connection].pool.db_config.host },
|
60
|
+
database: ->(context) { context[:connection].pool.db_config.database }
|
61
|
+
}
|
62
|
+
end
|
61
63
|
end
|
62
64
|
|
63
65
|
Application.run
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -10,7 +10,7 @@ require_relative "models/singer"
|
|
10
10
|
require_relative "models/album"
|
11
11
|
|
12
12
|
class Application
|
13
|
-
def self.run
|
13
|
+
def self.run
|
14
14
|
from_album = nil
|
15
15
|
to_album = nil
|
16
16
|
# Use a read/write transaction to execute multiple statements as an atomic unit.
|
@@ -20,7 +20,7 @@ class Application
|
|
20
20
|
to_album = Album.where.not(id: from_album.id).sample
|
21
21
|
|
22
22
|
puts ""
|
23
|
-
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) "\
|
23
|
+
puts "Transferring 10,000 marketing budget from #{from_album.title} (#{from_album.marketing_budget}) " \
|
24
24
|
"to #{to_album.title} (#{to_album.marketing_budget})"
|
25
25
|
from_album.update marketing_budget: from_album.marketing_budget - 10000
|
26
26
|
to_album.update marketing_budget: to_album.marketing_budget + 10000
|
@@ -29,10 +29,6 @@ class Application
|
|
29
29
|
puts "Budgets after update:"
|
30
30
|
puts "Marketing budget #{from_album.title}: #{from_album.reload.marketing_budget}"
|
31
31
|
puts "Marketing budget #{to_album.title}: #{to_album.reload.marketing_budget}"
|
32
|
-
|
33
|
-
puts ""
|
34
|
-
puts "Press any key to end the application"
|
35
|
-
STDIN.getch
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -22,10 +22,6 @@ class Application
|
|
22
22
|
albums = Album.annotate("request_tag: query-all-albums", "transaction_tag: sample-transaction").all
|
23
23
|
puts "Queried #{albums.length} albums using a request and a transaction tag"
|
24
24
|
end
|
25
|
-
|
26
|
-
puts ""
|
27
|
-
puts "Press any key to end the application"
|
28
|
-
STDIN.getch
|
29
25
|
end
|
30
26
|
end
|
31
27
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
5
5
|
# https://opensource.org/licenses/MIT.
|
6
6
|
|
7
|
-
require_relative "../../config/environment
|
7
|
+
require_relative "../../config/environment"
|
8
8
|
require_relative "../models/singer"
|
9
9
|
require_relative "../models/album"
|
10
10
|
|
@@ -32,10 +32,6 @@ class Application
|
|
32
32
|
# Simulate that the application is now running in the timezone America/Los_Angeles.
|
33
33
|
Time.zone = "America/Los_Angeles"
|
34
34
|
puts "#{'Meeting time in the local timezone (America/Los_Angeles):'.ljust 60} #{meeting.local_meeting_time}"
|
35
|
-
|
36
|
-
puts ""
|
37
|
-
puts "Press any key to end the application"
|
38
|
-
STDIN.getch
|
39
35
|
end
|
40
36
|
end
|
41
37
|
|
@@ -10,16 +10,20 @@ module ActiveRecord
|
|
10
10
|
module ConnectionAdapters
|
11
11
|
module Spanner
|
12
12
|
class Column < ConnectionAdapters::Column
|
13
|
-
# rubocop:disable Style/
|
13
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
14
14
|
def initialize(name, default, sql_type_metadata = nil, null = true,
|
15
15
|
default_function = nil, collation: nil, comment: nil,
|
16
16
|
primary_key: false, **)
|
17
|
-
# rubocop:enable Style/
|
17
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
18
18
|
super
|
19
19
|
@primary_key = primary_key
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def auto_incremented_by_db?
|
23
|
+
sql_type_metadata.is_identity
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_default?
|
23
27
|
super && !virtual?
|
24
28
|
end
|
25
29
|
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def internal_execute sql, name = "SQL", binds = [],
|
32
|
-
prepare: false, async: false, allow_retry: false # rubocop:disable Lint/UnusedMethodArgument,
|
32
|
+
prepare: false, async: false, allow_retry: false # rubocop:disable Lint/UnusedMethodArgument, /
|
33
33
|
statement_type = sql_statement_type sql
|
34
34
|
# Call `transform` to invoke any query transformers that might have been registered.
|
35
35
|
sql = transform sql
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
65
65
|
end
|
66
66
|
|
67
67
|
log_args = [sql, name]
|
68
|
-
log_args.
|
68
|
+
log_args.push binds, type_casted_binds(binds) if log_statement_binds
|
69
69
|
|
70
70
|
log(*log_args) do
|
71
71
|
types, params = to_types_and_params binds
|
@@ -83,12 +83,16 @@ module ActiveRecord
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def append_request_tag_from_query_logs sql, binds
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
86
|
+
possible_prefixes = [
|
87
|
+
"/*request_tag:true,",
|
88
|
+
"/*_request_tag='true',",
|
89
|
+
"/*_request_tag:true,",
|
90
|
+
"/*_request_tag='true',"
|
91
|
+
]
|
92
|
+
possible_prefixes.each do |prefix|
|
93
|
+
if sql.start_with? prefix
|
94
|
+
append_request_tag_from_query_logs_with_format sql, binds, prefix
|
95
|
+
end
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
@@ -101,7 +105,7 @@ module ActiveRecord
|
|
101
105
|
if options.request_tag == ""
|
102
106
|
options.request_tag = request_tag
|
103
107
|
else
|
104
|
-
options.request_tag += "
|
108
|
+
options.request_tag += ",#{request_tag}"
|
105
109
|
end
|
106
110
|
|
107
111
|
binds.append options
|
@@ -192,7 +196,7 @@ module ActiveRecord
|
|
192
196
|
# and this RPC can return multiple partial result sets for DML as well. Only the last partial
|
193
197
|
# result set will contain the statistics. Although there will never be any rows, this makes
|
194
198
|
# sure that the stream is fully consumed.
|
195
|
-
result.rows.each { |_| }
|
199
|
+
result.rows.each { |_| } # rubocop:disable Lint/EmptyBlock
|
196
200
|
return result.row_count if result.row_count
|
197
201
|
|
198
202
|
raise ActiveRecord::StatementInvalid.new(
|
@@ -282,12 +286,12 @@ module ActiveRecord
|
|
282
286
|
#
|
283
287
|
def begin_isolated_db_transaction isolation
|
284
288
|
if isolation.is_a? Hash
|
285
|
-
raise "Unsupported isolation level: #{isolation}" unless
|
289
|
+
raise "Unsupported isolation level: #{isolation}" unless
|
286
290
|
isolation[:timestamp] || isolation[:staleness] || isolation[:strong]
|
287
291
|
raise "Only one option is supported. It must be one of `timestamp`, `staleness` or `strong`." \
|
288
292
|
if isolation.count != 1
|
289
293
|
else
|
290
|
-
raise "Unsupported isolation level: #{isolation}" unless
|
294
|
+
raise "Unsupported isolation level: #{isolation}" unless
|
291
295
|
[:serializable, :read_only, :buffered_mutations, :pdml].include? isolation
|
292
296
|
end
|
293
297
|
|
@@ -312,26 +316,35 @@ module ActiveRecord
|
|
312
316
|
|
313
317
|
# Translates binds to Spanner types and params.
|
314
318
|
def to_types_and_params binds
|
315
|
-
types = binds
|
319
|
+
types = to_types binds
|
320
|
+
params = to_params binds
|
321
|
+
[types, params]
|
322
|
+
end
|
323
|
+
|
324
|
+
def to_types binds
|
325
|
+
binds.enum_for(:each_with_index).to_h do |bind, i|
|
316
326
|
type = :INT64
|
317
327
|
if bind.respond_to? :type
|
318
328
|
type = ActiveRecord::Type::Spanner::SpannerActiveRecordConverter
|
319
329
|
.convert_active_model_type_to_spanner(bind.type)
|
320
|
-
elsif bind.
|
330
|
+
elsif bind.instance_of? Symbol
|
321
331
|
# This ensures that for example :environment is sent as the string 'environment' to Cloud Spanner.
|
322
332
|
type = :STRING
|
323
|
-
elsif bind.
|
333
|
+
elsif bind.instance_of?(TrueClass) || bind.instance_of?(FalseClass)
|
324
334
|
type = :BOOL
|
325
335
|
end
|
326
336
|
[
|
327
337
|
# Generates binds for named parameters in the format `@p1, @p2, ...`
|
328
338
|
"p#{i + 1}", type
|
329
339
|
]
|
330
|
-
end
|
331
|
-
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def to_params binds
|
344
|
+
binds.enum_for(:each_with_index).to_h do |bind, i|
|
332
345
|
type = if bind.respond_to? :type
|
333
346
|
bind.type
|
334
|
-
elsif bind.
|
347
|
+
elsif bind.instance_of? Symbol
|
335
348
|
# This ensures that for example :environment is sent as the string 'environment' to Cloud Spanner.
|
336
349
|
:STRING
|
337
350
|
else
|
@@ -343,8 +356,7 @@ module ActiveRecord
|
|
343
356
|
.serialize_with_transaction_isolation_level(type, bind_value, :dml)
|
344
357
|
|
345
358
|
["p#{i + 1}", value]
|
346
|
-
end
|
347
|
-
[types, params]
|
359
|
+
end
|
348
360
|
end
|
349
361
|
|
350
362
|
# An insert/update/delete statement could use mutations in some specific circumstances.
|
@@ -353,7 +365,7 @@ module ActiveRecord
|
|
353
365
|
def should_use_mutation arel
|
354
366
|
!@connection.current_transaction.nil? \
|
355
367
|
&& @connection.current_transaction.isolation == :buffered_mutations \
|
356
|
-
&& can_use_mutation(arel)
|
368
|
+
&& can_use_mutation(arel)
|
357
369
|
end
|
358
370
|
|
359
371
|
def can_use_mutation arel
|
@@ -383,7 +395,7 @@ module ActiveRecord
|
|
383
395
|
)
|
384
396
|
end
|
385
397
|
|
386
|
-
COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
|
398
|
+
COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m \
|
387
399
|
unless defined? ActiveRecord::ConnectionAdapters::AbstractAdapter::COMMENT_REGEX
|
388
400
|
COMMENT_REGEX = ActiveRecord::ConnectionAdapters::AbstractAdapter::COMMENT_REGEX \
|
389
401
|
if defined? ActiveRecord::ConnectionAdapters::AbstractAdapter::COMMENT_REGEX
|
@@ -45,6 +45,7 @@ module ActiveRecord
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
48
49
|
module Spanner
|
49
50
|
module Quoting
|
50
51
|
def quote_column_name name
|
@@ -55,7 +56,7 @@ module ActiveRecord
|
|
55
56
|
QUOTED_TABLE_NAMES[name] ||= "`#{name.to_s.gsub '.', '`.`'}`".freeze
|
56
57
|
end
|
57
58
|
|
58
|
-
STR_ESCAPE_REGX = /[\n\r'\\]
|
59
|
+
STR_ESCAPE_REGX = /[\n\r'\\]/
|
59
60
|
STR_ESCAPE_VALUES = {
|
60
61
|
"\n" => "\\n", "\r" => "\\r", "'" => "\\'", "\\" => "\\\\"
|
61
62
|
}.freeze
|