diff --git a/.github/workflows/nightly-unit-tests.yaml b/.github/workflows/nightly-unit-tests.yaml index 4d90b8fe..c1f1680f 100644 --- a/.github/workflows/nightly-unit-tests.yaml +++ b/.github/workflows/nightly-unit-tests.yaml @@ -12,7 +12,7 @@ jobs: matrix: # Run acceptance tests all supported combinations of Ruby and ActiveRecord. ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"] - ar: ["~> 6.1.0", "~> 7.0.0", "~> 7.1.0"] + ar: ["~> 6.1.0", "~> 7.0.0", "~> 7.1.0", "~> 7.2.0"] # Exclude combinations that are not supported. exclude: - ruby: "2.7" diff --git a/lib/active_record/connection_adapters/spanner/database_statements.rb b/lib/active_record/connection_adapters/spanner/database_statements.rb index e0741f34..dac621b5 100644 --- a/lib/active_record/connection_adapters/spanner/database_statements.rb +++ b/lib/active_record/connection_adapters/spanner/database_statements.rb @@ -21,15 +21,15 @@ def execute sql, name = nil, binds = [] internal_execute sql, name, binds end - def internal_exec_query sql, name = "SQL", binds = [], prepare: false, async: false - result = internal_execute sql, name, binds, prepare: prepare, async: async + def internal_exec_query sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false + result = internal_execute sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry ActiveRecord::Result.new( result.fields.keys.map(&:to_s), result.rows.map(&:values) ) end def internal_execute sql, name = "SQL", binds = [], - prepare: false, async: false # rubocop:disable Lint/UnusedMethodArgument + prepare: false, async: false, allow_retry: false # rubocop:disable Lint/UnusedMethodArgument, Metrics/LineLength statement_type = sql_statement_type sql # Call `transform` to invoke any query transformers that might have been registered. sql = transform sql diff --git a/lib/active_record/connection_adapters/spanner/quoting.rb b/lib/active_record/connection_adapters/spanner/quoting.rb index 0d9c26f3..e4e18123 100644 --- a/lib/active_record/connection_adapters/spanner/quoting.rb +++ b/lib/active_record/connection_adapters/spanner/quoting.rb @@ -36,11 +36,11 @@ module Quoting QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc: def quote_column_name name - QUOTED_COLUMN_NAMES[name] ||= "`#{super.gsub '`', '``'}`".freeze + QUOTED_COLUMN_NAMES[name] ||= "`#{name.to_s.gsub '`', '``'}`".freeze end def quote_table_name name - QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "`.`").freeze + QUOTED_TABLE_NAMES[name] ||= "`#{name.to_s.gsub '.', '`.`'}`".freeze end STR_ESCAPE_REGX = /[\n\r'\\]/.freeze diff --git a/lib/active_record/connection_adapters/spanner_adapter.rb b/lib/active_record/connection_adapters/spanner_adapter.rb index 3dad93f6..2fe571e4 100644 --- a/lib/active_record/connection_adapters/spanner_adapter.rb +++ b/lib/active_record/connection_adapters/spanner_adapter.rb @@ -28,16 +28,18 @@ require "activerecord_spanner_adapter/transaction" module ActiveRecord - module ConnectionHandling # :nodoc: - def spanner_connection config - connection = ActiveRecordSpannerAdapter::Connection.new config - connection.connect! - ConnectionAdapters::SpannerAdapter.new connection, logger, nil, config - rescue Google::Cloud::Error => error - if error.instance_of? Google::Cloud::NotFoundError - raise ActiveRecord::NoDatabaseError - end - raise error + if ActiveRecord.version < Gem::Version.new("7.2") + module ConnectionHandling # :nodoc: + def spanner_connection config + connection = ActiveRecordSpannerAdapter::Connection.new config + connection.connect! + ConnectionAdapters::SpannerAdapter.new connection, logger, nil, config + rescue Google::Cloud::Error => error + if error.instance_of? Google::Cloud::NotFoundError + raise ActiveRecord::NoDatabaseError + end + raise error + end end end @@ -69,12 +71,19 @@ class SpannerAdapter < AbstractAdapter # Determines whether or not to log query binds when executing statements class_attribute :log_statement_binds, instance_writer: false, default: false - def initialize connection, logger, connection_options, config - @connection = connection - @connection_options = connection_options - super connection, logger, config - @raw_connection ||= connection - + def initialize config_or_deprecated_connection, deprecated_logger = nil, + deprecated_connection_options = nil, deprecated_config = nil + if config_or_deprecated_connection.is_a? Hash + @connection = ActiveRecordSpannerAdapter::Connection.new config_or_deprecated_connection + @connection.connect! + super config_or_deprecated_connection + @raw_connection ||= @connection + else + @connection = config_or_deprecated_connection + @connection_options = deprecated_connection_options + super config_or_deprecated_connection, deprecated_logger, deprecated_config + @raw_connection ||= config_or_deprecated_connection + end # Spanner does not support unprepared statements @prepared_statements = true end diff --git a/lib/activerecord-spanner-adapter.rb b/lib/activerecord-spanner-adapter.rb index e732d38a..9e92fcd1 100644 --- a/lib/activerecord-spanner-adapter.rb +++ b/lib/activerecord-spanner-adapter.rb @@ -15,7 +15,11 @@ class SpannerRailtie < ::Rails::Railtie end ActiveSupport.on_load :active_record do - require "active_record/connection_adapters/spanner_adapter" + if Rails.version >= "7.2.0" + ActiveRecord::ConnectionAdapters.register("spanner", "ActiveRecord::ConnectionAdapters::SpannerAdapter") + else + require "active_record/connection_adapters/spanner_adapter" + end end end end diff --git a/lib/activerecord_spanner_adapter/base.rb b/lib/activerecord_spanner_adapter/base.rb index 58993be8..d1eab9f3 100644 --- a/lib/activerecord_spanner_adapter/base.rb +++ b/lib/activerecord_spanner_adapter/base.rb @@ -16,6 +16,7 @@ class TableMetadata # :nodoc: class Base VERSION_7_1 = Gem::Version.create "7.1.0" + VERSION_7_2 = Gem::Version.create "7.2.0" # Creates an object (or multiple objects) and saves it to the database. This method will use mutations instead # of DML if there is no active transaction, or if the active transaction has been created with the option @@ -48,8 +49,18 @@ def self.buffered_mutations? spanner_adapter? && connection&.current_spanner_transaction&.isolation == :buffered_mutations end - def self._insert_record values, returning = [] - if !(buffered_mutations? || (primary_key && values.is_a?(Hash))) || !spanner_adapter? + def self._should_use_standard_insert_record? values + !(buffered_mutations? || (primary_key && values.is_a?(Hash))) || !spanner_adapter? + end + + def self._insert_record *args + if ActiveRecord.gem_version < VERSION_7_2 + values, returning = args + else + _connection, values, returning = [] + end + + if _should_use_standard_insert_record? values return super values if ActiveRecord.gem_version < VERSION_7_1 return super end