Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Rails 7.2.0 #328

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nightly-unit-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/active_record/connection_adapters/spanner/quoting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 25 additions & 16 deletions lib/active_record/connection_adapters/spanner_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion lib/activerecord-spanner-adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 13 additions & 2 deletions lib/activerecord_spanner_adapter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading