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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/acceptance-tests-on-emulator.yaml +4 -6
  3. data/.github/workflows/ci.yaml +4 -6
  4. data/.github/workflows/nightly-acceptance-tests-on-emulator.yaml +4 -6
  5. data/.github/workflows/nightly-unit-tests.yaml +4 -6
  6. data/.github/workflows/rubocop.yaml +1 -1
  7. data/.github/workflows/samples.yaml +30 -0
  8. data/.kokoro/release.cfg +2 -2
  9. data/.kokoro/release.sh +1 -4
  10. data/.release-please-manifest.json +1 -1
  11. data/.rubocop.yml +2 -2
  12. data/CHANGELOG.md +28 -0
  13. data/Gemfile +6 -5
  14. data/README.md +26 -22
  15. data/acceptance/cases/migration/command_recorder_test.rb +7 -38
  16. data/acceptance/cases/migration/references_index_test.rb +2 -11
  17. data/acceptance/cases/models/binary_identifiers.rb +97 -0
  18. data/acceptance/cases/models/default_value_test.rb +2 -2
  19. data/acceptance/cases/tasks/database_tasks_test.rb +71 -74
  20. data/acceptance/cases/transactions/read_write_transactions_test.rb +10 -4
  21. data/acceptance/models/binary_project.rb +20 -0
  22. data/acceptance/models/string_io.rb +28 -0
  23. data/acceptance/models/user.rb +20 -0
  24. data/acceptance/test_helper.rb +22 -8
  25. data/activerecord-spanner-adapter.gemspec +3 -3
  26. data/benchmarks/application.rb +3 -7
  27. data/examples/snippets/Rakefile +28 -5
  28. data/examples/snippets/array-data-type/application.rb +1 -5
  29. data/examples/snippets/array-data-type/config/database.yml +1 -0
  30. data/examples/snippets/auto-generated-primary-key/README.md +140 -0
  31. data/examples/snippets/auto-generated-primary-key/Rakefile +13 -0
  32. data/examples/snippets/auto-generated-primary-key/application.rb +86 -0
  33. data/examples/snippets/auto-generated-primary-key/config/database.yml +10 -0
  34. data/examples/snippets/auto-generated-primary-key/db/migrate/01_create_tables.rb +29 -0
  35. data/examples/snippets/auto-generated-primary-key/db/seeds.rb +31 -0
  36. data/examples/snippets/auto-generated-primary-key/models/album.rb +11 -0
  37. data/examples/snippets/auto-generated-primary-key/models/singer.rb +11 -0
  38. data/examples/snippets/bit-reversed-sequence/application.rb +0 -4
  39. data/examples/snippets/bit-reversed-sequence/config/database.yml +1 -0
  40. data/examples/snippets/bit-reversed-sequence/db/seeds.rb +2 -2
  41. data/examples/snippets/bulk-insert/application.rb +1 -5
  42. data/examples/snippets/bulk-insert/config/database.yml +1 -0
  43. data/examples/snippets/commit-timestamp/application.rb +0 -4
  44. data/examples/snippets/commit-timestamp/config/database.yml +1 -0
  45. data/examples/snippets/config/environment.rb +5 -0
  46. data/examples/snippets/create-records/application.rb +1 -5
  47. data/examples/snippets/create-records/config/database.yml +1 -0
  48. data/examples/snippets/date-data-type/application.rb +1 -5
  49. data/examples/snippets/date-data-type/config/database.yml +1 -0
  50. data/examples/snippets/date-data-type/db/seeds.rb +1 -1
  51. data/examples/snippets/generated-column/application.rb +0 -4
  52. data/examples/snippets/generated-column/config/database.yml +1 -0
  53. data/examples/snippets/generated-column/db/seeds.rb +1 -1
  54. data/examples/snippets/hints/application.rb +0 -4
  55. data/examples/snippets/hints/config/database.yml +1 -0
  56. data/examples/snippets/hints/db/seeds.rb +1 -1
  57. data/examples/snippets/interleaved-tables/application.rb +1 -5
  58. data/examples/snippets/interleaved-tables/config/database.yml +1 -0
  59. data/examples/snippets/interleaved-tables/db/seeds.rb +1 -1
  60. data/examples/snippets/interleaved-tables/models/album.rb +6 -2
  61. data/examples/snippets/interleaved-tables/models/track.rb +5 -1
  62. data/examples/snippets/interleaved-tables-before-7.1/application.rb +1 -5
  63. data/examples/snippets/interleaved-tables-before-7.1/config/database.yml +1 -0
  64. data/examples/snippets/interleaved-tables-before-7.1/db/seeds.rb +1 -1
  65. data/examples/snippets/migrations/application.rb +0 -4
  66. data/examples/snippets/migrations/config/database.yml +1 -0
  67. data/examples/snippets/mutations/application.rb +1 -5
  68. data/examples/snippets/mutations/config/database.yml +1 -0
  69. data/examples/snippets/mutations/db/seeds.rb +1 -1
  70. data/examples/snippets/optimistic-locking/application.rb +0 -4
  71. data/examples/snippets/optimistic-locking/config/database.yml +1 -0
  72. data/examples/snippets/optimistic-locking/db/seeds.rb +1 -1
  73. data/examples/snippets/partitioned-dml/application.rb +0 -4
  74. data/examples/snippets/partitioned-dml/config/database.yml +1 -0
  75. data/examples/snippets/partitioned-dml/db/seeds.rb +1 -1
  76. data/examples/snippets/query-logs/application.rb +15 -13
  77. data/examples/snippets/query-logs/config/database.yml +1 -0
  78. data/examples/snippets/query-logs/db/seeds.rb +1 -1
  79. data/examples/snippets/quickstart/application.rb +0 -4
  80. data/examples/snippets/quickstart/config/database.yml +1 -0
  81. data/examples/snippets/quickstart/db/seeds.rb +1 -1
  82. data/examples/snippets/read-only-transactions/application.rb +0 -4
  83. data/examples/snippets/read-only-transactions/config/database.yml +1 -0
  84. data/examples/snippets/read-only-transactions/db/seeds.rb +1 -1
  85. data/examples/snippets/read-write-transactions/application.rb +2 -6
  86. data/examples/snippets/read-write-transactions/config/database.yml +1 -0
  87. data/examples/snippets/read-write-transactions/db/seeds.rb +1 -1
  88. data/examples/snippets/stale-reads/application.rb +0 -4
  89. data/examples/snippets/stale-reads/config/database.yml +1 -0
  90. data/examples/snippets/stale-reads/db/seeds.rb +1 -1
  91. data/examples/snippets/tags/application.rb +0 -4
  92. data/examples/snippets/tags/config/database.yml +1 -0
  93. data/examples/snippets/tags/db/seeds.rb +1 -1
  94. data/examples/snippets/timestamp-data-type/application.rb +0 -4
  95. data/examples/snippets/timestamp-data-type/config/database.yml +1 -0
  96. data/lib/active_record/connection_adapters/spanner/column.rb +7 -3
  97. data/lib/active_record/connection_adapters/spanner/database_statements.rb +34 -22
  98. data/lib/active_record/connection_adapters/spanner/quoting.rb +2 -1
  99. data/lib/active_record/connection_adapters/spanner/schema_creation.rb +20 -11
  100. data/lib/active_record/connection_adapters/spanner/schema_definitions.rb +12 -2
  101. data/lib/active_record/connection_adapters/spanner/schema_statements.rb +22 -51
  102. data/lib/active_record/connection_adapters/spanner/type_metadata.rb +10 -8
  103. data/lib/active_record/connection_adapters/spanner_adapter.rb +42 -7
  104. data/lib/active_record/tasks/spanner_database_tasks.rb +4 -4
  105. data/lib/active_record/type/spanner/array.rb +4 -0
  106. data/lib/active_record/type/spanner/bytes.rb +10 -0
  107. data/lib/activerecord_spanner_adapter/base.rb +59 -32
  108. data/lib/activerecord_spanner_adapter/connection.rb +9 -5
  109. data/lib/activerecord_spanner_adapter/foreign_key.rb +9 -2
  110. data/lib/activerecord_spanner_adapter/index/column.rb +6 -1
  111. data/lib/activerecord_spanner_adapter/index.rb +10 -2
  112. data/lib/activerecord_spanner_adapter/information_schema.rb +5 -3
  113. data/lib/activerecord_spanner_adapter/primary_key.rb +2 -2
  114. data/lib/activerecord_spanner_adapter/table/column.rb +16 -4
  115. data/lib/activerecord_spanner_adapter/table.rb +8 -2
  116. data/lib/activerecord_spanner_adapter/transaction.rb +1 -1
  117. data/lib/activerecord_spanner_adapter/version.rb +1 -1
  118. data/lib/arel/visitors/spanner.rb +16 -11
  119. data/lib/spanner_client_ext.rb +4 -3
  120. metadata +23 -34
  121. data/examples/snippets/array-data-type/db/schema.rb +0 -31
  122. data/examples/snippets/bit-reversed-sequence/db/schema.rb +0 -31
  123. data/examples/snippets/bulk-insert/db/schema.rb +0 -31
  124. data/examples/snippets/commit-timestamp/db/schema.rb +0 -34
  125. data/examples/snippets/create-records/db/schema.rb +0 -31
  126. data/examples/snippets/date-data-type/db/schema.rb +0 -26
  127. data/examples/snippets/generated-column/db/schema.rb +0 -26
  128. data/examples/snippets/hints/db/schema.rb +0 -33
  129. data/examples/snippets/interleaved-tables/db/schema.rb +0 -39
  130. data/examples/snippets/interleaved-tables-before-7.1/db/schema.rb +0 -37
  131. data/examples/snippets/migrations/db/schema.rb +0 -38
  132. data/examples/snippets/mutations/db/schema.rb +0 -32
  133. data/examples/snippets/optimistic-locking/db/schema.rb +0 -34
  134. data/examples/snippets/partitioned-dml/db/schema.rb +0 -31
  135. data/examples/snippets/query-logs/db/schema.rb +0 -31
  136. data/examples/snippets/quickstart/db/schema.rb +0 -31
  137. data/examples/snippets/read-only-transactions/db/schema.rb +0 -31
  138. data/examples/snippets/read-write-transactions/db/schema.rb +0 -32
  139. data/examples/snippets/stale-reads/db/schema.rb +0 -31
  140. data/examples/snippets/tags/db/schema.rb +0 -31
  141. 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.rb"
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
- list_singers_albums_tracks
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
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
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
- # Rails 7.1 requires using query_constraints to define a composite foreign key.
15
- has_many :tracks, query_constraints: [:singerid, :albumid]
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
- belongs_to :album, query_constraints: [:singerid, :albumid]
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
- list_singers_albums_tracks
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
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
  require_relative "../models/track"
