From 680289fefc57758a4dcd38301d6e59a829c064b0 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 12 Mar 2023 07:56:39 -0400 Subject: [PATCH 1/4] add support for a ilike search feature --- lib/pg_search/features.rb | 1 + lib/pg_search/features/ilike.rb | 29 ++++++++++++++++ lib/pg_search/scope_options.rb | 1 + spec/lib/pg_search/features/ilike_spec.rb | 41 +++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 lib/pg_search/features/ilike.rb create mode 100644 spec/lib/pg_search/features/ilike_spec.rb diff --git a/lib/pg_search/features.rb b/lib/pg_search/features.rb index b95cbd50..89ad48f1 100644 --- a/lib/pg_search/features.rb +++ b/lib/pg_search/features.rb @@ -3,6 +3,7 @@ require "pg_search/features/feature" require "pg_search/features/dmetaphone" +require "pg_search/features/ilike" require "pg_search/features/trigram" require "pg_search/features/tsearch" diff --git a/lib/pg_search/features/ilike.rb b/lib/pg_search/features/ilike.rb new file mode 100644 index 00000000..f480569a --- /dev/null +++ b/lib/pg_search/features/ilike.rb @@ -0,0 +1,29 @@ +module PgSearch + module Features + class ILike < Feature + def conditions + Arel::Nodes::Grouping.new( + Arel::Nodes::InfixOperation.new( + 'ILIKE', + normalized_document, + normalized_query + ) + ) + end + + def rank + Arel::Nodes::Grouping.new(Arel.sql('0')) # no ranking or delegate to tsearch like DMetaphone? + end + + private + + def normalized_query + Arel.sql(connection.quote("%#{query}%")) + end + + def normalized_document + Arel::Nodes::Grouping.new(Arel.sql(document)) + end + end + end +end diff --git a/lib/pg_search/scope_options.rb b/lib/pg_search/scope_options.rb index 6fe515dd..24c97177 100644 --- a/lib/pg_search/scope_options.rb +++ b/lib/pg_search/scope_options.rb @@ -135,6 +135,7 @@ def subquery_join FEATURE_CLASSES = { dmetaphone: Features::DMetaphone, + ilike: Features::ILike, tsearch: Features::TSearch, trigram: Features::Trigram }.freeze diff --git a/spec/lib/pg_search/features/ilike_spec.rb b/spec/lib/pg_search/features/ilike_spec.rb new file mode 100644 index 00000000..a72ad780 --- /dev/null +++ b/spec/lib/pg_search/features/ilike_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "spec_helper" +require "ostruct" + +# rubocop:disable RSpec/MultipleMemoizedHelpers, RSpec/NestedGroups +describe PgSearch::Features::ILike do + subject(:feature) { described_class.new(query, options, columns, Model, normalizer) } + + let(:query) { "lolwut" } + let(:options) { {} } + let(:columns) { + [ + PgSearch::Configuration::Column.new(:name, nil, Model), + PgSearch::Configuration::Column.new(:content, nil, Model) + ] + } + let(:normalizer) { PgSearch::Normalizer.new(config) } + let(:config) { OpenStruct.new(ignore: []) } + + let(:coalesced_columns) do + <<~SQL.squish + coalesce(#{Model.quoted_table_name}."name"::text, '') + || ' ' + || coalesce(#{Model.quoted_table_name}."content"::text, '') + SQL + end + + with_model :Model do + table do |t| + t.string :name + t.string :content + end + end + + describe "conditions" do + it "escapes the search document and query" do + expect(feature.conditions.to_sql).to eq("((#{coalesced_columns}) ILIKE '%#{query}%')") + end + end +end \ No newline at end of file From 00a42c8db13b38d4a0dce1eff178b721613ab429 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 24 Mar 2023 13:51:32 -0400 Subject: [PATCH 2/4] update readme --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4ccf1562..1d654f82 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ end * [`:trigram` (Trigram search)](#trigram-trigram-search) * [`:threshold`](#threshold) * [`:word_similarity`](#word_similarity) + * [`:ilike` (Basic Search)](#ilike-basic-search) * [Limiting Fields When Combining Features](#limiting-fields-when-combining-features) * [Ignoring accent marks](#ignoring-accent-marks) * [Using tsvector columns](#using-tsvector-columns) @@ -548,7 +549,7 @@ search techniques. ```ruby class Beer < ActiveRecord::Base include PgSearch::Model - pg_search_scope :search_name, against: :name, using: [:tsearch, :trigram, :dmetaphone] + pg_search_scope :search_name, against: :name, using: [:tsearch, :trigram, :dmetaphone, :ilike] end ``` @@ -562,7 +563,8 @@ class Beer < ActiveRecord::Base using: { :trigram => {}, :dmetaphone => {}, - :tsearch => { :prefix => true } + :tsearch => { :prefix => true }, + :ilike => {} } end ``` @@ -573,6 +575,7 @@ The currently implemented features are * :trigram - [Trigram search](http://www.postgresql.org/docs/current/static/pgtrgm.html), which requires the trigram extension * :dmetaphone - [Double Metaphone search](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html#AEN177521), which requires the fuzzystrmatch extension +* :iliek - Basic search using built in ilike operator #### :tsearch (Full Text Search) @@ -976,6 +979,22 @@ Sentence.similarity_like("word") # => [] Sentence.word_similarity_like("word") # => [sentence] ``` +### :ilike (Basic Search) + +Basic search using ilike. This will look for anything containing an exact match, ie `%QUERY%`. This is useful in situations where you are looking for a substring. + +```ruby +class Company < ActiveRecord::Base + include PgSearch::Model + pg_search_scope :find_substring, + against: :name, + using: :ilike +end + +macrohard = Company.create! name: "MacroHard" +Website.find_substring("hard") # => [macrohard] +``` + ### Limiting Fields When Combining Features Sometimes when doing queries combining different features you From b5cf476ca044984ef1c8b466d98e4708c962613e Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 13 Apr 2023 21:16:41 -0400 Subject: [PATCH 3/4] updates for rubocop --- lib/pg_search/features/ilike.rb | 4 ++-- .../features/{ilike_spec.rb => i_like_spec.rb} | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) rename spec/lib/pg_search/features/{ilike_spec.rb => i_like_spec.rb} (81%) diff --git a/lib/pg_search/features/ilike.rb b/lib/pg_search/features/ilike.rb index f480569a..39667a50 100644 --- a/lib/pg_search/features/ilike.rb +++ b/lib/pg_search/features/ilike.rb @@ -4,7 +4,7 @@ class ILike < Feature def conditions Arel::Nodes::Grouping.new( Arel::Nodes::InfixOperation.new( - 'ILIKE', + "ILIKE", normalized_document, normalized_query ) @@ -12,7 +12,7 @@ def conditions end def rank - Arel::Nodes::Grouping.new(Arel.sql('0')) # no ranking or delegate to tsearch like DMetaphone? + Arel::Nodes::Grouping.new(Arel.sql("0")) # no ranking or delegate to tsearch like DMetaphone? end private diff --git a/spec/lib/pg_search/features/ilike_spec.rb b/spec/lib/pg_search/features/i_like_spec.rb similarity index 81% rename from spec/lib/pg_search/features/ilike_spec.rb rename to spec/lib/pg_search/features/i_like_spec.rb index a72ad780..9afd1ba7 100644 --- a/spec/lib/pg_search/features/ilike_spec.rb +++ b/spec/lib/pg_search/features/i_like_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" require "ostruct" -# rubocop:disable RSpec/MultipleMemoizedHelpers, RSpec/NestedGroups +# rubocop:disable RSpec/MultipleMemoizedHelpers describe PgSearch::Features::ILike do subject(:feature) { described_class.new(query, options, columns, Model, normalizer) } @@ -38,4 +38,11 @@ expect(feature.conditions.to_sql).to eq("((#{coalesced_columns}) ILIKE '%#{query}%')") end end -end \ No newline at end of file + + describe "#rank" do + it "doesn't do different ranks" do + expect(feature.rank.to_sql).to eq("(0)") + end + end +end +# rubocop:enable RSpec/MultipleMemoizedHelpers From 90575a8648b5bfa188d462a90f9d8892dcd9dcee Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 3 Oct 2023 15:06:11 -0400 Subject: [PATCH 4/4] typo Co-authored-by: Sandra <56364494+skuo-gh@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d654f82..9274c089 100644 --- a/README.md +++ b/README.md @@ -575,7 +575,7 @@ The currently implemented features are * :trigram - [Trigram search](http://www.postgresql.org/docs/current/static/pgtrgm.html), which requires the trigram extension * :dmetaphone - [Double Metaphone search](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html#AEN177521), which requires the fuzzystrmatch extension -* :iliek - Basic search using built in ilike operator +* :ilike - Basic search using built in ilike operator #### :tsearch (Full Text Search)