diff --git a/.github/workflows/cronjob.yml b/.github/workflows/cronjob.yml index 941d3a5b..32f6c718 100644 --- a/.github/workflows/cronjob.yml +++ b/.github/workflows/cronjob.yml @@ -56,6 +56,48 @@ jobs: - name: Run tests run: bundle exec rspec + postgis: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + ruby: + - 3.2.2 + env: + DB: postgis + RAILS: main + DATABASE_USERNAME: postgres + DATABASE_PASSWORD: postgres + DATABASE_HOST: 127.0.0.1 + services: + postgres: + image: postgres + ports: + - 5432:5432 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_HOST_AUTH_METHOD: trust + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + - name: Setup databases + run: | + psql -h localhost -p 5432 -W postgres -c 'create database ransack;' -U postgres; + - name: Install dependencies + run: bundle install + - name: Run tests + run: bundle exec rspec + postgres: runs-on: ubuntu-22.04 strategy: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0025eb93..0b7f7a3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,6 +68,53 @@ jobs: - name: Run tests run: bundle exec rspec + postgis: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + rails: + - 7-2-stable + - v7.1.0 + - v7.0.3 + - v6.1.6 + ruby: + - 3.2.2 + - 3.1.4 + env: + DB: postgis + RAILS: ${{ matrix.rails }} + DATABASE_USERNAME: postgres + DATABASE_PASSWORD: postgres + DATABASE_HOST: 127.0.0.1 + services: + postgres: + image: postgres + ports: + - 5432:5432 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_HOST_AUTH_METHOD: trust + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Setup databases + run: | + psql -h localhost -p 5432 -W postgres -c 'create database ransack;' -U postgres; + - name: Run tests + run: bundle exec rspec + postgres: runs-on: ubuntu-22.04 strategy: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dee586f..98a801e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Fix wildcard escaping with PostGIS adapter. + ## 4.2.1 - 2024-8-11 * Fix Rails 7.1.x compatibility diff --git a/Gemfile b/Gemfile index 695a117e..700c9d19 100644 --- a/Gemfile +++ b/Gemfile @@ -17,6 +17,7 @@ rails_version = case rails gem 'faker' gem 'sqlite3', '~> 1.4' gem 'pg' +gem 'activerecord-postgis-adapter' gem 'pry' gem 'byebug' diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index 9202b4b0..027e87be 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -165,7 +165,7 @@ def escape_wildcards(unescaped) when "Mysql2".freeze # Necessary for MySQL unescaped.to_s.gsub(/([\\%_])/, '\\\\\\1') - when "PostgreSQL".freeze + when "PostGIS".freeze, "PostgreSQL".freeze # Necessary for PostgreSQL unescaped.to_s.gsub(/([\\%_.])/, '\\\\\\1') else diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index ae0972d9..4b243456 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -158,9 +158,10 @@ module Ransack describe 'cont' do it_has_behavior 'wildcard escaping', :name_cont, - (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + (case ActiveRecord::Base.connection.adapter_name + when "PostGIS", "PostgreSQL" /"people"."name" ILIKE '%\\%\\.\\_\\\\%'/ - elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + when "Mysql2" /`people`.`name` LIKE '%\\\\%.\\\\_\\\\\\\\%'/ else /"people"."name" LIKE '%%._\\%'/ @@ -177,9 +178,10 @@ module Ransack describe 'not_cont' do it_has_behavior 'wildcard escaping', :name_not_cont, - (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + (case ActiveRecord::Base.connection.adapter_name + when "PostGIS", "PostgreSQL" /"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/ - elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + when "Mysql2" /`people`.`name` NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/ else /"people"."name" NOT LIKE '%%._\\%'/ @@ -196,9 +198,12 @@ module Ransack describe 'i_cont' do it_has_behavior 'wildcard escaping', :name_i_cont, - (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + (case ActiveRecord::Base.connection.adapter_name + when "PostGIS" + /LOWER\("people"."name"\) ILIKE '%\\%\\.\\_\\\\%'/ + when "PostgreSQL" /"people"."name" ILIKE '%\\%\\.\\_\\\\%'/ - elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + when "Mysql2" /LOWER\(`people`.`name`\) LIKE '%\\\\%.\\\\_\\\\\\\\%'/ else /LOWER\("people"."name"\) LIKE '%%._\\%'/ @@ -215,9 +220,12 @@ module Ransack describe 'not_i_cont' do it_has_behavior 'wildcard escaping', :name_not_i_cont, - (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + (case ActiveRecord::Base.connection.adapter_name + when "PostGIS" + /LOWER\("people"."name"\) NOT ILIKE '%\\%\\.\\_\\\\%'/ + when "PostgreSQL" /"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/ - elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + when "Mysql2" /LOWER\(`people`.`name`\) NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/ else /LOWER\("people"."name"\) NOT LIKE '%%._\\%'/ diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 555299c4..f51abc50 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -1,4 +1,5 @@ require 'active_record' +require 'activerecord-postgis-adapter' case ENV['DB'].try(:downcase) when 'mysql', 'mysql2' @@ -20,6 +21,17 @@ host: ENV.fetch("DATABASE_HOST") { "localhost" }, min_messages: 'warning' ) +when 'postgis' + # To test with PostGIS: `DB=postgis bundle exec rake spec` + ActiveRecord::Base.establish_connection( + adapter: 'postgis', + postgis_extension: 'postgis', + database: 'ransack', + username: ENV.fetch("DATABASE_USERNAME") { "postgres" }, + password: ENV.fetch("DATABASE_PASSWORD") { "" }, + host: ENV.fetch("DATABASE_HOST") { "localhost" }, + min_messages: 'warning' + ) else # Otherwise, assume SQLite3: `bundle exec rake spec` ActiveRecord::Base.establish_connection(