diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c5533b..199a2fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,11 @@ Each change should fall into categories that would affect whether the release is As such, _Breaking Changes_ are major. _Features_ would map to either major or minor. _Fixes_, _Performance_, and _Misc_ are either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding _Documentation_ (including tests) would be patch level. -### [v9.0.1) / 2022-01-07](https://github.com/mbleigh/acts-as-taggable-on/compare/v8.1.0...v9.0.0) +### [v9.0.2) / unreleased](https://github.com/mbleigh/acts-as-taggable-on/compare/v9.0.1...master) +* Features + * [@glampr Add support for prefix and suffix searches alongside previously supported containment (wildcard) searches](https://github.com/mbleigh/acts-as-taggable-on/pull/1082) + +### [v9.0.1) / 2022-01-07](https://github.com/mbleigh/acts-as-taggable-on/compare/v9.0.0..v9.0.1) * Fixes * Fix migration that generate default index diff --git a/README.md b/README.md index f292f6d7..685e0cca 100644 --- a/README.md +++ b/README.md @@ -255,7 +255,11 @@ User.tagged_with(["awesome", "cool"], :exclude => true) User.tagged_with(['awesome', 'cool'], :on => :tags, :any => true).tagged_with(['smart', 'shy'], :on => :skills, :any => true) ``` -You can also use `:wild => true` option along with `:any` or `:exclude` option. It will be looking for `%awesome%` and `%cool%` in SQL. +#### Wildcard tag search +You now have the following options for prefix, suffix and containment search, along with `:any` or `:exclude` option. +Use `wild: :suffix` to place a wildcard at the end of the tag. It will be looking for `awesome%` and `cool%` in SQL. +Use `wild: :prefix` to place a wildcard at the beginning of the tag. It will be looking for `%awesome` and `%cool` in SQL. +Use `wild: true` to place a wildcard both at the beginning and the end of the tag. It will be looking for `%awesome%` and `%cool%` in SQL. __Tip:__ `User.tagged_with([])` or `User.tagged_with('')` will return `[]`, an empty set of records. diff --git a/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb b/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb index 8c7f09f8..d0ede626 100644 --- a/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb +++ b/lib/acts_as_taggable_on/taggable/tagged_with_query/query_base.rb @@ -32,26 +32,16 @@ def tag_match_type(tag) matches_attribute = tag_arel_table[:name] matches_attribute = matches_attribute.lower unless ActsAsTaggableOn.strict_case_match - if options[:wild].present? - matches_attribute.matches("%#{escaped_tag(tag)}%", '!', ActsAsTaggableOn.strict_case_match) - else - matches_attribute.matches(escaped_tag(tag), '!', ActsAsTaggableOn.strict_case_match) - end + matches_attribute.matches(wildcard_escaped_tag(tag), '!', ActsAsTaggableOn.strict_case_match) end def tags_match_type matches_attribute = tag_arel_table[:name] matches_attribute = matches_attribute.lower unless ActsAsTaggableOn.strict_case_match - if options[:wild].present? - matches_attribute.matches_any(tag_list.map do |tag| - "%#{escaped_tag(tag)}%" - end, '!', ActsAsTaggableOn.strict_case_match) - else - matches_attribute.matches_any(tag_list.map do |tag| - escaped_tag(tag).to_s - end, '!', ActsAsTaggableOn.strict_case_match) - end + matches_attribute.matches_any(tag_list.map do |tag| + wildcard_escaped_tag(tag).to_s + end, '!', ActsAsTaggableOn.strict_case_match) end def escaped_tag(tag) @@ -59,6 +49,15 @@ def escaped_tag(tag) ActsAsTaggableOn::Utils.escape_like(tag) end + def wildcard_escaped_tag(tag) + case options[:wild] + when :suffix then "#{escaped_tag(tag)}%" + when :prefix then "%#{escaped_tag(tag)}" + when true then "%#{escaped_tag(tag)}%" + else escaped_tag(tag) + end + end + def adjust_taggings_alias(taggings_alias) taggings_alias = "taggings_alias_#{Digest::SHA1.hexdigest(taggings_alias)}" if taggings_alias.size > 75 taggings_alias diff --git a/spec/acts_as_taggable_on/taggable_spec.rb b/spec/acts_as_taggable_on/taggable_spec.rb index e9fd6cfd..39766423 100644 --- a/spec/acts_as_taggable_on/taggable_spec.rb +++ b/spec/acts_as_taggable_on/taggable_spec.rb @@ -480,6 +480,10 @@ jim = TaggableModel.create(name: 'Jim', tag_list: 'jim, steve') expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve]) + expect(TaggableModel.tagged_with(%w(bob tricia), wild: :prefix, any: true).to_a.sort_by { |o| o.id }).to eq([bob, steve]) + expect(TaggableModel.tagged_with(%w(bob tricia), wild: :suffix, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank]) + expect(TaggableModel.tagged_with(%w(cia), wild: :prefix, any: true).to_a.sort_by { |o| o.id }).to eq([bob, steve]) + expect(TaggableModel.tagged_with(%w(j), wild: :suffix, any: true).to_a.sort_by { |o| o.id }).to eq([frank, steve, jim]) expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, exclude: true).to_a).to eq([jim]) expect(TaggableModel.tagged_with('ji', wild: true, any: true).to_a).to match_array([frank, jim]) end