Skip to content
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
4 changes: 3 additions & 1 deletion .github/workflows/acceptance-tests-on-emulator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ jobs:
max-parallel: 4
matrix:
ruby: ["3.1", "3.2", "3.3", "3.4"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0", "~> 8.1.0"]
# Exclude combinations that are not supported.
exclude:
- ruby: "3.1"
ar: "~> 8.0.0"
- ruby: "3.1"
ar: "~> 8.1.0"
- ruby: "3.4"
ar: "~> 7.0.0"
- ruby: "3.4"
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ jobs:
max-parallel: 4
matrix:
ruby: ["3.1", "3.2", "3.3", "3.4"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0", "~> 8.1.0"]
# Exclude combinations that are not supported.
exclude:
- ruby: "3.1"
ar: "~> 8.0.0"
- ruby: "3.1"
ar: "~> 8.1.0"
- ruby: "3.4"
ar: "~> 7.0.0"
- ruby: "3.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ jobs:
max-parallel: 4
matrix:
ruby: ["3.1", "3.2", "3.3", "3.4"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0", "~> 8.1.0"]
# Exclude combinations that are not supported.
exclude:
- ruby: "3.1"
ar: "~> 8.0.0"
- ruby: "3.1"
ar: "~> 8.1.0"
- ruby: "3.4"
ar: "~> 7.0.0"
- ruby: "3.4"
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/nightly-unit-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ jobs:
matrix:
# Run acceptance tests all supported combinations of Ruby and ActiveRecord.
ruby: ["3.1", "3.2", "3.3", "3.4"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0"]
ar: ["~> 7.0.0", "~> 7.1.0", "~> 7.2.0", "~> 8.0.0", "~> 8.1.0"]
# Exclude combinations that are not supported.
exclude:
- ruby: "3.1"
ar: "~> 8.0.0"
- ruby: "3.1"
ar: "~> 8.1.0"
- ruby: "3.4"
ar: "~> 7.0.0"
- ruby: "3.4"
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ar_version = ENV.fetch("AR_VERSION", "~> 7.1.0")
gem "activerecord", ar_version
gem "ostruct"
gem "minitest", "~> 5.27.0"
gem "minitest-rg", "~> 5.3.0"
gem "minitest-rg", "~> 5.4.0"
gem "pry", "~> 0.14.2"
gem "pry-byebug", "~> 3.11.0"
gem "mutex_m"
Expand Down
4 changes: 2 additions & 2 deletions acceptance/cases/migration/index_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_rename_index_too_long
e = assert_raises(ArgumentError) {
connection.rename_index(table_name, "old_idx", too_long_index_name)
}
assert_match(/too long; the limit is #{connection.index_name_length} characters/, e.message)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is slightly different in 8.1 than in the other versions. We don't really care about the specific error message, only that it is actually an error message about the index name being too long.

assert_match(/too long/, e.message)

assert connection.index_name_exists?(table_name, "old_idx")
end
Expand All @@ -79,7 +79,7 @@ def test_add_index_does_not_accept_too_long_index_names
e = assert_raises(ArgumentError) {
connection.add_index(table_name, "foo", name: too_long_index_name)
}
assert_match(/too long; the limit is #{connection.index_name_length} characters/, e.message)
assert_match(/too long/, e.message)

assert_not connection.index_name_exists?(table_name, too_long_index_name)
connection.add_index(table_name, "foo", name: good_index_name)
Expand Down
4 changes: 2 additions & 2 deletions activerecord-spanner-adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency "activerecord", [">= 7.0", "< 9"]

spec.add_development_dependency "autotest-suffix", "~> 1.1"
spec.add_development_dependency "bundler", "~> 2.0"
spec.add_development_dependency "bundler", [">= 2.0", "< 5.0"]
spec.add_development_dependency "google-style", "~> 1.31.0"
spec.add_development_dependency "minitest", "~> 5.10"
spec.add_development_dependency "minitest-autotest", "~> 1.0"
spec.add_development_dependency "minitest-focus", "~> 1.1"
spec.add_development_dependency "minitest-rg", "~> 5.2"
spec.add_development_dependency "minitest-rg", "~> 5.4"
spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "redcarpet", "~> 3.0"
spec.add_development_dependency "simplecov", "~> 0.9"
Expand Down
27 changes: 20 additions & 7 deletions lib/active_record/connection_adapters/spanner/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,26 @@ module ActiveRecord
module ConnectionAdapters
module Spanner
class Column < ConnectionAdapters::Column
# rubocop:disable Style/OptionalBooleanParameter
def initialize(name, default, sql_type_metadata = nil, null = true,
default_function = nil, collation: nil, comment: nil,
primary_key: false, **)
# rubocop:enable Style/OptionalBooleanParameter
super
@primary_key = primary_key
VERSION_8_1 = Gem::Version.create "8.1.0"

if ActiveRecord.gem_version < VERSION_8_1
# rubocop:disable Style/OptionalBooleanParameter
def initialize(name, default, sql_type_metadata = nil, null = true,
default_function = nil, collation: nil, comment: nil,
primary_key: false, **)
# rubocop:enable Style/OptionalBooleanParameter
super
@primary_key = primary_key
end
else
# rubocop:disable Style/OptionalBooleanParameter
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8.1 introduced a new positional parameter cast_type for this constructor.

default_function = nil, collation: nil, comment: nil,
primary_key: false, **)
# rubocop:enable Style/OptionalBooleanParameter
super
@primary_key = primary_key
end
end

def auto_incremented_by_db?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ def add_column_options! column, sql, options
sql << " NOT NULL"
end
if options.key? :default
sql << " DEFAULT (#{quote_default_expression options[:default], column})"
sql << if respond_to? :quote_default_expression_for_column_definition, :include_private
" DEFAULT (#{quote_default_expression_for_column_definition options[:default], column})"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to the same cast_type change above. In 8.1, we need to call quote_default_expression_for_column_definition, which again uses the value of cast_type to generate the correct expression.

else
" DEFAULT (#{quote_default_expression options[:default], column})"
end
elsif column.type == :primary_key
if @connection.use_auto_increment?
sql << " AUTO_INCREMENT"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module Spanner
#
module SchemaStatements
VERSION_7_2 = Gem::Version.create "7.2.0"
VERSION_8_1 = Gem::Version.create "8.1.0"

def current_database
@connection.database_id
Expand Down Expand Up @@ -116,18 +117,37 @@ def column_definitions table_name
information_schema { |i| i.table_columns table_name }
end

def new_column_from_field _table_name, field, _definitions = nil
Spanner::Column.new \
field.name,
field.default,
fetch_type_metadata(field.spanner_type,
field.ordinal_position,
field.allow_commit_timestamp,
field.generated,
is_identity: field.is_identity),
field.nullable,
field.default_function,
primary_key: field.primary_key
if ActiveRecord.gem_version < VERSION_8_1
def new_column_from_field _table_name, field, _definitions = nil
Spanner::Column.new \
field.name,
field.default,
fetch_type_metadata(field.spanner_type,
field.ordinal_position,
field.allow_commit_timestamp,
field.generated,
is_identity: field.is_identity),
field.nullable,
field.default_function,
primary_key: field.primary_key
end
else
def new_column_from_field _table_name, field, _definitions = nil
cast_type = type_map.lookup field.type
raise ArgumentError, "unknown type: `#{field.type}`" if cast_type.nil?
Spanner::Column.new \
field.name,
cast_type,
field.default,
fetch_type_metadata(field.spanner_type,
field.ordinal_position,
field.allow_commit_timestamp,
field.generated,
is_identity: field.is_identity),
field.nullable,
field.default_function,
primary_key: field.primary_key
end
end

def fetch_type_metadata sql_type, ordinal_position = nil, allow_commit_timestamp = nil, generated = nil,
Expand Down
25 changes: 25 additions & 0 deletions lib/active_record/connection_adapters/spanner/type_mapping.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2026 Google LLC
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been moved to a separate file, so we can require it from two places. It is now also needed in connection.rb.

#
# Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
#
# frozen_string_literal: true

NATIVE_DATABASE_TYPES = {
primary_key: "INT64",
parent_key: "INT64",
string: { name: "STRING", limit: "MAX" },
text: { name: "STRING", limit: "MAX" },
integer: { name: "INT64" },
bigint: { name: "INT64" },
float: { name: "FLOAT64" },
decimal: { name: "NUMERIC" },
numeric: { name: "NUMERIC" },
datetime: { name: "TIMESTAMP" },
time: { name: "TIMESTAMP" },
date: { name: "DATE" },
binary: { name: "BYTES", limit: "MAX" },
boolean: { name: "BOOL" },
json: { name: "JSON" }
}.freeze
22 changes: 5 additions & 17 deletions lib/active_record/connection_adapters/spanner_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require "active_record/connection_adapters/spanner/schema_statements"
require "active_record/connection_adapters/spanner/schema_cache"
require "active_record/connection_adapters/spanner/schema_definitions"
require "active_record/connection_adapters/spanner/type_mapping"
require "active_record/connection_adapters/spanner/type_metadata"
require "active_record/connection_adapters/spanner/quoting"
require "active_record/type/spanner/array"
Expand Down Expand Up @@ -46,23 +47,6 @@ def spanner_connection config
module ConnectionAdapters
class SpannerAdapter < AbstractAdapter
ADAPTER_NAME = "spanner".freeze
NATIVE_DATABASE_TYPES = {
primary_key: "INT64",
parent_key: "INT64",
string: { name: "STRING", limit: "MAX" },
text: { name: "STRING", limit: "MAX" },
integer: { name: "INT64" },
bigint: { name: "INT64" },
float: { name: "FLOAT64" },
decimal: { name: "NUMERIC" },
numeric: { name: "NUMERIC" },
datetime: { name: "TIMESTAMP" },
time: { name: "TIMESTAMP" },
date: { name: "DATE" },
binary: { name: "BYTES", limit: "MAX" },
boolean: { name: "BOOL" },
json: { name: "JSON" }
}.freeze

include Spanner::Quoting
include Spanner::DatabaseStatements
Expand Down Expand Up @@ -118,6 +102,10 @@ def native_database_types
NATIVE_DATABASE_TYPES
end

def self.native_database_types
NATIVE_DATABASE_TYPES
end

# Database

def self.database_exists? config
Expand Down
5 changes: 5 additions & 0 deletions lib/activerecord_spanner_adapter/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

require "google/cloud/spanner"
require "spanner_client_ext"
require "active_record/connection_adapters/spanner/type_mapping"
require "activerecord_spanner_adapter/information_schema"
require_relative "../active_record/connection_adapters/spanner/errors/transaction_mutation_limit_exceeded_error"

Expand Down Expand Up @@ -43,6 +44,10 @@ def self.spanners config
end
end

def native_database_types
NATIVE_DATABASE_TYPES
end

# Clears the cached information about the underlying information schemas.
# Call this method if you drop and recreate a database with the same name
# to prevent the cached information to be used for the new database.
Expand Down
Loading