Skip to content
Open
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: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ jobs:
--health-timeout 5s
--health-retries 5
env:
AR_VERSION: 8.0.0.1
AR_VERSION: 8.1.1
strategy:
fail-fast: false
matrix:
# https://ruby-lang.org/en/downloads/branches
ruby: ["3.4", "3.3", "3.2"]
# https://www.postgresql.org/support/versioning/
pg: [12-master, 13-master, 14-master, 15-master, 16-master]
pg: [14-master, 15-master, 16-master, 17-master, 18-3.6-alpine]
steps:
- name: Set Up Actions
uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ Make sure the tests pass:
Run tests with a specific ActiveRecord version:

```sh
AR_VERSION=7.0.1 bundle install
AR_VERSION=7.0.1 bundle exec rake test
AR_VERSION=8.1.0 bundle install
AR_VERSION=8.1.0 bundle exec rake test
```

To run a specific test, use the `POSTGIS_TEST_FILES` environment variable:
Expand Down
6 changes: 3 additions & 3 deletions activerecord-postgis-adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Gem::Specification.new do |spec|
spec.summary = "ActiveRecord adapter for PostGIS, based on RGeo."
spec.description =
"ActiveRecord connection adapter for PostGIS. It is based on the stock " \
"PostgreSQL adapter, and adds built-in support for the spatial extensions "\
"PostgreSQL adapter, and adds built-in support for the spatial extensions " \
"provided by PostGIS. It uses the RGeo library to represent spatial data in Ruby."

spec.version = ActiveRecord::ConnectionAdapters::PostGIS::VERSION
Expand All @@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
# ruby-lang.org/en/downloads/branches
spec.required_ruby_version = ">= 3.2.0"

spec.add_dependency "activerecord", "~> 8.0.0"
spec.add_dependency "rgeo-activerecord", "~> 8.0.0"
spec.add_dependency "activerecord", "~> 8.1.0"
spec.add_dependency "rgeo-activerecord", "~> 8.1.0"

spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "minitest", "~> 5.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
module ActiveRecord # :nodoc:
module ConnectionAdapters # :nodoc:
module PostGIS # :nodoc:
class SpatialColumn < ConnectionAdapters::PostgreSQLColumn # :nodoc:
class Column < PostgreSQL::Column # :nodoc:
# sql_type examples:
# "Geometry(Point,4326)"
# "Geography(Point,4326)"
def initialize(name, default, sql_type_metadata = nil, null = true,
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true,
default_function = nil, collation: nil, comment: nil,
serial: nil, generated: nil, spatial: nil, identity: nil)
@sql_type_metadata = sql_type_metadata
super(name, cast_type, default, sql_type_metadata, null, default_function,
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
@geographic = !!(sql_type_metadata.sql_type =~ /geography\(/i)
if spatial
# This case comes from an entry in the geometry_columns table
Expand All @@ -30,8 +31,6 @@ def initialize(name, default, sql_type_metadata = nil, null = true,
# @geometric_type = geo_type_from_sql_type(sql_type)
build_from_sql_type(sql_type_metadata.sql_type)
end
super(name, default, sql_type_metadata, null, default_function,
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
if spatial? && @srid
@limit = { srid: @srid, type: to_type_name(geometric_type) }
@limit[:has_z] = true if @has_z
Expand All @@ -58,6 +57,49 @@ def spatial?
%i[geometry geography].include?(@sql_type_metadata.type)
end

def init_with(coder)
@geographic = coder["geographic"]
@geometric_type = coder["geometric_type"]
@has_m = coder["has_m"]
@has_z = coder["has_z"]
@srid = coder["srid"]
@limit = coder["limit"]
super
end

def encode_with(coder)
coder["geographic"] = @geographic
coder["geometric_type"] = @geometric_type
coder["has_m"] = @has_m
coder["has_z"] = @has_z
coder["srid"] = @srid
coder["limit"] = @limit
super
end

def ==(other)
other.is_a?(Column) &&
super &&
other.geographic == geographic &&
other.geometric_type == geometric_type &&
other.has_m == has_m &&
other.has_z == has_z &&
other.srid == srid &&
other.limit == limit
end
alias :eql? :==

def hash
Column.hash ^
super.hash ^
geographic.hash ^
geometric_type.hash ^
has_m.hash ^
has_z.hash ^
srid.hash ^
limit.hash
end

private

def set_geometric_type_from_name(name)
Expand Down
43 changes: 24 additions & 19 deletions lib/active_record/connection_adapters/postgis/oid/spatial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ module OID
# Responsible for parsing sql_types returned from the database and WKT features.
class Spatial < Type::Value
def initialize(geo_type: "geometry", srid: 0, has_z: false, has_m: false, geographic: false)
@geo_type = geo_type
@srid = srid
@has_z = has_z
@has_m = has_m
@geographic = geographic
super()
@geographic = geographic.freeze
@factory_attrs = {
geo_type: geo_type.underscore.freeze,
has_m: has_m.freeze,
has_z: has_z.freeze,
srid: srid.freeze,
sql_type: type.to_s.freeze
}.freeze
end
protected attr_reader :geographic, :factory_attrs

# sql_type: geometry, geometry(Point), geometry(Point,4326), ...
#
Expand Down Expand Up @@ -53,10 +58,9 @@ def self.parse_sql_type(sql_type)
end

def spatial_factory
@spatial_factory ||=
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
factory_attrs
)
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
factory_attrs
)
end

def spatial?
Expand All @@ -80,6 +84,17 @@ def serialize(value)
.generate(geo_value)
end

def ==(other)
super &&
@geographic == other.geographic &&
@factory_attrs == other.factory_attrs
end
alias eql? ==

def hash
super ^ [@geographic, @factory_attrs].hash
end

private

def cast_value(value)
Expand All @@ -105,16 +120,6 @@ def wkt_parser(string)
RGeo::WKRep::WKTParser.new(spatial_factory, support_ewkt: true, default_srid: @srid)
end
end

def factory_attrs
{
geo_type: @geo_type.underscore,
has_m: @has_m,
has_z: @has_z,
srid: @srid,
sql_type: type.to_s
}
end
end
end
end
Expand Down
15 changes: 15 additions & 0 deletions lib/active_record/connection_adapters/postgis/quoting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ def type_cast(value)
super
end
end

# NOTE: This method should be private in future rails versions.
# Hence we should also make it private then.
#
# See https://github.com/rails/rails/blob/v8.1.1/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb#L190
def lookup_cast_type(sql_type)
type_map.lookup(
# oid
query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i,
# fmod, not needed.
nil,
# details needed for `..::PostGIS::OID::Spatial` (e.g. `geometry(point,3857)`)
sql_type
)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ def new_column_from_field(table_name, field, _definitions)
type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
default_value = extract_value_from_default(default)

if attgenerated.present?
default_function = default
else
default_function = extract_default_function(default_value, default)
end
default_function = if attgenerated.present?
default
else
extract_default_function(default_value, default)
end

if (match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/))
serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
Expand All @@ -25,8 +25,9 @@ def new_column_from_field(table_name, field, _definitions)
# {:dimension=>2, :has_m=>false, :has_z=>false, :name=>"latlon", :srid=>0, :type=>"GEOMETRY"}
spatial = spatial_column_info(table_name).get(column_name, type_metadata.sql_type)

SpatialColumn.new(
Column.new(
column_name,
get_oid_type(oid.to_i, fmod.to_i, column_name, type),
default_value,
type_metadata,
!notnull,
Expand Down
9 changes: 3 additions & 6 deletions lib/active_record/connection_adapters/postgis_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
require_relative "postgis/database_statements"
require_relative "postgis/spatial_column_info"
require_relative "postgis/spatial_table_definition"
require_relative "postgis/spatial_column"
require_relative "postgis/column"
require_relative "postgis/arel_tosql"
require_relative "postgis/oid/spatial"
require_relative "postgis/oid/date_time"
Expand Down Expand Up @@ -84,17 +84,15 @@ def initialize_type_map(map = type_map)
# "geometry(Polygon,4326) NOT NULL"
# "geometry(Geography,4326)"
geo_type, srid, has_z, has_m, geographic = PostGIS::OID::Spatial.parse_sql_type(sql_type)
PostGIS::OID::Spatial.new(geo_type: geo_type, srid: srid, has_z: has_z, has_m: has_m, geographic: geographic)
PostGIS::OID::Spatial.new(geo_type: geo_type, srid: srid, has_z: has_z, has_m: has_m, geographic: geographic).freeze
end
end

super
end

def native_database_types
@native_database_types ||= begin
default_types = PostgreSQLAdapter.native_database_types
default_types.merge({
@native_database_types ||= super.merge({
geography: { name: "geography" },
geometry: { name: "geometry" },
geometry_collection: { name: "geometry_collection" },
Expand All @@ -106,7 +104,6 @@ def native_database_types
st_point: { name: "st_point" },
st_polygon: { name: "st_polygon" }
})
end
end
end

Expand Down
2 changes: 2 additions & 0 deletions test/excludes/AssociationDeprecationTest/NotifyModeTest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require_relative "fix_backtrace_cleaner"
include(FixBacktraceCleaner)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require_relative "fix_backtrace_cleaner"
include(FixBacktraceCleaner)
2 changes: 2 additions & 0 deletions test/excludes/AssociationDeprecationTest/RaiseModeTest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require_relative "fix_backtrace_cleaner"
include(FixBacktraceCleaner)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require_relative "fix_backtrace_cleaner"
include(FixBacktraceCleaner)
2 changes: 2 additions & 0 deletions test/excludes/AssociationDeprecationTest/WarnModeTest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require_relative "fix_backtrace_cleaner"
include(FixBacktraceCleaner)
10 changes: 10 additions & 0 deletions test/excludes/AssociationDeprecationTest/fix_backtrace_cleaner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module FixBacktraceCleaner
def setup
super
bc = ActiveSupport::BacktraceCleaner.new
bc.remove_silencers!
bc.remove_filters!
bc.add_silencer { !_1.include?(::AssociationDeprecationTest::TestCase::THIS_FILE) }
ActiveRecord::LogSubscriber.backtrace_cleaner = bc
end
end
Loading