@@ -16,10 +16,6 @@ class Application
16
16
  tables.rows.each do |row|
17
17
  puts row[:TABLE_NAME]
18
18
  end
19
-
20
- puts ""
21
- puts "Press any key to end the application"
22
- STDIN.getch
23
19
  end
24
20
  end
25
21
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
 
@@ -38,10 +38,6 @@ class Application
38
38
 
39
39
  singer.reload
40
40
  puts "Reloaded singer data: #{singer.first_name} #{singer.last_name}, version: #{singer.lock_version}"
41
-
42
- puts ""
43
- puts "Press any key to end the application"
44
- STDIN.getch
45
41
  end
46
42
  end
47
43
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
 
@@ -38,10 +38,6 @@ class Application
38
38
  puts ""
39
39
  puts "Singers in the database: #{singer_count}"
40
40
  puts "Albums in the database: #{album_count}"
41
-
42
- puts ""
43
- puts "Press any key to end the application"
44
- STDIN.getch
45
41
  end
46
42
  end
47
43
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
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
- # This block manually enables Query Logs without a full Rails application.
30
+ # Enable query logs in a non-Rails application.
35
31
  # This should normally not be needed in your application.
36
- ActiveRecord::QueryLogs.taggings.merge!(
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
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
 
@@ -41,10 +41,6 @@ class Application
41
41
  Singer.where(last_name.matches("A%")).each do |s|
42
42
  puts "#{s.first_name} #{s.last_name}"
43
43
  end
44
-
45
- puts ""
46
- puts "Press any key to end the application"
47
- STDIN.getch
48
44
  end
49
45
  end
50
46
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
 
@@ -67,10 +67,6 @@ class Application
67
67
  puts "This error is expected."
68
68
  end
69
69
  end
70
-
71
- puts ""
72
- puts "Press any key to end the application"
73
- STDIN.getch
74
70
  end
75
71
  end
76
72
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
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 # rubocop:disable Metrics/AbcSize
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
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
7
+ require_relative "../../config/environment"
8
8
  require_relative "../models/singer"
9
9
  require_relative "../models/album"
10
10
 
@@ -53,10 +53,6 @@ class Application
53
53
  puts ""
54
54
  puts "Updated album title: #{album.title}"
55
55
  puts "Title somewhere during the last 10 seconds: #{album_max_staleness&.title}"
56
-
57
- puts ""
58
- puts "Press any key to end the application"
59
- STDIN.getch
60
56
  end
61
57
  end
62
58
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
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
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -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.rb"
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
 
@@ -6,3 +6,4 @@ development:
6
6
  database: testdb
7
7
  pool: 5
8
8
  timeout: 5000
9
+ schema_dump: false
@@ -10,16 +10,20 @@ module ActiveRecord
10
10
  module ConnectionAdapters
11
11
  module Spanner
12
12
  class Column < ConnectionAdapters::Column
13
- # rubocop:disable Style/MethodDefParentheses
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/MethodDefParentheses
17
+ # rubocop:enable Style/OptionalBooleanParameter
18
18
  super
19
19
  @primary_key = primary_key
20
20
  end
21
21
 
22
- def has_default? # rubocop:disable Naming/PredicateName
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, Metrics/LineLength
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.concat [binds, type_casted_binds(binds)] if log_statement_binds
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
- legacy_formatter_prefix = "/*request_tag:true,"
87
- sql_commenter_prefix = "/*request_tag='true',"
88
- if sql.start_with? legacy_formatter_prefix
89
- append_request_tag_from_query_logs_with_format sql, binds, legacy_formatter_prefix
90
- elsif sql.start_with? sql_commenter_prefix
91
- append_request_tag_from_query_logs_with_format sql, binds, sql_commenter_prefix
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 += "," + 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.enum_for(:each_with_index).map do |bind, i|
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.class == Symbol
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.class == TrueClass || bind.class == FalseClass
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.to_h
331
- params = binds.enum_for(:each_with_index).map do |bind, i|
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.class == Symbol
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.to_h
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.freeze \
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'\\]/.freeze
59
+ STR_ESCAPE_REGX = /[\n\r'\\]/
59
60
  STR_ESCAPE_VALUES = {
60
61
  "\n" => "\\n", "\r" => "\\r", "'" => "\\'", "\\" => "\\\\"
61
62
  }.freeze