searchable-by 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 472133b9b419e573a1c87b721a5c368b3915ef28cb94e897424f55f7191f723f
4
- data.tar.gz: d3c31e307f54b0545171e7e12b86d75d32f5874676af467399fdb2e533927c16
3
+ metadata.gz: e3c6177e1001a078408b9466190f08df81a8dc812724903650ecd4a1b267fa09
4
+ data.tar.gz: 8c08713658466f75b21cac681a4dcce20bef6dc1544c4d7a935bb1eb285f54ea
5
5
  SHA512:
6
- metadata.gz: 1bd8dc39da51b94327d7912661cda9e2d38cdbf7d6e62eea1930e5d39a85c3bfd81c468477e8cfac48451b7dde055b9075a03686787c481c1cf2fcc5fa9d9c5f
7
- data.tar.gz: e9881b0f0022a0f884d6780afb3f24daf53872a473e22571f1eed730c8c76083148dbec4e99825875a68bb425568776c04fb7ac5d7ad26b1aa9202be3160d357
6
+ metadata.gz: f384f6380a8124c6a8a5f1591d54b14cbce6def8766cbe0271f43f023c98d0a6622f99f0ac22d7537b497ea59ea10ff7412b005729159d6d3cbc78908c00e8a6
7
+ data.tar.gz: ae93c1ce199d6a6315d579346ddff7c04dd1673782c85c130d9c17def56aa94d1873cb44333a53937d789e76683436641fd4187f1b26fd89327079d9857aefe7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- searchable-by (0.6.1)
4
+ searchable-by (0.7.0)
5
5
  activerecord
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -34,6 +34,14 @@ class Post < ActiveRecord::Base
34
34
  joins(:author)
35
35
  end
36
36
  end
37
+
38
+ # Multiple profiles can be defined. This one only searches title and metadata.
39
+ searchable_by :metadata do
40
+ column :title, match: :prefix
41
+
42
+ # Allow custom wildcard replacement using a match e.g. searching for `"My*Post"` will query `ILIKE 'My%Post'`.
43
+ column :metadata, match: :prefix, wildcard: '*'
44
+ end
37
45
  end
38
46
 
39
47
  # Search for 'alice'
@@ -44,4 +52,7 @@ Post.search_by('alice "pie recipe"')
44
52
 
45
53
  # Search for 'alice' but NOT for 'pie recipe'
46
54
  Post.search_by('alice -"pie recipe"')
