From 374911332b1b04b2faaab44b6dce056c555eedb8 Mon Sep 17 00:00:00 2001 From: Nikolai B Date: Sun, 3 Nov 2024 13:59:06 +0000 Subject: [PATCH] Fix sql sanitization of multi geoms --- lib/rgeo/active_record.rb | 1 + .../active_record/multi_geom_sanitization.rb | 17 +++++++++++++++++ test/basic_test.rb | 10 ++++++++++ test/support/fake_record.rb | 10 ++++++++++ test/test_helper.rb | 1 + 5 files changed, 39 insertions(+) create mode 100644 lib/rgeo/active_record/multi_geom_sanitization.rb diff --git a/lib/rgeo/active_record.rb b/lib/rgeo/active_record.rb index 86d001e..a4555cd 100644 --- a/lib/rgeo/active_record.rb +++ b/lib/rgeo/active_record.rb @@ -9,3 +9,4 @@ require_relative "active_record/arel_spatial_queries" require_relative "active_record/common_adapter_elements" require_relative "active_record/geometry_mixin" +require_relative "active_record/multi_geom_sanitization" diff --git a/lib/rgeo/active_record/multi_geom_sanitization.rb b/lib/rgeo/active_record/multi_geom_sanitization.rb new file mode 100644 index 0000000..075d803 --- /dev/null +++ b/lib/rgeo/active_record/multi_geom_sanitization.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +require 'active_support/core_ext/array/wrap' + +module MultiGeomSanitization + private + + # NOTE connection and value order is swapped in Rails 8 + def replace_bind_variable(connection, value) + if value.class.name.start_with?("RGeo::") && value.respond_to?(:map) + super(connection, Array.wrap(value)) + else + super + end + end +end + +ActiveRecord::Sanitization::ClassMethods.prepend(MultiGeomSanitization) diff --git a/test/basic_test.rb b/test/basic_test.rb index c40f577..9b0c433 100644 --- a/test/basic_test.rb +++ b/test/basic_test.rb @@ -124,6 +124,16 @@ def test_arel_visit_RGeo_ActiveRecord_SpatialNamedFunction_with_distinct assert_equal("SPATIAL_FUNC(DISTINCT ST_GeomFromText('POINT (1.0 2.0)'), ST_GeomFromText('LINESTRING (1.0 2.0, 2.0 3.0)'))", sql.value) end + def test_multi_geom_sanitization + multi_geom = RGeo::Geos.factory.parse_wkt("MULTIPOLYGON (((0 0, 0 1, 1 1, 0 0)),((1 1, 0 0, 0 1, 1 1)))") + sql = "ST_DWithin(geom, :geom, :buffer)" + + assert_equal( + "ST_DWithin(geom, 'MULTIPOLYGON (((0 0, 0 1, 1 1, 0 0)), ((1 1, 0 0, 0 1, 1 1)))', '10')", + FakeRecord::Base.sanitize_sql([ sql, geom: multi_geom, buffer: 10 ]) + ) + end + private def arel_visitor diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 2e29671..75eb44d 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -88,6 +88,10 @@ def quote(thing, column = nil) "'#{thing.to_s.gsub("'", "\\\\'")}'" end end + + def cast_bound_value(value) + value.to_s + end end class ConnectionPool @@ -123,8 +127,14 @@ def quote(thing, column = nil) end class Base + include ActiveRecord::Sanitization + attr_accessor :connection_pool + def self.with_connection + yield new.connection + end + def initialize @connection_pool = ConnectionPool.new end diff --git a/test/test_helper.rb b/test/test_helper.rb index 83e0c80..7590de7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -9,6 +9,7 @@ require "minitest/autorun" require "rgeo-activerecord" require "support/fake_record" +require "active_support/core_ext/date/acts_like" Arel::Visitors::ToSql.include RGeo::ActiveRecord::SpatialToSql Arel::Table.engine = FakeRecord::Base.new