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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +11 -0
- data/lib/searchable_by.rb +1 -0
- data/lib/searchable_by/column.rb +13 -19
- data/lib/searchable_by/concern.rb +8 -11
- data/lib/searchable_by/config.rb +7 -0
- data/lib/searchable_by/profiles.rb +23 -0
- data/lib/searchable_by/util.rb +0 -6
- data/searchable-by.gemspec +1 -1
- data/spec/searchable_by_spec.rb +8 -3
- data/spec/spec_helper.rb +6 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3c6177e1001a078408b9466190f08df81a8dc812724903650ecd4a1b267fa09
|
4
|
+
data.tar.gz: 8c08713658466f75b21cac681a4dcce20bef6dc1544c4d7a935bb1eb285f54ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f384f6380a8124c6a8a5f1591d54b14cbce6def8766cbe0271f43f023c98d0a6622f99f0ac22d7537b497ea59ea10ff7412b005729159d6d3cbc78908c00e8a6
|
7
|
+
data.tar.gz: ae93c1ce199d6a6315d579346ddff7c04dd1673782c85c130d9c17def56aa94d1873cb44333a53937d789e76683436641fd4187f1b26fd89327079d9857aefe7
|
data/Gemfile.lock
CHANGED
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)
|
data/lib/searchable_by/column.rb
CHANGED
@@ -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
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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 :
|
5
|
-
base.
|
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.
|
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
|
-
|
16
|
-
|
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 =
|
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
|
|
data/lib/searchable_by/config.rb
CHANGED
@@ -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
|
data/lib/searchable_by/util.rb
CHANGED
@@ -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!)
|
data/searchable-by.gemspec
CHANGED
data/spec/searchable_by_spec.rb
CHANGED
@@ -7,8 +7,8 @@ describe SearchableBy do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'configures correctly' do
|
10
|
-
expect(AbstractModel.
|
11
|
-
expect(Post.
|
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
|
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: :
|
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: :
|
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.
|
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-
|
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
|