55
+
56
+ # Search using metadata profile
57
+ Post.search_by('meta', profile: :metadata)
47
58
  ```
data/lib/searchable_by.rb CHANGED
@@ -4,6 +4,7 @@ module SearchableBy
4
4
  autoload :Column, 'searchable_by/column'
5
5
  autoload :Concern, 'searchable_by/concern'
6
6
  autoload :Config, 'searchable_by/config'
7
+ autoload :Profiles, 'searchable_by/profiles'
7
8
  autoload :Util, 'searchable_by/util'
8
9
 
9
10
  Value = Struct.new(:term, :negate, :phrase)
@@ -1,22 +1,19 @@
1
1
  module SearchableBy
2
2
  class Column
3
+ VALID_MATCH_TYPES = %i[all prefix exact].freeze
4
+
3
5
  attr_reader :attr, :type, :match, :match_phrase, :wildcard
4
6
  attr_accessor :node
5
7
 
6
- def initialize(attr, type: :string, match: :all, match_phrase: nil, wildcard: nil, **opts) # rubocop:disable Metrics/ParameterLists
7
- if opts.key?(:min_length)
8
- ActiveSupport::Deprecation.warn(
9
- 'Setting min_length for individual columns is deprecated and will be removed in the next release.' \
10
- 'Please pass it as an option to searchable_by instead',
11
- )
12
- end
13
-
8
+ def initialize(attr, type: :string, match: :all, match_phrase: nil, wildcard: nil)
14
9
  @attr = attr
15
10
  @type = type.to_sym
16
11
  @match = match
17
12
  @match_phrase = match_phrase || match
18
- @min_length = opts[:min_length].to_i
19
13
  @wildcard = wildcard
14
+
15
+ raise ArgumentError, "invalid match option #{@match.inspect}" unless VALID_MATCH_TYPES.include? @match
16
+ raise ArgumentError, "invalid match_phrase option #{@match_phrase.inspect}" unless VALID_MATCH_TYPES.include? @match_phrase
20
17
  end
21
18
 
22
19
  def build_condition(value)
@@ -32,11 +29,6 @@ module SearchableBy
32
29
 
33
30
  private
34
31
 
35
- # TODO: remove when removing min_length option from columns
36
- def usable?(value)
37
- value.term.length >= @min_length
38
- end
39
-
40
32
  def int_condition(scope, value)
41
33
  scope.and(node.eq(Integer(value.term)))
42
34
  rescue ArgumentError
@@ -49,11 +41,13 @@ module SearchableBy
49
41
 
50
42
  case type
51
43
  when :exact
52
- term.downcase!
53
- scope.and(node.lower.eq(term))
54
- when :full
55
- escape_term!(term)
56
- scope.and(node.matches(term))
44
+ if wildcard
45
+ escape_term!(term)
46
+ scope.and(node.matches(term))
47
+ else
48
+ term.downcase!
49
+ scope.and(node.lower.eq(term))
50
+ end
57
51
  when :prefix
58
52
  escape_term!(term)
59
53
  scope.and(node.matches("#{term}%"))
@@ -1,28 +1,25 @@
1
1
  module SearchableBy
2
2
  module Concern
3
3
  def self.extended(base) # :nodoc:
4
- base.class_attribute :_searchable_by_config, instance_accessor: false, instance_predicate: false
5
- base._searchable_by_config = Config.new
4
+ base.class_attribute :_searchable_by_profiles, instance_accessor: false, instance_predicate: false
5
+ base._searchable_by_profiles = Profiles.new
6
6
  super
7
7
  end
8
8
 
9
9
  def inherited(base) # :nodoc:
10
- base._searchable_by_config = _searchable_by_config.dup
10
+ base._searchable_by_profiles = _searchable_by_profiles.dup
11
11
  super
12
12
  end
13
13
 
14
- def searchable_by(max_terms: nil, min_length: 0, **options, &block)
15
- _searchable_by_config.instance_eval(&block)
16
- _searchable_by_config.max_terms = max_terms if max_terms
17
- _searchable_by_config.min_length = min_length
18
- _searchable_by_config.options.update(options) unless options.empty?
19
- _searchable_by_config
14
+ def searchable_by(profile = :default, max_terms: nil, min_length: 0, **options, &block)
15
+ _searchable_by_profiles[profile].configure(max_terms, min_length, **options, &block)
16
+ _searchable_by_profiles
20
17
  end
21
18
 
22
19
  # @param [String] query the search query
23
20
  # @return [ActiveRecord::Relation] the scoped relation
24
- def search_by(query)
25
- config = _searchable_by_config
21
+ def search_by(query, profile: :default)
22
+ config = _searchable_by_profiles[profile]
26
23
  columns = config.columns
27
24
  return all if columns.empty?
28
25
 
@@ -11,6 +11,13 @@ module SearchableBy
11
11
  scope { all }
12
12
  end
13
13
 
14
+ def configure(max_terms, min_length, **options, &block)
15
+ instance_eval(&block)
16
+ self.max_terms = max_terms if max_terms
17
+ self.min_length = min_length
18
+ self.options.update(options) unless options.empty?
19
+ end
20
+
14
21
  def initialize_copy(other)
15
22
  @columns = other.columns.dup
16
23
  super
@@ -0,0 +1,23 @@
1
+ module SearchableBy
2
+ class Profiles
3
+ def initialize
4
+ @profiles = {}
5
+ end
6
+
7
+ def [](name)
8
+ name = name.to_sym
9
+ @profiles[name] ||= Config.new
10
+ end
11
+
12
+ def each(&block)
13
+ @profiles.each(&block)
14
+ end
15
+
16
+ def initialize_copy(other)
17
+ @profiles = {}
18
+ other.each do |name, config|
19
+ @profiles[name] = config.dup
20
+ end
21
+ end
22
+ end
23
+ end
@@ -29,12 +29,6 @@ module SearchableBy
29
29
 
30
30
  def self.build_clauses(columns, values)
31
31
  values.map do |value|
32
- # TODO: remove when removing min_length option from columns
33
- usable = columns.all? do |column|
34
- column.send(:usable?, value)
35
- end
36
- next unless usable
37
-
38
32
  group = columns.map do |column|
39
33
  column.build_condition(value)
40
34
  end.tap(&:compact!)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'searchable-by'
3
- s.version = '0.6.1'
3
+ s.version = '0.7.0'
4
4
  s.authors = ['Dimitrij Denissenko']
5
5
  s.email = ['dimitrij@blacksquaremedia.com']
6
6
  s.summary = 'Generate search scopes'
@@ -7,8 +7,8 @@ describe SearchableBy do
7
7
  end
8
8
 
9
9
  it 'configures correctly' do
10
- expect(AbstractModel._searchable_by_config.columns.size).to eq(1)
11
- expect(Post._searchable_by_config.columns.size).to eq(6)
10
+ expect(AbstractModel._searchable_by_profiles[:default].columns.size).to eq(1)
11
+ expect(Post._searchable_by_profiles[:default].columns.size).to eq(6)
12
12
  end
13
13
 
14
14
  it 'generates SQL' do
@@ -93,9 +93,14 @@ describe SearchableBy do
93
93
  expect(Post.search_by(POSTS[:ab1].id.to_s).count).to eq(1)
94
94
  end
95
95
 
96
- it 'supports wildcard searching' do
96
+ it 'supports wildcards' do
97
97
  expect(User.search_by('*uni*dom')).to match_array(USERS.values_at(:a))
98
98
  expect(User.search_by('*uni*o*')).to match_array(USERS.values_at(:a, :b))
99
99
  expect(User.search_by('*uni*of*dom')).to be_empty
100
100
  end
101
+
102
+ it 'supports profiles' do
103
+ expect(User.search_by('king', profile: :country_only)).to match_array(USERS.values_at(:a))
104
+ expect(User.search_by('Norris', profile: :country_only)).to be_empty
105
+ end
101
106
  end
data/spec/spec_helper.rb CHANGED
@@ -32,7 +32,11 @@ class User < AbstractModel
32
32
 
33
33
  searchable_by min_length: 3 do
34
34
  column :bio
35
- column :country, wildcard: '*', match: :full
35
+ column :country, wildcard: '*', match: :exact
36
+ end
37
+
38
+ searchable_by :country_only do
39
+ column :country
36
40
  end
37
41
  end
38
42
 
@@ -44,7 +48,7 @@ class Post < AbstractModel
44
48
  column :title, match: :prefix, match_phrase: :exact
45
49
  column :body
46
50
  column proc { User.arel_table[:name] }, match: :exact
47
- column proc { User.arel_table[:country] }, wildcard: '*', match: :full
51
+ column proc { User.arel_table[:country] }, wildcard: '*', match: :exact
48
52
  column { User.arel_table.alias('reviewers_posts')[:name] }
49
53
 
50
54
  scope do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchable-by
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-30 00:00:00.000000000 Z
11
+ date: 2021-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -128,6 +128,7 @@ files:
128
128
  - lib/searchable_by/column.rb
129
129
  - lib/searchable_by/concern.rb
130
130
  - lib/searchable_by/config.rb
131
+ - lib/searchable_by/profiles.rb
131
132
  - lib/searchable_by/util.rb
132
133
  - searchable-by.gemspec
133
134
  - spec/searchable_by/util_spec.rb