activerecord-cockroachdb-adapter 7.0.3 → 7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 594ac59a7a678d5619ea771e3130a481481560adcc88032d7c17d61b6dabc279
4
- data.tar.gz: 0cd6ea6bd6a1fe808142a91e35a24d4e15a59b48f56e4dba37d8a25584dd7a8a
3
+ metadata.gz: 6c3f85e82470685a2ece6851d557bcaf03f5a77ce309d76062c3960ca17d1606
4
+ data.tar.gz: b6ab7bfb9d29feebf217b70b11ccf2f73e6fb0853138cc27f4556f07b6c36dac
5
5
  SHA512:
6
- metadata.gz: 56205a247976012b6a25691045a773ca9fefecc1b98bb47ee83fb85dffede72a8aed5bc605a332d00b31fb57f67ee1018b850d14638581454980a6b96d2e8865
7
- data.tar.gz: 92515e498cc8cedfe284cfe4cf9b3cb87eae72630aa5828e5983dfabe488ad214386561a0fb8072963b0796559209ee033cb010495d263d44eb1abf048afaa37
6
+ metadata.gz: 96fbb4c5a42c1ab3f2fe590f3c74012b883c818608c5b9d0525f30739f1d4d8733c95cfffd31a8a05350d6210d995f84d915727a494264d1cb1c217d10d200b1
7
+ data.tar.gz: 12ae86ab8f26eb074eabb60cd3f831eed44729d98f70bdc88d1c0d9c3d5cff5680ae7cf0a9643756395e6cfc1257cb7fc62ee5abab4c37c6f0fe45817fc619a0
data/.editorconfig ADDED
@@ -0,0 +1,7 @@
1
+ root = true
2
+
3
+ [*.rb]
4
+ indent_style = space
5
+ indent_size = 2
6
+ trim_trailing_whitespace = true
7
+ insert_final_newline = true
@@ -4,12 +4,9 @@
4
4
  name: Test
5
5
 
6
6
  on:
7
- # Triggers the workflow on push or pull request events.
8
7
  push:
9
- # This should disable running the workflow on tags, according to the
10
- # on.<push|pull_request>.<branches|tags> GitHub Actions docs.
11
- branches:
12
- - "*"
8
+ branches: [master]
9
+ # Triggers the workflow on pull request events.
13
10
  pull_request:
14
11
  types: [opened, reopened, synchronize]
15
12
 
@@ -18,27 +15,42 @@ on:
18
15
 
19
16
  # This allows a subsequently queued workflow run to interrupt previous runs.
20
17
  concurrency:
21
- group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
18
+ group: "${{ github.workflow }} @ ${{ github.ref }}"
22
19
  cancel-in-progress: true
23
20
 
24
21
  jobs:
22
+ # Since the name of the matrix job depends on the version, we define another job with a more stable name.
23
+ test_results:
24
+ if: ${{ always() }}
25
+ runs-on: ubuntu-latest
26
+ name: Test Results
27
+ needs: [test]
28
+ steps:
29
+ - run: |
30
+ result="${{ needs.test.result }}"
31
+ if [[ $result == "success" || $result == "skipped" ]]; then
32
+ exit 0
33
+ else
34
+ exit 1
35
+ fi
36
+
25
37
  test:
26
38
  runs-on: ubuntu-latest
27
39
  strategy:
28
40
  matrix:
29
- crdb: [v23.1.5]
30
- ruby: [ruby-head]
41
+ crdb: [v23.1.11]
42
+ ruby: [head]
31
43
  name: Test (crdb=${{ matrix.crdb }} ruby=${{ matrix.ruby }})
32
44
  steps:
33
45
  - name: Set Up Actions
34
- uses: actions/checkout@v3
46
+ uses: actions/checkout@v4
35
47
  - name: Install GEOS
36
48
  run: sudo apt-get install libgeos-dev
37
49
  - name: Set Up Ruby
38
50
  uses: ruby/setup-ruby@v1
39
51
  with:
40
- ruby-version: ${{ matrix.ruby }}
41
- bundler-cache: true
52
+ ruby-version: ${{ matrix.ruby }}
53
+ bundler-cache: true
42
54
  - name: Install and Start Cockroachdb
43
55
  run: |
44
56
  # Download CockroachDB
@@ -83,4 +95,4 @@ jobs:
83
95
  SET CLUSTER SETTING sql.defaults.experimental_temporary_tables.enabled = 'true';
84
96
  "
85
97
  - name: Test
86
- run: bundle exec rake test
98
+ run: bundle exec rake test TESTOPTS='--profile=3'
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Ongoing
4
4
 
5
+ - Add support for [AOST](cockroachlabs.com/docs/stable/as-of-system-time) queries ([#284](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/284))
6
+ - Dump schema name in foreign keys ([#289](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/289))
7
+
8
+ ## 7.1.0 - 2024-01-30
9
+
10
+ - Add support for Rails 7.1 ([#300](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/300)).
11
+
5
12
  ## 7.0.3 - 2023-08-23
6
13
 
7
14
  - Fix Multiple Database connections ([#283](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/)).
data/Gemfile CHANGED
@@ -10,6 +10,11 @@ module RailsTag
10
10
  def call
11
11
  req = gemspec_requirement
12
12
  "v" + all_activerecord_versions.find { req.satisfied_by?(_1) }.version
13
+ rescue => e
14
+ warn "Unable to determine Rails version. Using last used. Error: #{e.message}"
15
+ lockfile = File.expand_path("Gemfile.lock", __dir__)
16
+ File.foreach(lockfile, chomp: true).find { _1[/tag: (.*)$/] }
17
+ Regexp.last_match(1)
13
18
  end
14
19
 
15
20
  def gemspec_requirement
@@ -43,9 +48,13 @@ group :development, :test do
43
48
  # a specific rails codebase.
44
49
  gem "rails", github: "rails/rails", tag: RailsTag.call
45
50
 
51
+ # Needed for the test suite
52
+ gem "msgpack", ">= 1.7.0"
53
+
46
54
  gem "rake"
47
- gem "byebug"
55
+ gem "debug"
48
56
  gem "minitest-excludes", "~> 2.0.1"
57
+ gem "minitest-github_action_reporter", github: "BuonOmo/minitest-github_action_reporter", require: "minitest/github_action_reporter_plugin"
49
58
 
50
59
  # Gems used by the ActiveRecord test suite
51
60
  gem "bcrypt", "~> 3.1.18"
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.description = "Allows the use of CockroachDB as a backend for ActiveRecord and Rails apps."
15
15
  spec.homepage = "https://github.com/cockroachdb/activerecord-cockroachdb-adapter"
16
16
 
17
- spec.add_dependency "activerecord", "~> 7.0.3"
17
+ spec.add_dependency "activerecord", "~> 7.1.0"
18
18
  spec.add_dependency "pg", "~> 1.2"
19
19
  spec.add_dependency "rgeo-activerecord", "~> 7.0.0"
20
20
 
data/bin/console CHANGED
@@ -12,39 +12,23 @@ require "active_record"
12
12
  # structure_load(Post.connection_db_config, "awesome-file.sql")
13
13
  require "active_record/connection_adapters/cockroachdb/database_tasks"
14
14
 
15
- begin
16
- retried = false
17
- ActiveRecord::Base.establish_connection(
18
- #Alternative version: "cockroachdb://root@localhost:26257/ar_crdb_console"
19
- adapter: "cockroachdb",
20
- host: "localhost",
21
- port: 26257,
22
- user: "root",
23
- database: "ar_crdb_console"
24
- )
25
- ActiveRecord::Base.connection
26
- rescue ActiveRecord::NoDatabaseError
27
- raise if retried
28
- system("cockroach sql --insecure --host=localhost:26257 --execute='create database ar_crdb_console'",
29
- exception: true)
30
- retried = true
31
- retry
32
- end
33
-
34
- class Post < ActiveRecord::Base
35
- end
36
-
37
- unless Post.table_exists?
38
- migration = Class.new(ActiveRecord::Migration::Current) do
39
- def up
40
- create_table("posts") do |t|
41
- t.string :title
42
- t.text :body
43
- end
44
- end
45
- end
46
- migration.migrate(:up)
47
- end
15
+ schema_kind = ENV.fetch("SCHEMA_KIND", "default")
16
+
17
+ system("cockroach sql --insecure --host=localhost:26257 --execute='drop database if exists ar_crdb_console'",
18
+ exception: true)
19
+ system("cockroach sql --insecure --host=localhost:26257 --execute='create database ar_crdb_console'",
20
+ exception: true)
21
+
22
+ ActiveRecord::Base.establish_connection(
23
+ #Alternative version: "cockroachdb://root@localhost:26257/ar_crdb_console"
24
+ adapter: "cockroachdb",
25
+ host: "localhost",
26
+ port: 26257,
27
+ user: "root",
28
+ database: "ar_crdb_console"
29
+ )
30
+
31
+ load "#{__dir__}/console_schemas/#{schema_kind}.rb"
48
32
 
49
33
  require "irb"
50
34
  IRB.start(__FILE__)
@@ -0,0 +1,9 @@
1
+ class Post < ActiveRecord::Base
2
+ end
3
+
4
+ ActiveRecord::Schema.define do
5
+ create_table("posts") do |t|
6
+ t.string :title
7
+ t.text :body
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ class Post < ActiveRecord::Base
2
+ self.table_name = "bar.posts"
3
+ end
4
+
5
+ class Comment < ActiveRecord::Base
6
+ self.table_name = "foo.comments"
7
+ end
8
+
9
+ ActiveRecord::Schema.define do
10
+ create_schema("foo")
11
+ create_schema("bar")
12
+ create_table("bar.posts") do |t|
13
+ t.string :title
14
+ t.text :body
15
+ end
16
+
17
+ create_table("foo.comments") do |t|
18
+ t.integer :post_id
19
+ t.text :body
20
+ end
21
+
22
+ add_foreign_key "foo.comments", "bar.posts", column: "post_id"
23
+ end
@@ -9,6 +9,7 @@ pid_file="$root_dir/tmp/cockroach.pid"
9
9
  log_file="$root_dir/tmp/cockroachdb.log"
10
10
 
11
11
  mkdir -p "$root_dir/tmp"
12
+ [[ -f "$pid_file" ]] && kill -9 $(cat "$pid_file")
12
13
  rm -f "$pid_file"
13
14
 
14
15
  if ! (( ${+commands[cockroach]} )); then
@@ -20,8 +21,6 @@ cockroach start-single-node \
20
21
  --insecure --store=type=mem,size=0.25 --advertise-addr=localhost --pid-file "$pid_file" \
21
22
  &> "$log_file" &
22
23
 
23
- cockroach_pid=$!
24
-
25
24
  until [[ -f "$pid_file" ]]; do
26
25
  sleep 1
27
26
  done
@@ -41,8 +40,9 @@ ALTER DATABASE system CONFIGURE ZONE USING "gc.ttlseconds" = 600;
41
40
 
42
41
  CREATE DATABASE activerecord_unittest;
43
42
  CREATE DATABASE activerecord_unittest2;
44
- SQL
45
43
 
46
- tail -f "$log_file"
44
+ SET CLUSTER SETTING sql.defaults.experimental_alter_column_type.enabled = 'true';
45
+ SET CLUSTER SETTING sql.defaults.experimental_temporary_tables.enabled = 'true';
46
+ SQL
47
47
 
48
- trap "kill $cockroach_pid" EXIT
48
+ echo "CockroachDB started. PID: $(cat "$pid_file"). log: $log_file"
data/build/Dockerfile CHANGED
@@ -1,7 +1,7 @@
1
1
  # This Dockerfile extends the Examples-ORM testing image in order to
2
2
  # install specific dependencies required for ActiveRecord tests.
3
3
 
4
- FROM cockroachdb/example-orms-builder:20200413-1918
4
+ FROM us-east1-docker.pkg.dev/crl-ci-images/cockroach/example-orms-builder:20200413-1918
5
5
 
6
6
  # Native dependencies for libxml-ruby and sqlite3.
7
7
  RUN apt-get --allow-releaseinfo-change update -y && apt-get install -y \
@@ -22,6 +22,14 @@ module Arel # :nodoc:
22
22
  module Visitors # :nodoc:
23
23
  class CockroachDB < PostgreSQL # :nodoc:
24
24
  include RGeo::ActiveRecord::SpatialToSql
25
+
26
+ def visit_Arel_Nodes_JoinSource(o, collector)
27
+ super
28
+ if o.aost
29
+ collector << " AS OF SYSTEM TIME '#{o.aost.iso8601}'"
30
+ end
31
+ collector
32
+ end
25
33
  end
26
34
  end
27
35
  end
@@ -1,11 +1,11 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module CockroachDB
4
- class Column < PostgreSQLColumn
4
+ class Column < PostgreSQL::Column
5
5
  # most functions taken from activerecord-postgis-adapter spatial_column
6
6
  # https://github.com/rgeo/activerecord-postgis-adapter/blob/master/lib/active_record/connection_adapters/postgis/spatial_column.rb
7
7
  def initialize(name, default, sql_type_metadata = nil, null = true,
8
- default_function = nil, collation: nil, comment: nil,
8
+ default_function = nil, collation: nil, comment: nil, identity: nil,
9
9
  serial: nil, spatial: nil, generated: nil, hidden: nil)
10
10
  @sql_type_metadata = sql_type_metadata
11
11
  @geographic = !!(sql_type_metadata.sql_type =~ /geography\(/i)
@@ -30,7 +30,7 @@ module ActiveRecord
30
30
  build_from_sql_type(sql_type_metadata.sql_type)
31
31
  end
32
32
  super(name, default, sql_type_metadata, null, default_function,
33
- collation: collation, comment: comment, serial: serial, generated: generated)
33
+ collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
34
34
  if spatial? && @srid
35
35
  @limit = { srid: @srid, type: to_type_name(geometric_type) }
36
36
  @limit[:has_z] = true if @has_z
@@ -53,10 +53,6 @@ module ActiveRecord
53
53
  spatial? ? @limit : super
54
54
  end
55
55
 
56
- def virtual?
57
- @generated.present?
58
- end
59
-
60
56
  def hidden?
61
57
  @hidden
62
58
  end
@@ -45,6 +45,14 @@ module ActiveRecord
45
45
  def st_polygon(name, options = {})
46
46
  column(name, :st_polygon, **options)
47
47
  end
48
+
49
+ private
50
+
51
+ def valid_column_definition_options
52
+ spatial = [:srid, :has_z, :has_m, :geographic, :spatial_type]
53
+ crdb = [:hidden]
54
+ super + spatial + crdb
55
+ end
48
56
  end
49
57
  end
50
58
 
@@ -2,21 +2,6 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module CockroachDB
4
4
  module DatabaseStatements
5
- # Since CockroachDB will run all transactions with serializable isolation,
6
- # READ UNCOMMITTED, READ COMMITTED, and REPEATABLE READ are all aliases
7
- # for SERIALIZABLE. This lets the adapter support all isolation levels,
8
- # but READ UNCOMMITTED has been removed from this list because the
9
- # ActiveRecord transaction isolation test fails for READ UNCOMMITTED.
10
- # See https://www.cockroachlabs.com/docs/v19.2/transactions.html#isolation-levels
11
- def transaction_isolation_levels
12
- {
13
- read_committed: "READ COMMITTED",
14
- repeatable_read: "REPEATABLE READ",
15
- serializable: "SERIALIZABLE",
16
- read_uncommitted: "READ UNCOMMITTED"
17
- }
18
- end
19
-
20
5
  # Overridden to avoid using transactions for schema creation.
21
6
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
22
7
  fixture_inserts = build_fixture_statements(fixture_set)
@@ -29,74 +14,6 @@ module ActiveRecord
29
14
  end
30
15
  end
31
16
  end
32
-
33
- private
34
- def execute_batch(statements, name = nil)
35
- statements.each do |statement|
36
- execute(statement, name)
37
- end
38
- end
39
-
40
- DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
41
- private_constant :DEFAULT_INSERT_VALUE
42
-
43
- def default_insert_value(column)
44
- DEFAULT_INSERT_VALUE
45
- end
46
-
47
- def build_fixture_sql(fixtures, table_name)
48
- columns = schema_cache.columns_hash(table_name)
49
-
50
- values_list = fixtures.map do |fixture|
51
- fixture = fixture.stringify_keys
52
-
53
- unknown_columns = fixture.keys - columns.keys
54
- if unknown_columns.any?
55
- raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
56
- end
57
-
58
- columns.map do |name, column|
59
- if fixture.key?(name)
60
- type = lookup_cast_type_from_column(column)
61
- with_yaml_fallback(type.serialize(fixture[name]))
62
- else
63
- default_insert_value(column)
64
- end
65
- end
66
- end
67
-
68
- table = Arel::Table.new(table_name)
69
- manager = Arel::InsertManager.new
70
- manager.into(table)
71
-
72
- if values_list.size == 1
73
- values = values_list.shift
74
- new_values = []
75
- columns.each_key.with_index { |column, i|
76
- unless values[i].equal?(DEFAULT_INSERT_VALUE)
77
- new_values << values[i]
78
- manager.columns << table[column]
79
- end
80
- }
81
- values_list << new_values
82
- else
83
- columns.each_key { |column| manager.columns << table[column] }
84
- end
85
-
86
- manager.values = manager.create_values_list(values_list)
87
- manager.to_sql
88
- end
89
-
90
- def build_fixture_statements(fixture_set)
91
- fixture_set.map do |table_name, fixtures|
92
- next if fixtures.empty?
93
- build_fixture_sql(fixtures, table_name)
94
- end.compact
95
- end
96
-
97
- def with_multi_statements
98
- yield
99
- end
100
17
  end
101
18
  end
102
19
  end
@@ -10,37 +10,44 @@ module ActiveRecord
10
10
  "https://github.com/cockroachdb/activerecord-cockroachdb-adapter/issues/new"
11
11
  end
12
12
 
13
- case ActiveRecord.dump_schemas
14
- when :all, String
15
- raise "Custom schemas are not supported in CockroachDB. " \
16
- "See https://github.com/cockroachdb/cockroach/issues/26443."
17
- when :schema_search_path
18
- if configuration_hash[:schema_search_path]
19
- raise "Custom schemas are not supported in CockroachDB. " \
20
- "See https://github.com/cockroachdb/cockroach/issues/26443."
13
+ # "See https://github.com/cockroachdb/cockroach/issues/26443."
14
+ search_path =
15
+ case ActiveRecord.dump_schemas
16
+ when :schema_search_path
17
+ configuration_hash[:schema_search_path]
18
+ when :all
19
+ nil
20
+ when String
21
+ ActiveRecord.dump_schemas
21
22
  end
22
- end
23
23
 
24
24
  conn = ActiveRecord::Base.connection
25
- File.open(filename, "w") do |file|
26
- %w(SCHEMAS TYPES).each do |object_kind|
27
- ActiveRecord::Base.connection.execute("SHOW CREATE ALL #{object_kind}").each_row { file.puts _1 }
28
- end
25
+ begin
26
+ old_search_path = conn.schema_search_path
27
+ conn.schema_search_path = search_path
28
+ File.open(filename, "w") do |file|
29
+ %w(SCHEMAS TYPES).each do |object_kind|
30
+ ActiveRecord::Base.connection.execute("SHOW CREATE ALL #{object_kind}").each_row { file.puts _1 }
31
+ end
29
32
 
30
- ignore_tables = ActiveRecord::SchemaDumper.ignore_tables.to_set
33
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables.to_set
31
34
 
32
- conn.execute("SHOW CREATE ALL TABLES").each_row do |(sql)|
33
- if sql.start_with?("CREATE")
34
- table_name = sql[/CREATE TABLE (?:.*?\.)?\"?(.*?)[\" ]/, 1]
35
- next if ignore_tables.member?(table_name)
36
- elsif sql.start_with?("ALTER")
37
- table_name = sql[/ALTER TABLE (?:.*?\.)?\"?(.*?)[\" ]/, 1]
38
- ref_table_name = sql[/REFERENCES (?:.*?\.)?\"?(.*?)[\" ]/, 1]
39
- next if ignore_tables.member?(table_name) || ignore_tables.member?(ref_table_name)
40
- end
35
+ conn.execute("SHOW CREATE ALL TABLES").each_row do |(sql)|
36
+ if sql.start_with?("CREATE")
37
+ table_name = sql[/CREATE TABLE (?:.*?\.)?\"?(.*?)[\" ]/, 1]
38
+ next if ignore_tables.member?(table_name)
39
+ elsif sql.start_with?("ALTER")
40
+ table_name = sql[/ALTER TABLE (?:.*?\.)?\"?(.*?)[\" ]/, 1]
41
+ ref_table_name = sql[/REFERENCES (?:.*?\.)?\"?(.*?)[\" ]/, 1]
42
+ next if ignore_tables.member?(table_name) || ignore_tables.member?(ref_table_name)
43
+ end
41
44
 
42
- file.puts sql
45
+ file.puts sql
46
+ end
47
+ file.puts "SET seach_path TO #{conn.schema_search_path};\n\n"
43
48
  end
49
+ ensure
50
+ conn.schema_search_path = old_search_path
44
51
  end
45
52
  end
46
53
 
@@ -11,6 +11,14 @@ module ActiveRecord
11
11
  module ConnectionAdapters
12
12
  module CockroachDB
13
13
  module ReferentialIntegrity
14
+ # CockroachDB will raise a `PG::ForeignKeyViolation` when re-enabling
15
+ # referential integrity (e.g: adding a foreign key with invalid data
16
+ # raises).
17
+ # So foreign keys should always be valid for that matter.
18
+ def check_all_foreign_keys_valid!
19
+ true
20
+ end
21
+
14
22
  def disable_referential_integrity
15
23
  foreign_keys = tables.map { |table| foreign_keys(table) }.flatten
16
24
 
@@ -31,16 +39,12 @@ module ActiveRecord
31
39
 
32
40
  begin
33
41
  foreign_keys.each do |foreign_key|
34
- begin
35
- add_foreign_key(foreign_key.from_table, foreign_key.to_table, **foreign_key.options)
36
- rescue ActiveRecord::StatementInvalid => error
37
- if error.cause.class == PG::DuplicateObject
38
- # This error is safe to ignore because the yielded caller
39
- # already re-added the foreign key constraint.
40
- else
41
- raise error
42
- end
43
- end
42
+ # Avoid having PG:DuplicateObject error if a test is ran in transaction.
43
+ # TODO: verify that there is no cache issue related to running this (e.g: fk
44
+ # still in cache but not in db)
45
+ next if foreign_key_exists?(foreign_key.from_table, name: foreign_key.options[:name])
46
+
47
+ add_foreign_key(foreign_key.from_table, foreign_key.to_table, **foreign_key.options)
44
48
  end
45
49
  ensure
46
50
  ActiveRecord::Base.table_name_prefix = old_prefix
@@ -36,16 +36,25 @@ module ActiveRecord
36
36
  # Modified version of the postgresql foreign_keys method.
37
37
  # Replaces t2.oid::regclass::text with t2.relname since this is
38
38
  # more efficient in CockroachDB.
39
+ # Also, CockroachDB does not append the schema name in relname,
40
+ # so we append it manually.
39
41
  def foreign_keys(table_name)
40
42
  scope = quoted_scope(table_name)
41
43
  fk_info = exec_query(<<~SQL, "SCHEMA")
42
- SELECT t2.relname AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid
44
+ SELECT CASE
45
+ WHEN n2.nspname = current_schema()
46
+ THEN ''
47
+ ELSE n2.nspname || '.'
48
+ END || t2.relname AS to_table,
49
+ a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred,
50
+ c.conkey, c.confkey, c.conrelid, c.confrelid
43
51
  FROM pg_constraint c
44
52
  JOIN pg_class t1 ON c.conrelid = t1.oid
45
53
  JOIN pg_class t2 ON c.confrelid = t2.oid
46
54
  JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
47
55
  JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
48
56
  JOIN pg_namespace t3 ON c.connamespace = t3.oid
57
+ JOIN pg_namespace n2 ON t2.relnamespace = n2.oid
49
58
  WHERE c.contype = 'f'
50
59
  AND t1.relname = #{scope[:name]}
51
60
  AND t3.nspname = #{scope[:schema]}
@@ -53,17 +62,31 @@ module ActiveRecord
53
62
  SQL
54
63
 
55
64
  fk_info.map do |row|
65
+ to_table = PostgreSQL::Utils.unquote_identifier(row["to_table"])
66
+ conkey = row["conkey"].scan(/\d+/).map(&:to_i)
67
+ confkey = row["confkey"].scan(/\d+/).map(&:to_i)
68
+
69
+ if conkey.size > 1
70
+ column = column_names_from_column_numbers(row["conrelid"], conkey)
71
+ primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
72
+ else
73
+ column = PostgreSQL::Utils.unquote_identifier(row["column"])
74
+ primary_key = row["primary_key"]
75
+ end
76
+
56
77
  options = {
57
- column: row["column"],
78
+ column: column,
58
79
  name: row["name"],
59
- primary_key: row["primary_key"]
80
+ primary_key: primary_key
60
81
  }
61
-
62
82
  options[:on_delete] = extract_foreign_key_action(row["on_delete"])
63
83
  options[:on_update] = extract_foreign_key_action(row["on_update"])
84
+ options[:deferrable] = extract_constraint_deferrable(row["deferrable"], row["deferred"])
85
+
64
86
  options[:validate] = row["valid"]
87
+ to_table = PostgreSQL::Utils.unquote_identifier(row["to_table"])
65
88
 
66
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
89
+ ForeignKeyDefinition.new(table_name, to_table, options)
67
90
  end
68
91
  end
69
92
 
@@ -76,16 +99,20 @@ module ActiveRecord
76
99
 
77
100
  # override
78
101
  # https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb#L624
79
- def new_column_from_field(table_name, field)
80
- column_name, type, default, notnull, oid, fmod, collation, comment, generated, hidden = field
102
+ def new_column_from_field(table_name, field, _definition)
103
+ column_name, type, default, notnull, oid, fmod, collation, comment, identity, attgenerated, hidden = field
81
104
  type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
82
105
  default_value = extract_value_from_default(default)
83
- default_function = extract_default_function(default_value, default)
84
106
 
85
- serial =
86
- if (match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/))
87
- sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
88
- end
107
+ if attgenerated.present?
108
+ default_function = default
109
+ else
110
+ default_function = extract_default_function(default_value, default)
111
+ end
112
+
113
+ if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
114
+ serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
115
+ end
89
116
 
90
117
  # {:dimension=>2, :has_m=>false, :has_z=>false, :name=>"latlon", :srid=>0, :type=>"GEOMETRY"}
91
118
  spatial = spatial_column_info(table_name).get(column_name, type_metadata.sql_type)
@@ -99,8 +126,9 @@ module ActiveRecord
99
126
  collation: collation,
100
127
  comment: comment.presence,
101
128
  serial: serial,
129
+ identity: identity.presence,
102
130
  spatial: spatial,
103
- generated: generated,
131
+ generated: attgenerated,
104
132
  hidden: hidden
105
133
  )
106
134
  end
@@ -1,15 +1,16 @@
1
1
  module ActiveRecord
2
2
  module Type
3
- class << self
3
+ module CRDBExt
4
4
  # Return :postgresql instead of :cockroachdb for current_adapter_name so
5
5
  # we can continue using the ActiveRecord::Types defined in
6
6
  # PostgreSQLAdapter.
7
7
  def adapter_name_from(model)
8
- name = model.connection_db_config.adapter.to_sym
8
+ name = super
9
9
  return :postgresql if name == :cockroachdb
10
10
 
11
11
  name
12
12
  end
13
13
  end
14
+ singleton_class.prepend CRDBExt
14
15
  end
15
16
  end
@@ -1,5 +1,6 @@
1
1
  require "rgeo/active_record"
2
2
 
3
+ require_relative "../../arel/nodes/join_source_ext"
3
4
  require "active_record/connection_adapters/postgresql_adapter"
4
5
  require "active_record/connection_adapters/cockroachdb/attribute_methods"
5
6
  require "active_record/connection_adapters/cockroachdb/column_methods"
@@ -160,7 +161,7 @@ module ActiveRecord
160
161
  end
161
162
 
162
163
  def supports_bulk_alter?
163
- false
164
+ true
164
165
  end
165
166
 
166
167
  def supports_json?
@@ -181,7 +182,15 @@ module ActiveRecord
181
182
  end
182
183
 
183
184
  def supports_partial_index?
184
- @crdb_version >= 2020
185
+ true
186
+ end
187
+
188
+ def supports_index_include?
189
+ false
190
+ end
191
+
192
+ def supports_exclusion_constraints?
193
+ false
185
194
  end
186
195
 
187
196
  def supports_expression_index?
@@ -196,7 +205,7 @@ module ActiveRecord
196
205
  end
197
206
 
198
207
  def supports_comments?
199
- @crdb_version >= 2010
208
+ true
200
209
  end
201
210
 
202
211
  def supports_comments_in_create?
@@ -208,11 +217,11 @@ module ActiveRecord
208
217
  end
209
218
 
210
219
  def supports_virtual_columns?
211
- @crdb_version >= 2110
220
+ true
212
221
  end
213
222
 
214
223
  def supports_string_to_array_coercion?
215
- @crdb_version >= 2020
224
+ true
216
225
  end
217
226
 
218
227
  def supports_partitioned_indexes?
@@ -238,62 +247,30 @@ module ActiveRecord
238
247
  alias index_name_length max_identifier_length
239
248
  alias table_alias_length max_identifier_length
240
249
 
241
- def initialize(connection, logger, conn_params, config)
242
- super(connection, logger, conn_params, config)
243
-
244
- # crdb_version is the version of the binary running on the node. We
245
- # really want to use `SHOW CLUSTER SETTING version` to get the cluster
246
- # version, but that is only available to admins. Instead, we can use
247
- # crdb_internal.is_at_least_version, but that's only available in 22.1.
248
- crdb_version_string = query_value("SHOW crdb_version")
249
- if crdb_version_string.include? "v22.1"
250
- version_num = query_value(<<~SQL, "VERSION")
251
- SELECT
252
- CASE
253
- WHEN crdb_internal.is_at_least_version('22.2') THEN 2220
254
- WHEN crdb_internal.is_at_least_version('22.1') THEN 2210
255
- ELSE 2120
256
- END;
257
- SQL
258
- else
259
- # This branch can be removed once the dialect stops supporting v21.2
260
- # and earlier.
261
- if crdb_version_string.include? "v1."
262
- version_num = 1
263
- elsif crdb_version_string.include? "v2."
264
- version_num 2
265
- elsif crdb_version_string.include? "v19.1."
266
- version_num = 1910
267
- elsif crdb_version_string.include? "v19.2."
268
- version_num = 1920
269
- elsif crdb_version_string.include? "v20.1."
270
- version_num = 2010
271
- elsif crdb_version_string.include? "v20.2."
272
- version_num = 2020
273
- elsif crdb_version_string.include? "v21.1."
274
- version_num = 2110
275
- else
276
- version_num = 2120
277
- end
278
- end
279
- @crdb_version = version_num.to_i
280
-
281
- # NOTE: this is normally in configure_connection, but that is run
282
- # before crdb_version is determined. Once all supported versions
283
- # of CockroachDB support SET intervalstyle it can safely be moved
284
- # back.
285
- # Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
286
- if @crdb_version >= 2120
287
- begin
288
- execute("SET intervalstyle_enabled = true", "SCHEMA")
289
- execute("SET intervalstyle = iso_8601", "SCHEMA")
290
- rescue
291
- # Ignore any error. This can happen with a cluster that has
292
- # not yet finalized the v21.2 upgrade. v21.2 does not have
293
- # a way to tell if the upgrade was finalized (see comment above).
294
- end
295
- end
296
- end
250
+ # NOTE: This commented bit of code allows to have access to crdb version,
251
+ # which can be useful for feature detection. However, we currently don't
252
+ # need, hence we avoid the extra queries.
253
+ #
254
+ # def initialize(connection, logger, conn_params, config)
255
+ # super(connection, logger, conn_params, config)
256
+
257
+ # # crdb_version is the version of the binary running on the node. We
258
+ # # really want to use `SHOW CLUSTER SETTING version` to get the cluster
259
+ # # version, but that is only available to admins. Instead, we can use
260
+ # # crdb_internal.is_at_least_version, but that's only available in 22.1.
261
+ # crdb_version_string = query_value("SHOW crdb_version")
262
+ # if crdb_version_string.include? "v22.1"
263
+ # version_num = query_value(<<~SQL, "VERSION")
264
+ # SELECT
265
+ # CASE
266
+ # WHEN crdb_internal.is_at_least_version('22.2') THEN 2220
267
+ # WHEN crdb_internal.is_at_least_version('22.1') THEN 2210
268
+ # ELSE 2120
269
+ # END;
270
+ # SQL
271
+ # end
272
+ # @crdb_version = version_num.to_i
273
+ # end
297
274
 
298
275
  def self.database_exists?(config)
299
276
  !!ActiveRecord::Base.cockroachdb_connection(config)
@@ -306,12 +283,12 @@ module ActiveRecord
306
283
  # (DO $$) that CockroachDB does not support.
307
284
  #
308
285
  # Given a name and an array of values, creates an enum type.
309
- def create_enum(name, values)
310
- sql_values = values.map { |s| "'#{s}'" }.join(", ")
286
+ def create_enum(name, values, **options)
287
+ sql_values = values.map { |s| quote(s) }.join(", ")
311
288
  query = <<~SQL
312
- CREATE TYPE IF NOT EXISTS \"#{name}\" AS ENUM (#{sql_values});
289
+ CREATE TYPE IF NOT EXISTS #{quote_table_name(name)} AS ENUM (#{sql_values});
313
290
  SQL
314
- exec_query(query)
291
+ internal_exec_query(query).tap { reload_type_map }
315
292
  end
316
293
 
317
294
  class << self
@@ -369,56 +346,6 @@ module ActiveRecord
369
346
 
370
347
  private
371
348
 
372
- # Configures the encoding, verbosity, schema search path, and time zone of the connection.
373
- # This is called by #connect and should not be called manually.
374
- #
375
- # NOTE(joey): This was cradled from postgresql_adapter.rb. This
376
- # was due to needing to override configuration statements.
377
- def configure_connection
378
- if @config[:encoding]
379
- @connection.set_client_encoding(@config[:encoding])
380
- end
381
- self.client_min_messages = @config[:min_messages] || "warning"
382
- self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
383
-
384
- # Use standard-conforming strings so we don't have to do the E'...' dance.
385
- set_standard_conforming_strings
386
-
387
- variables = @config.fetch(:variables, {}).stringify_keys
388
-
389
- # If using Active Record's time zone support configure the connection to return
390
- # TIMESTAMP WITH ZONE types in UTC.
391
- unless variables["timezone"]
392
- if ActiveRecord.default_timezone == :utc
393
- variables["timezone"] = "UTC"
394
- elsif @local_tz
395
- variables["timezone"] = @local_tz
396
- end
397
- end
398
-
399
- # NOTE(joey): This is a workaround as CockroachDB 1.1.x
400
- # supports SET TIME ZONE <...> and SET "time zone" = <...> but
401
- # not SET timezone = <...>.
402
- if variables.key?("timezone")
403
- tz = variables.delete("timezone")
404
- execute("SET TIME ZONE #{quote(tz)}", "SCHEMA")
405
- end
406
-
407
- # SET statements from :variables config hash
408
- # https://www.postgresql.org/docs/current/static/sql-set.html
409
- variables.map do |k, v|
410
- if v == ":default" || v == :default
411
- # Sets the value to the global or compile default
412
-
413
- # NOTE(joey): I am not sure if simply commenting this out
414
- # is technically correct.
415
- # execute("SET #{k} = DEFAULT", "SCHEMA")
416
- elsif !v.nil?
417
- execute("SET SESSION #{k} = #{quote(v)}", "SCHEMA")
418
- end
419
- end
420
- end
421
-
422
349
  # Override extract_value_from_default because the upstream definition
423
350
  # doesn't handle the variations in CockroachDB's behavior.
424
351
  def extract_value_from_default(default)
@@ -502,7 +429,8 @@ module ActiveRecord
502
429
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
503
430
  pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
504
431
  c.collname, NULL AS comment,
505
- #{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated,
432
+ attidentity,
433
+ attgenerated,
506
434
  NULL as is_hidden
507
435
  FROM pg_attribute a
508
436
  LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
@@ -517,26 +445,31 @@ module ActiveRecord
517
445
 
518
446
  # Use regex comparison because if a type is an array it will
519
447
  # have [] appended to the end of it.
520
- target_types = [
521
- /geometry/,
522
- /geography/,
523
- /interval/,
524
- /numeric/
525
- ]
526
-
527
- re = Regexp.union(target_types)
448
+ re = /\A(?:geometry|geography|interval|numeric)/
449
+
450
+ # 0: attname
451
+ # 1: type
452
+ # 2: default
453
+ # 3: attnotnull
454
+ # 4: atttypid
455
+ # 5: atttypmod
456
+ # 6: collname
457
+ # 7: comment
458
+ # 8: attidentity
459
+ # 9: attgenerated
460
+ # 10: is_hidden
528
461
  fields.map do |field|
529
462
  dtype = field[1]
530
463
  field[1] = crdb_fields[field[0]][2].downcase if re.match(dtype)
531
464
  field[7] = crdb_fields[field[0]][1]&.gsub!(/^\'|\'?$/, '')
532
- field[9] = true if crdb_fields[field[0]][3]
465
+ field[10] = true if crdb_fields[field[0]][3]
533
466
  field
534
467
  end
535
468
  fields.delete_if do |field|
536
469
  # Don't include rowid column if it is hidden and the primary key
537
470
  # is not defined (meaning CRDB implicitly created it).
538
471
  if field[0] == CockroachDBAdapter::DEFAULT_PRIMARY_KEY
539
- field[9] && !primary_key(table_name)
472
+ field[10] && !primary_key(table_name)
540
473
  else
541
474
  false # Keep this entry.
542
475
  end
@@ -549,11 +482,14 @@ module ActiveRecord
549
482
  # precision, and scale information in the type.
550
483
  # Ex. geometry -> geometry(point, 4326)
551
484
  def crdb_column_definitions(table_name)
485
+ table_name = PostgreSQL::Utils.extract_schema_qualified_name(table_name)
486
+ table = table_name.identifier
487
+ with_schema = " AND c.table_schema = #{quote(table_name.schema)}" if table_name.schema
552
488
  fields = \
553
489
  query(<<~SQL, "SCHEMA")
554
490
  SELECT c.column_name, c.column_comment, c.crdb_sql_type, c.is_hidden::BOOLEAN
555
- FROM information_schema.columns c
556
- WHERE c.table_name = #{quote(table_name)}
491
+ FROM information_schema.columns c
492
+ WHERE c.table_name = #{quote(table)}#{with_schema}
557
493
  SQL
558
494
 
559
495
  fields.reduce({}) do |a, e|
@@ -594,21 +530,10 @@ module ActiveRecord
594
530
  def load_additional_types(oids = nil)
595
531
  if @config[:use_follower_reads_for_type_introspection]
596
532
  initializer = OID::TypeMapInitializer.new(type_map)
597
-
598
- query = <<~SQL
599
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
600
- FROM pg_type as t
601
- LEFT JOIN pg_range as r ON oid = rngtypid AS OF SYSTEM TIME '-10s'
602
- SQL
603
-
604
- if oids
605
- query += "WHERE t.oid IN (%s)" % oids.join(", ")
606
- else
607
- query += initializer.query_conditions_for_initial_load
608
- end
609
-
610
- execute_and_clear(query, "SCHEMA", []) do |records|
611
- initializer.run(records)
533
+ load_types_queries_with_aost(initializer, oids) do |query|
534
+ execute_and_clear(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false) do |records|
535
+ initializer.run(records)
536
+ end
612
537
  end
613
538
  else
614
539
  super
@@ -619,6 +544,21 @@ module ActiveRecord
619
544
  super
620
545
  end
621
546
 
547
+ def load_types_queries_with_aost(initializer, oids)
548
+ query = <<~SQL
549
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
550
+ FROM pg_type as t
551
+ LEFT JOIN pg_range as r ON oid = rngtypid AS OF SYSTEM TIME '-10s'
552
+ SQL
553
+ if oids
554
+ yield query + "WHERE t.oid IN (%s)" % oids.join(", ")
555
+ else
556
+ yield query + initializer.query_conditions_for_known_type_names
557
+ yield query + initializer.query_conditions_for_known_type_types
558
+ yield query + initializer.query_conditions_for_array_types
559
+ end
560
+ end
561
+
622
562
  # override
623
563
  # This method maps data types to their proper decoder.
624
564
  #
@@ -649,15 +589,13 @@ module ActiveRecord
649
589
  WHERE t.typname IN (%s)
650
590
  SQL
651
591
 
652
- coders = execute_and_clear(query, "SCHEMA", []) do |result|
653
- result
654
- .map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
655
- .compact
592
+ coders = execute_and_clear(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false) do |result|
593
+ result.filter_map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
656
594
  end
657
595
 
658
596
  map = PG::TypeMapByOid.new
659
597
  coders.each { |coder| map.add_coder(coder) }
660
- @connection.type_map_for_results = map
598
+ @raw_connection.type_map_for_results = map
661
599
 
662
600
  @type_map_for_results = PG::TypeMapByOid.new
663
601
  @type_map_for_results.default_type_map = map
@@ -3,6 +3,23 @@
3
3
  module ActiveRecord
4
4
  class Relation
5
5
  module QueryMethodsExt
6
+ def aost!(time) # :nodoc:
7
+ unless time.nil? || time.is_a?(Time)
8
+ raise ArgumentError, "Unsupported argument type: #{time} (#{time.class})"
9
+ end
10
+
11
+ @aost = time
12
+ self
13
+ end
14
+
15
+ # Set system time for the current query. Using
16
+ # `.aost(nil)` resets.
17
+ #
18
+ # See cockroachlabs.com/docs/stable/as-of-system-time
19
+ def aost(time)
20
+ spawn.aost!(time)
21
+ end
22
+
6
23
  def from!(...) # :nodoc:
7
24
  @force_index = nil
8
25
  @index_hint = nil
@@ -59,8 +76,20 @@ module ActiveRecord
59
76
  self
60
77
  end
61
78
 
79
+ # TODO: reset or no reset?
80
+
81
+ def show_create
82
+ connection.execute("show create table #{connection.quote_table_name self.table_name}").first["create_statement"]
83
+ end
84
+
62
85
  private
63
86
 
87
+ def build_arel(...)
88
+ arel = super
89
+ arel.aost(@aost) if @aost.present?
90
+ arel
91
+ end
92
+
64
93
  def from_clause_is_a_table_name?
65
94
  # if empty, we are just dealing with the current table.
66
95
  return true if from_clause.empty?
@@ -94,5 +123,5 @@ module ActiveRecord
94
123
  # as ancestor. That is how active_record is doing is as well.
95
124
  #
96
125
  # @see https://github.com/rails/rails/blob/914130a9f/activerecord/lib/active_record/querying.rb#L23
97
- Querying.delegate(:force_index, :index_hint, to: :all)
126
+ Querying.delegate(:force_index, :index_hint, :aost, :show_create, to: :all)
98
127
  end
@@ -0,0 +1,28 @@
1
+ module Arel
2
+ module Nodes
3
+ module JoinSourceExt
4
+ def initialize(...)
5
+ super
6
+ @aost = nil
7
+ end
8
+
9
+ def hash
10
+ [*super, aost].hash
11
+ end
12
+
13
+ def eql?(other)
14
+ super && aost == other.aost
15
+ end
16
+ alias_method :==, :eql?
17
+ end
18
+ JoinSource.attr_accessor :aost
19
+ JoinSource.prepend JoinSourceExt
20
+ end
21
+ module SelectManagerExt
22
+ def aost(time)
23
+ @ctx.source.aost = time
24
+ nil
25
+ end
26
+ end
27
+ SelectManager.prepend SelectManagerExt
28
+ end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- COCKROACH_DB_ADAPTER_VERSION = "7.0.3"
4
+ COCKROACH_DB_ADAPTER_VERSION = "7.1.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-cockroachdb-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.3
4
+ version: 7.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cockroach Labs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-23 00:00:00.000000000 Z
11
+ date: 2024-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.3
19
+ version: 7.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 7.0.3
26
+ version: 7.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -74,6 +74,7 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - ".editorconfig"
77
78
  - ".github/workflows/ci.yml"
78
79
  - ".github/workflows/docker.yml"
79
80
  - ".gitignore"
@@ -87,6 +88,8 @@ files:
87
88
  - Rakefile
88
89
  - activerecord-cockroachdb-adapter.gemspec
89
90
  - bin/console
91
+ - bin/console_schemas/default.rb
92
+ - bin/console_schemas/schemas.rb
90
93
  - bin/setup
91
94
  - bin/start-cockroachdb
92
95
  - build/Dockerfile
@@ -118,6 +121,7 @@ files:
118
121
  - lib/active_record/migration/cockroachdb/compatibility.rb
119
122
  - lib/active_record/relation/query_methods_ext.rb
120
123
  - lib/activerecord-cockroachdb-adapter.rb
124
+ - lib/arel/nodes/join_source_ext.rb
121
125
  - lib/version.rb
122
126
  homepage: https://github.com/cockroachdb/activerecord-cockroachdb-adapter
123
127
  licenses:
@@ -139,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  - !ruby/object:Gem::Version
140
144
  version: '0'
141
145
  requirements: []
142
- rubygems_version: 3.4.9
146
+ rubygems_version: 3.4.10
143
147
  signing_key:
144
148
  specification_version: 4
145
149
  summary: CockroachDB adapter for ActiveRecord.