activerecord-cockroachdb-adapter 0.3.0.beta1 → 6.0.0beta2

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: 48ca5207eae1d4bf1c26da960ad80e78f54099b1eb62466e89ff5186c9d41632
4
- data.tar.gz: d3d8a5c38a3adda552b283663d4aaf88e05587b3ac9e0da28418fa05d72cfcdd
3
+ metadata.gz: f2d3e8ca47a966406dd46a2516ee8e28d4634109974b012604efa5eeef41661c
4
+ data.tar.gz: 78f2720ce377db8b5d61c830c2f8819f4a928bceee3121668348293944b459ac
5
5
  SHA512:
6
- metadata.gz: 955dca7f67f68b93fd2ebd19cd6027de446598c823abbc108ce5630fbf6d566c14c09e283f37e3d04fb306ff72a68e55f6856daea91a61f9488636f9da957920
7
- data.tar.gz: 9cb056da8d37cd199427f2ae25d354bcb3fb606fde92e1c01fb2cef7eedd2122a9eccbf0b3693d7d0c7197f8ff8d7d4b1321d16d9212db4331673ddf5669b934
6
+ metadata.gz: 7928d308947df985eac1ecf4ac2338d8ed5e079c2436562a822b149699b0bc42e38411e90a73a5623c376613ca610060d68f9040d823b9fa65d2869baa98a6fd
7
+ data.tar.gz: 5421bb06b3185d331a0a43e700e2475f6ce28ee38d433ba28e3e82c4a0e361a94518dd46fd41b54d1a83f1a217d19e098eef0a251ad7e79803263c08bfd7e3dc
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
@@ -46,19 +46,31 @@ Using [bundler](http://bundler.io/), install the dependancies of Rails.
46
46
  bundle install
47
47
  ```
48
48
 
49
- Then, to run the full ActiveRecord test suite with an active CockroachDB instance:
49
+ Then, to run the full test suite with an active CockroachDB instance:
50
50
 
51
51
  ```bash
52
52
  bundle exec rake test
53
53
  ```
54
54
 
55
- To run specific tests, set environemnt variable `TEST_FILES_AR`. For example, to run ActiveRecord tests `test/cases/associations_test.rb` and `test/cases/ar_schema_test.rb.rb`
55
+ To run specific ActiveRecord tests, set environemnt variable `TEST_FILES_AR`. For example, to run ActiveRecord tests `test/cases/associations_test.rb` and `test/cases/ar_schema_test.rb.rb`
56
56
 
57
57
  ```bash
58
58
  TEST_FILES_AR="test/cases/associations_test.rb,test/cases/ar_schema_test.rb" bundle exec rake test
59
59
  ```
60
60
 
61
- By default, tests will be run from the bundled version of Rails. To run against a local copy, set environemnt variable `RAILS_SOURCE`.
61
+ To run specific CockroachDB Adapter tests, set environemnt variable `TEST_FILES`. For example, to run CockroachDB Adpater tests `test/cases/adapter_test.rb` and `test/cases/associations/left_outer_join_association_test.rb`
62
+
63
+ ```bash
64
+ TEST_FILES="test/cases/adapter_test.rb,test/cases/associations/left_outer_join_association_test.rb" bundle exec rake test
65
+ ```
66
+
67
+ To run a specific test case, use minitest's `-n` option to run tests that match a given pattern. All minitest options are set via the `TESTOPTS` environemnt variable. For example, to run `test_indexes` from CockroachDB's `test/cases/adapter_test.rb` file
68
+
69
+ ```bash
70
+ TEST_FILES="test/cases/adapter_test.rb" TESTOPTS=`-n=/test_indexes/` bundle exec rake test
71
+ ```
72
+
73
+ By default, tests will be run from the bundled version of Rails. To run against a local copy, set environemnt variable `RAILS_SOURCE`. Running against a local copy of Rails can be helpful when try to debug issues.
62
74
 
63
75
  ```bash
64
76
  RAILS_SOURCE="path/to/local_copy" bundle exec rake test
data/README.md CHANGED
@@ -7,7 +7,7 @@ CockroachDB adapter for ActiveRecord 4 and 5. This is a lightweight extension of
7
7
  Add this line to your project's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'activerecord-cockroachdb-adapter', '~> 0.2'
10
+ gem 'activerecord-cockroachdb-adapter', '~> 5.2.0'
11
11
  ```
12
12
 
13
13
  If you're using Rails 4.x, use the `0.1.x` versions of this gem.
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "activerecord-cockroachdb-adapter"
7
- spec.version = "0.3.0.beta1"
7
+ spec.version = "6.0.0beta2"
8
8
  spec.licenses = ["Apache-2.0"]
9
9
  spec.authors = ["Cockroach Labs"]
10
10
  spec.email = ["cockroach-db@googlegroups.com"]
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.description = "Allows the use of CockroachDB as a backend for ActiveRecord and Rails apps."
14
14
  spec.homepage = "https://github.com/cockroachdb/activerecord-cockroachdb-adapter"
15
15
 
16
- spec.add_dependency "activerecord", "~> 5.2"
16
+ spec.add_dependency "activerecord", "~> 6.0.3"
17
17
  spec.add_dependency "pg", ">= 0.20"
18
18
 
19
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- set -euo pipefail
3
+ set -euox pipefail
4
4
 
5
5
  # Download CockroachDB
6
- VERSION=v20.1.0-rc.1
6
+ VERSION=v20.2.3
7
7
  wget -qO- https://binaries.cockroachdb.com/cockroach-$VERSION.linux-amd64.tgz | tar xvz
8
8
  readonly COCKROACH=./cockroach-$VERSION.linux-amd64/cockroach
9
9
 
@@ -21,7 +21,7 @@ run_cockroach() {
21
21
  cockroach quit --insecure || true
22
22
  rm -rf cockroach-data
23
23
  # Start CockroachDB.
24
- cockroach start --insecure --host=localhost --listening-url-file="$urlfile" >/dev/null 2>&1 &
24
+ cockroach start-single-node --max-sql-memory=25% --cache=25% --insecure --host=localhost --listening-url-file="$urlfile" >/dev/null 2>&1 &
25
25
  # Ensure CockroachDB is stopped on script exit.
26
26
  trap "echo 'Exit routine: Killing CockroachDB.' && kill -9 $! &> /dev/null" EXIT
27
27
  # Wait until CockroachDB has started.
@@ -33,6 +33,9 @@ run_cockroach() {
33
33
  done
34
34
  cockroach sql --insecure -e 'CREATE DATABASE activerecord_unittest;'
35
35
  cockroach sql --insecure -e 'CREATE DATABASE activerecord_unittest2;'
36
+ cockroach sql --insecure -e 'SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false;'
37
+ cockroach sql --insecure -e 'SET CLUSTER SETTING sql.stats.histogram_collection.enabled = false;'
38
+ cockroach sql --insecure -e "SET CLUSTER SETTING jobs.retention_time = '180s';"
36
39
  }
37
40
 
38
41
  # Install ruby dependencies.
@@ -41,7 +44,7 @@ bundle install
41
44
 
42
45
  run_cockroach
43
46
 
44
- if ! (bundle exec rake test); then
47
+ if ! (RUBYOPT="-W0" TESTOPTS="-v" bundle exec rake test); then
45
48
  echo "Tests failed"
46
49
  HAS_FAILED=1
47
50
  else
data/docker.sh CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # This file is largely cargo-culted from cockroachdb/cockroach/build/builder.sh.
4
4
 
5
- set -euo pipefail
5
+ set -euox pipefail
6
6
 
7
7
  DOCKER_IMAGE_TAG=activerecord_test_container
8
8
 
@@ -15,6 +15,87 @@ module ActiveRecord
15
15
  serializable: "SERIALIZABLE"
16
16
  }
17
17
  end
18
+
19
+ # Overridden to avoid using transactions for schema creation.
20
+ def insert_fixtures_set(fixture_set, tables_to_delete = [])
21
+ fixture_inserts = build_fixture_statements(fixture_set)
22
+ table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
23
+ statements = table_deletes + fixture_inserts
24
+
25
+ with_multi_statements do
26
+ disable_referential_integrity do
27
+ execute_batch(statements, "Fixtures Load")
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+ def execute_batch(statements, name = nil)
34
+ statements.each do |statement|
35
+ execute(statement, name)
36
+ end
37
+ end
38
+
39
+ DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
40
+ private_constant :DEFAULT_INSERT_VALUE
41
+
42
+ def default_insert_value(column)
43
+ DEFAULT_INSERT_VALUE
44
+ end
45
+
46
+ def build_fixture_sql(fixtures, table_name)
47
+ columns = schema_cache.columns_hash(table_name)
48
+
49
+ values_list = fixtures.map do |fixture|
50
+ fixture = fixture.stringify_keys
51
+
52
+ unknown_columns = fixture.keys - columns.keys
53
+ if unknown_columns.any?
54
+ raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
55
+ end
56
+
57
+ columns.map do |name, column|
58
+ if fixture.key?(name)
59
+ type = lookup_cast_type_from_column(column)
60
+ with_yaml_fallback(type.serialize(fixture[name]))
61
+ else
62
+ default_insert_value(column)
63
+ end
64
+ end
65
+ end
66
+
67
+ table = Arel::Table.new(table_name)
68
+ manager = Arel::InsertManager.new
69
+ manager.into(table)
70
+
71
+ if values_list.size == 1
72
+ values = values_list.shift
73
+ new_values = []
74
+ columns.each_key.with_index { |column, i|
75
+ unless values[i].equal?(DEFAULT_INSERT_VALUE)
76
+ new_values << values[i]
77
+ manager.columns << table[column]
78
+ end
79
+ }
80
+ values_list << new_values
81
+ else
82
+ columns.each_key { |column| manager.columns << table[column] }
83
+ end
84
+
85
+ manager.values = manager.create_values_list(values_list)
86
+ manager.to_sql
87
+ end
88
+
89
+ def build_fixture_statements(fixture_set)
90
+ fixture_set.map do |table_name, fixtures|
91
+ next if fixtures.empty?
92
+ build_fixture_sql(fixtures, table_name)
93
+ end.compact
94
+ end
95
+
96
+ def with_multi_statements
97
+ yield
98
+ end
18
99
  end
19
100
  end
20
101
  end
@@ -38,6 +38,54 @@ module ActiveRecord
38
38
  def default_sequence_name(table_name, pk = "id")
39
39
  nil
40
40
  end
41
+
42
+ # CockroachDB will use INT8 if the SQL type is INTEGER, so we make it use
43
+ # INT4 explicitly when needed.
44
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
45
+ sql = \
46
+ case type.to_s
47
+ when "integer"
48
+ case limit
49
+ when nil; "int"
50
+ when 1, 2; "int2"
51
+ when 3, 4; "int4"
52
+ when 5..8; "int8"
53
+ else super
54
+ end
55
+ else
56
+ super
57
+ end
58
+ # The call to super might have appeneded [] already.
59
+ if array && type != :primary_key && !sql.end_with?("[]")
60
+ sql = "#{sql}[]"
61
+ end
62
+ sql
63
+ end
64
+
65
+ # This overrides the method from PostegreSQL adapter
66
+ # Resets the sequence of a table's primary key to the maximum value.
67
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
68
+ unless pk && sequence
69
+ default_pk, default_sequence = pk_and_sequence_for(table)
70
+
71
+ pk ||= default_pk
72
+ sequence ||= default_sequence
73
+ end
74
+
75
+ if @logger && pk && !sequence
76
+ @logger.warn "#{table} has primary key #{pk} with no default sequence."
77
+ end
78
+
79
+ if pk && sequence
80
+ quoted_sequence = quote_table_name(sequence)
81
+ max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
82
+ if max_pk.nil?
83
+ minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
84
+ end
85
+
86
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA")
87
+ end
88
+ end
41
89
  end
42
90
  end
43
91
  end
@@ -8,16 +8,22 @@ module ActiveRecord
8
8
  # transactions that fail due to serialization errors. Failed
9
9
  # transactions will be retried until they pass or the max retry limit is
10
10
  # exceeded.
11
- def within_new_transaction(options = {})
12
- attempts = options.fetch(:attempts, 0)
11
+ def within_new_transaction(isolation: nil, joinable: true, attempts: 0)
13
12
  super
14
- rescue ActiveRecord::SerializationFailure => error
13
+ rescue ActiveRecord::StatementInvalid => error
14
+ raise unless retryable? error
15
15
  raise if attempts >= @connection.max_transaction_retries
16
16
 
17
17
  attempts += 1
18
18
  sleep_seconds = (2 ** attempts + rand) / 10
19
19
  sleep(sleep_seconds)
20
- within_new_transaction(options.merge(attempts: attempts)) { yield }
20
+ within_new_transaction(isolation: isolation, joinable: joinable, attempts: attempts) { yield }
21
+ end
22
+
23
+ def retryable?(error)
24
+ return true if error.is_a? ActiveRecord::SerializationFailure
25
+ return retryable? error.cause if error.cause
26
+ false
21
27
  end
22
28
  end
23
29
  end
@@ -24,10 +24,14 @@ module ActiveRecord
24
24
  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:sslmode, :application_name]
25
25
  conn_params.slice!(*valid_conn_param_keys)
26
26
 
27
- # The postgres drivers don't allow the creation of an unconnected
28
- # PG::Connection object, so just pass a nil connection object for the
29
- # time being.
30
- ConnectionAdapters::CockroachDBAdapter.new(nil, logger, conn_params, config)
27
+ conn = PG.connect(conn_params)
28
+ ConnectionAdapters::CockroachDBAdapter.new(conn, logger, conn_params, config)
29
+ rescue ::PG::Error, ActiveRecord::ActiveRecordError => error
30
+ if error.message.include?("does not exist")
31
+ raise ActiveRecord::NoDatabaseError
32
+ else
33
+ raise
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -56,6 +60,10 @@ module ActiveRecord
56
60
  100000
57
61
  end
58
62
 
63
+ def supports_bulk_alter?
64
+ false
65
+ end
66
+
59
67
  def supports_json?
60
68
  # FIXME(joey): Add a version check.
61
69
  true
@@ -69,18 +77,12 @@ module ActiveRecord
69
77
  false
70
78
  end
71
79
 
72
- def supports_ranges?
73
- # See cockroachdb/cockroach#17022
74
- false
75
- end
76
-
77
80
  def supports_materialized_views?
78
81
  false
79
82
  end
80
83
 
81
84
  def supports_partial_index?
82
- # See cockroachdb/cockroach#9683
83
- false
85
+ @crdb_version >= 202
84
86
  end
85
87
 
86
88
  def supports_expression_index?
@@ -103,8 +105,7 @@ module ActiveRecord
103
105
  end
104
106
 
105
107
  def supports_advisory_locks?
106
- # FIXME(joey): We may want to make this false.
107
- true
108
+ false
108
109
  end
109
110
 
110
111
  def supports_virtual_columns?
@@ -112,6 +113,10 @@ module ActiveRecord
112
113
  false
113
114
  end
114
115
 
116
+ def supports_string_to_array_coercion?
117
+ @crdb_version >= 202
118
+ end
119
+
115
120
  # This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
116
121
  # migration from PostgreSQL to CockroachDB. In practice, this limitation
117
122
  # is arbitrary since CockroachDB supports index name lengths and table alias
@@ -127,6 +132,31 @@ module ActiveRecord
127
132
  alias index_name_length max_identifier_length
128
133
  alias table_alias_length max_identifier_length
129
134
 
135
+ def initialize(connection, logger, conn_params, config)
136
+ super(connection, logger, conn_params, config)
137
+ crdb_version_string = query_value("SHOW crdb_version")
138
+ if crdb_version_string.include? "v1."
139
+ version_num = 1
140
+ elsif crdb_version_string.include? "v2."
141
+ version_num 2
142
+ elsif crdb_version_string.include? "v19.1."
143
+ version_num = 191
144
+ elsif crdb_version_string.include? "v19.2."
145
+ version_num = 192
146
+ elsif crdb_version_string.include? "v20.1."
147
+ version_num = 201
148
+ else
149
+ version_num = 202
150
+ end
151
+ @crdb_version = version_num
152
+ end
153
+
154
+ def self.database_exists?(config)
155
+ !!ActiveRecord::Base.cockroachdb_connection(config)
156
+ rescue ActiveRecord::NoDatabaseError
157
+ false
158
+ end
159
+
130
160
  private
131
161
 
132
162
  def initialize_type_map(m = type_map)
@@ -199,7 +229,8 @@ module ActiveRecord
199
229
  def extract_value_from_default(default)
200
230
  super ||
201
231
  extract_escaped_string_from_default(default) ||
202
- extract_time_from_default(default)
232
+ extract_time_from_default(default) ||
233
+ extract_empty_array_from_default(default)
203
234
  end
204
235
 
205
236
  # Both PostgreSQL and CockroachDB use C-style string escapes under the
@@ -241,6 +272,15 @@ module ActiveRecord
241
272
  nil
242
273
  end
243
274
 
275
+ # CockroachDB stores default values for arrays in the `ARRAY[...]` format.
276
+ # In general, it is hard to parse that, but it is easy to handle the common
277
+ # case of an empty array.
278
+ def extract_empty_array_from_default(default)
279
+ return unless supports_string_to_array_coercion?
280
+ return unless default =~ /\AARRAY\[\]\z/
281
+ return "{}"
282
+ end
283
+
244
284
  # end private
245
285
  end
246
286
  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: 0.3.0.beta1
4
+ version: 6.0.0beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cockroach Labs
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-17 00:00:00.000000000 Z
11
+ date: 2020-12-22 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: '5.2'
19
+ version: 6.0.3
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: '5.2'
26
+ version: 6.0.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -77,7 +77,7 @@ licenses:
77
77
  - Apache-2.0
78
78
  metadata:
79
79
  allowed_push_host: https://rubygems.org
80
- post_install_message:
80
+ post_install_message:
81
81
  rdoc_options: []
82
82
  require_paths:
83
83
  - lib
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  - !ruby/object:Gem::Version
93
93
  version: 1.3.1
94
94
  requirements: []
95
- rubygems_version: 3.1.2
96
- signing_key:
95
+ rubygems_version: 3.1.4
96
+ signing_key:
97
97
  specification_version: 4
98
98
  summary: CockroachDB adapter for ActiveRecord.
99
99
  test_files: []