searchable-by 0.5.7 → 0.6.1
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/.github/workflows/test.yml +21 -0
- data/.rubocop.yml +7 -8
- data/Gemfile.lock +33 -31
- data/README.md +7 -4
- data/lib/searchable_by/column.rb +28 -7
- data/lib/searchable_by/concern.rb +6 -4
- data/lib/searchable_by/config.rb +2 -1
- data/lib/searchable_by/util.rb +15 -12
- data/searchable-by.gemspec +4 -8
- data/spec/searchable_by/util_spec.rb +3 -2
- data/spec/searchable_by_spec.rb +30 -1
- data/spec/spec_helper.rb +10 -2
- metadata +7 -49
- data/.travis.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 472133b9b419e573a1c87b721a5c368b3915ef28cb94e897424f55f7191f723f
|
4
|
+
data.tar.gz: d3c31e307f54b0545171e7e12b86d75d32f5874676af467399fdb2e533927c16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bd8dc39da51b94327d7912661cda9e2d38cdbf7d6e62eea1930e5d39a85c3bfd81c468477e8cfac48451b7dde055b9075a03686787c481c1cf2fcc5fa9d9c5f
|
7
|
+
data.tar.gz: e9881b0f0022a0f884d6780afb3f24daf53872a473e22571f1eed730c8c76083148dbec4e99825875a68bb425568776c04fb7ac5d7ad26b1aa9202be3160d357
|
@@ -0,0 +1,21 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [main]
|
6
|
+
pull_request:
|
7
|
+
branches: [main]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
ruby:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ["2.6", "2.7", "3.0"]
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.ruby-version }}
|
20
|
+
bundler-cache: true
|
21
|
+
- run: bundle exec rake
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
- https://gitlab.com/bsm/misc/raw/master/rubocop/default.yml
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-bsm:
|
3
|
+
- default.yml
|
4
|
+
inherit_mode:
|
5
|
+
merge:
|
6
|
+
- Exclude
|
8
7
|
|
9
8
|
AllCops:
|
10
|
-
TargetRubyVersion: "2.
|
9
|
+
TargetRubyVersion: "2.6"
|
11
10
|
|
12
11
|
Naming/FileName:
|
13
12
|
Exclude:
|
data/Gemfile.lock
CHANGED
@@ -1,37 +1,36 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
searchable-by (0.
|
4
|
+
searchable-by (0.6.1)
|
5
5
|
activerecord
|
6
|
-
activesupport
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: http://rubygems.org/
|
10
9
|
specs:
|
11
|
-
activemodel (6.1.
|
12
|
-
activesupport (= 6.1.
|
13
|
-
activerecord (6.1.
|
14
|
-
activemodel (= 6.1.
|
15
|
-
activesupport (= 6.1.
|
16
|
-
activesupport (6.1.
|
10
|
+
activemodel (6.1.4)
|
11
|
+
activesupport (= 6.1.4)
|
12
|
+
activerecord (6.1.4)
|
13
|
+
activemodel (= 6.1.4)
|
14
|
+
activesupport (= 6.1.4)
|
15
|
+
activesupport (6.1.4)
|
17
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
18
17
|
i18n (>= 1.6, < 2)
|
19
18
|
minitest (>= 5.1)
|
20
19
|
tzinfo (~> 2.0)
|
21
20
|
zeitwerk (~> 2.3)
|
22
|
-
ast (2.4.
|
23
|
-
concurrent-ruby (1.1.
|
21
|
+
ast (2.4.2)
|
22
|
+
concurrent-ruby (1.1.9)
|
24
23
|
diff-lcs (1.4.4)
|
25
|
-
i18n (1.8.
|
24
|
+
i18n (1.8.10)
|
26
25
|
concurrent-ruby (~> 1.0)
|
27
|
-
minitest (5.14.
|
26
|
+
minitest (5.14.4)
|
28
27
|
parallel (1.20.1)
|
29
|
-
parser (3.0.
|
28
|
+
parser (3.0.2.0)
|
30
29
|
ast (~> 2.4.1)
|
31
30
|
rainbow (3.0.0)
|
32
|
-
rake (13.0.
|
33
|
-
regexp_parser (2.
|
34
|
-
rexml (3.2.
|
31
|
+
rake (13.0.6)
|
32
|
+
regexp_parser (2.1.1)
|
33
|
+
rexml (3.2.5)
|
35
34
|
rspec (3.10.0)
|
36
35
|
rspec-core (~> 3.10.0)
|
37
36
|
rspec-expectations (~> 3.10.0)
|
@@ -41,27 +40,32 @@ GEM
|
|
41
40
|
rspec-expectations (3.10.1)
|
42
41
|
diff-lcs (>= 1.2.0, < 2.0)
|
43
42
|
rspec-support (~> 3.10.0)
|
44
|
-
rspec-mocks (3.10.
|
43
|
+
rspec-mocks (3.10.2)
|
45
44
|
diff-lcs (>= 1.2.0, < 2.0)
|
46
45
|
rspec-support (~> 3.10.0)
|
47
|
-
rspec-support (3.10.
|
48
|
-
rubocop (1.
|
46
|
+
rspec-support (3.10.2)
|
47
|
+
rubocop (1.18.3)
|
49
48
|
parallel (~> 1.10)
|
50
49
|
parser (>= 3.0.0.0)
|
51
50
|
rainbow (>= 2.2.2, < 4.0)
|
52
51
|
regexp_parser (>= 1.8, < 3.0)
|
53
52
|
rexml
|
54
|
-
rubocop-ast (>= 1.
|
53
|
+
rubocop-ast (>= 1.7.0, < 2.0)
|
55
54
|
ruby-progressbar (~> 1.7)
|
56
55
|
unicode-display_width (>= 1.4.0, < 3.0)
|
57
|
-
rubocop-ast (1.
|
58
|
-
parser (>=
|
59
|
-
rubocop-
|
60
|
-
rubocop (
|
56
|
+
rubocop-ast (1.7.0)
|
57
|
+
parser (>= 3.0.1.1)
|
58
|
+
rubocop-bsm (0.6.0)
|
59
|
+
rubocop (~> 1.0)
|
60
|
+
rubocop-performance
|
61
|
+
rubocop-rake
|
62
|
+
rubocop-rspec
|
63
|
+
rubocop-performance (1.11.4)
|
64
|
+
rubocop (>= 1.7.0, < 2.0)
|
61
65
|
rubocop-ast (>= 0.4.0)
|
62
|
-
rubocop-rake (0.
|
63
|
-
rubocop
|
64
|
-
rubocop-rspec (2.
|
66
|
+
rubocop-rake (0.6.0)
|
67
|
+
rubocop (~> 1.0)
|
68
|
+
rubocop-rspec (2.4.0)
|
65
69
|
rubocop (~> 1.0)
|
66
70
|
rubocop-ast (>= 1.1.0)
|
67
71
|
ruby-progressbar (1.11.0)
|
@@ -79,11 +83,9 @@ DEPENDENCIES
|
|
79
83
|
rake
|
80
84
|
rspec
|
81
85
|
rubocop
|
82
|
-
rubocop-
|
83
|
-
rubocop-rake
|
84
|
-
rubocop-rspec
|
86
|
+
rubocop-bsm
|
85
87
|
searchable-by!
|
86
88
|
sqlite3
|
87
89
|
|
88
90
|
BUNDLED WITH
|
89
|
-
2.
|
91
|
+
2.2.21
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Searchable By
|
2
2
|
|
3
|
+
[](https://github.com/bsm/searchable-by/actions/workflows/test.yml)
|
4
|
+
|
3
5
|
ActiveRecord plugin to quickly create search scopes.
|
4
6
|
|
5
7
|
## Installation
|
@@ -13,11 +15,12 @@ class Post < ActiveRecord::Base
|
|
13
15
|
belongs_to :author
|
14
16
|
|
15
17
|
# Limit the number of terms per query to 3.
|
16
|
-
|
18
|
+
# Ignore search terms shorter than 3 characters (useful for trigram indexes).
|
19
|
+
searchable_by max_terms: 3, min_length: 3 do
|
17
20
|
# Allow to search strings with custom match type.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
column :title,
|
22
|
+
match: :prefix, # Use btree index-friendly prefix match, e.g. `ILIKE 'term%'` instead of default `ILIKE '%term%'`.
|
23
|
+
match_phrase: :exact, # For phrases use exact match type, e.g. searching for `"My Post"` will query `WHERE LOWER(title) = 'my post'`.
|
21
24
|
|
22
25
|
# ... and integers.
|
23
26
|
column :id, type: :integer
|
data/lib/searchable_by/column.rb
CHANGED
@@ -1,13 +1,22 @@
|
|
1
1
|
module SearchableBy
|
2
2
|
class Column
|
3
|
-
attr_reader :attr, :type, :match, :match_phrase
|
3
|
+
attr_reader :attr, :type, :match, :match_phrase, :wildcard
|
4
4
|
attr_accessor :node
|
5
5
|
|
6
|
-
def initialize(attr, type: :string, match: :all, match_phrase: nil)
|
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
|
+
|
7
14
|
@attr = attr
|
8
15
|
@type = type.to_sym
|
9
16
|
@match = match
|
10
17
|
@match_phrase = match_phrase || match
|
18
|
+
@min_length = opts[:min_length].to_i
|
19
|
+
@wildcard = wildcard
|
11
20
|
end
|
12
21
|
|
13
22
|
def build_condition(value)
|
@@ -23,6 +32,11 @@ module SearchableBy
|
|
23
32
|
|
24
33
|
private
|
25
34
|
|
35
|
+
# TODO: remove when removing min_length option from columns
|
36
|
+
def usable?(value)
|
37
|
+
value.term.length >= @min_length
|
38
|
+
end
|
39
|
+
|
26
40
|
def int_condition(scope, value)
|
27
41
|
scope.and(node.eq(Integer(value.term)))
|
28
42
|
rescue ArgumentError
|
@@ -37,15 +51,22 @@ module SearchableBy
|
|
37
51
|
when :exact
|
38
52
|
term.downcase!
|
39
53
|
scope.and(node.lower.eq(term))
|
54
|
+
when :full
|
55
|
+
escape_term!(term)
|
56
|
+
scope.and(node.matches(term))
|
40
57
|
when :prefix
|
41
|
-
|
42
|
-
term.gsub!('_', '\_')
|
58
|
+
escape_term!(term)
|
43
59
|
scope.and(node.matches("#{term}%"))
|
44
|
-
else
|
45
|
-
|
46
|
-
term.gsub!('_', '\_')
|
60
|
+
else # :all (wraps term in wildcards)
|
61
|
+
escape_term!(term)
|
47
62
|
scope.and(node.matches("%#{term}%"))
|
48
63
|
end
|
49
64
|
end
|
65
|
+
|
66
|
+
def escape_term!(term)
|
67
|
+
term.gsub!('%', '\%')
|
68
|
+
term.gsub!('_', '\_')
|
69
|
+
term.gsub!(wildcard, '%') if wildcard
|
70
|
+
end
|
50
71
|
end
|
51
72
|
end
|
@@ -11,9 +11,10 @@ module SearchableBy
|
|
11
11
|
super
|
12
12
|
end
|
13
13
|
|
14
|
-
def searchable_by(max_terms: nil, **options, &block)
|
14
|
+
def searchable_by(max_terms: nil, min_length: 0, **options, &block)
|
15
15
|
_searchable_by_config.instance_eval(&block)
|
16
16
|
_searchable_by_config.max_terms = max_terms if max_terms
|
17
|
+
_searchable_by_config.min_length = min_length
|
17
18
|
_searchable_by_config.options.update(options) unless options.empty?
|
18
19
|
_searchable_by_config
|
19
20
|
end
|
@@ -21,10 +22,11 @@ module SearchableBy
|
|
21
22
|
# @param [String] query the search query
|
22
23
|
# @return [ActiveRecord::Relation] the scoped relation
|
23
24
|
def search_by(query)
|
24
|
-
|
25
|
+
config = _searchable_by_config
|
26
|
+
columns = config.columns
|
25
27
|
return all if columns.empty?
|
26
28
|
|
27
|
-
values = Util.norm_values(query).first(
|
29
|
+
values = Util.norm_values(query, min_length: config.min_length).first(config.max_terms)
|
28
30
|
return all if values.empty?
|
29
31
|
|
30
32
|
columns.each do |col|
|
@@ -33,7 +35,7 @@ module SearchableBy
|
|
33
35
|
clauses = Util.build_clauses(columns, values)
|
34
36
|
return all if clauses.empty?
|
35
37
|
|
36
|
-
scope = instance_exec(&
|
38
|
+
scope = instance_exec(&config.scoping)
|
37
39
|
clauses.each do |clause|
|
38
40
|
scope = scope.where(clause)
|
39
41
|
end
|
data/lib/searchable_by/config.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module SearchableBy
|
2
2
|
class Config
|
3
3
|
attr_reader :columns, :scoping, :options
|
4
|
-
attr_accessor :max_terms
|
4
|
+
attr_accessor :max_terms, :min_length
|
5
5
|
|
6
6
|
def initialize
|
7
7
|
@columns = []
|
8
8
|
@max_terms = 5
|
9
|
+
@min_length = 0
|
9
10
|
@options = {}
|
10
11
|
scope { all }
|
11
12
|
end
|
data/lib/searchable_by/util.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module SearchableBy
|
2
2
|
module Util
|
3
|
-
def self.norm_values(query)
|
3
|
+
def self.norm_values(query, min_length: 0)
|
4
4
|
values = []
|
5
5
|
query = query.to_s.dup
|
6
6
|
|
@@ -10,7 +10,7 @@ module SearchableBy
|
|
10
10
|
term = Regexp.last_match(2)
|
11
11
|
negate = Regexp.last_match(1) == '-'
|
12
12
|
|
13
|
-
values.push Value.new(term, negate, true) unless term.blank?
|
13
|
+
values.push Value.new(term, negate, true) unless term.blank? || term.length < min_length
|
14
14
|
''
|
15
15
|
end
|
16
16
|
|
@@ -20,7 +20,7 @@ module SearchableBy
|
|
20
20
|
negate = term[0] == '-'
|
21
21
|
term.slice!(0) if negate || term[0] == '+'
|
22
22
|
|
23
|
-
values.push Value.new(term, negate, false) unless term.blank?
|
23
|
+
values.push Value.new(term, negate, false) unless term.blank? || term.length < min_length
|
24
24
|
end
|
25
25
|
|
26
26
|
values.uniq!
|
@@ -28,19 +28,22 @@ module SearchableBy
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.build_clauses(columns, values)
|
31
|
-
|
32
|
-
|
33
|
-
|
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)
|
34
35
|
end
|
35
|
-
|
36
|
-
|
36
|
+
next unless usable
|
37
|
+
|
38
|
+
group = columns.map do |column|
|
39
|
+
column.build_condition(value)
|
40
|
+
end.tap(&:compact!)
|
41
|
+
next if group.empty?
|
37
42
|
|
38
|
-
clause =
|
43
|
+
clause = group.inject(&:or)
|
39
44
|
clause = clause.not if value.negate
|
40
45
|
clause
|
41
|
-
end
|
42
|
-
clauses.compact!
|
43
|
-
clauses
|
46
|
+
end.tap(&:compact!)
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
data/searchable-by.gemspec
CHANGED
@@ -1,27 +1,23 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'searchable-by'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.6.1'
|
4
4
|
s.authors = ['Dimitrij Denissenko']
|
5
5
|
s.email = ['dimitrij@blacksquaremedia.com']
|
6
6
|
s.summary = 'Generate search scopes'
|
7
7
|
s.description = 'ActiveRecord plugin'
|
8
8
|
s.homepage = 'https://github.com/bsm/sortable-by'
|
9
|
-
s.license = '
|
9
|
+
s.license = 'Apache-2.0'
|
10
10
|
|
11
11
|
s.files = `git ls-files -z`.split("\x0").reject {|f| f.start_with?('spec/') }
|
12
12
|
s.test_files = `git ls-files -z -- spec/*`.split("\x0")
|
13
13
|
s.require_paths = ['lib']
|
14
|
-
s.required_ruby_version = '>= 2.
|
14
|
+
s.required_ruby_version = '>= 2.6'
|
15
15
|
|
16
16
|
s.add_dependency 'activerecord'
|
17
|
-
s.add_dependency 'activesupport'
|
18
|
-
|
19
17
|
s.add_development_dependency 'bundler'
|
20
18
|
s.add_development_dependency 'rake'
|
21
19
|
s.add_development_dependency 'rspec'
|
22
20
|
s.add_development_dependency 'rubocop'
|
23
|
-
s.add_development_dependency 'rubocop-
|
24
|
-
s.add_development_dependency 'rubocop-rake'
|
25
|
-
s.add_development_dependency 'rubocop-rspec'
|
21
|
+
s.add_development_dependency 'rubocop-bsm'
|
26
22
|
s.add_development_dependency 'sqlite3'
|
27
23
|
end
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe SearchableBy::Util do
|
4
4
|
context 'with norm_values' do
|
5
|
-
def norm(str)
|
6
|
-
described_class.norm_values(str).each_with_object({}) do |val, acc|
|
5
|
+
def norm(str, **opts)
|
6
|
+
described_class.norm_values(str, **opts).each_with_object({}) do |val, acc|
|
7
7
|
acc[val.term] = val.negate
|
8
8
|
end
|
9
9
|
end
|
@@ -30,6 +30,7 @@ describe SearchableBy::Util do
|
|
30
30
|
expect(norm('+plus "in other term"')).to eq('in other term' => false, 'plus' => false)
|
31
31
|
expect(norm('with_blank \'\'')).to eq('with_blank' => false, '\'\'' => false)
|
32
32
|
expect(norm('with_blank_doubles ""')).to eq('with_blank_doubles' => false)
|
33
|
+
expect(norm('with min length', min_length: 4)).to eq('length' => false, 'with' => false)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
data/spec/searchable_by_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe SearchableBy do
|
|
8
8
|
|
9
9
|
it 'configures correctly' do
|
10
10
|
expect(AbstractModel._searchable_by_config.columns.size).to eq(1)
|
11
|
-
expect(Post._searchable_by_config.columns.size).to eq(
|
11
|
+
expect(Post._searchable_by_config.columns.size).to eq(6)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'generates SQL' do
|
@@ -22,6 +22,14 @@ describe SearchableBy do
|
|
22
22
|
expect(sql).not_to include(%("posts"."id"))
|
23
23
|
expect(sql).to include(%("posts"."title" LIKE 'foo\\%bar%'))
|
24
24
|
expect(sql).to include(%("posts"."body" LIKE '%foo\\%bar%'))
|
25
|
+
|
26
|
+
sql = User.search_by('uni*dom').to_sql
|
27
|
+
expect(sql).to include(%("users"."country" LIKE 'uni%dom'))
|
28
|
+
expect(sql).to include(%("users"."bio" LIKE '%uni*dom%'))
|
29
|
+
|
30
|
+
sql = User.search_by('"uni * dom"').to_sql
|
31
|
+
expect(sql).to include(%("users"."country" LIKE 'uni % dom'))
|
32
|
+
expect(sql).to include(%("users"."bio" LIKE '%uni * dom%'))
|
25
33
|
end
|
26
34
|
|
27
35
|
it 'searches' do
|
@@ -57,10 +65,25 @@ describe SearchableBy do
|
|
57
65
|
expect(Post.search_by('"ab"').pluck(:title)).to be_empty
|
58
66
|
expect(Post.search_by('"ab1"').pluck(:title)).to match_array(%w[ab1])
|
59
67
|
|
68
|
+
# country uses match: :full in combination with wildcard: '*'
|
69
|
+
expect(Post.search_by('*kingdom').pluck(:title)).to match_array(%w[ax1 ax2 ab1])
|
70
|
+
|
60
71
|
# body uses match: :all (default)
|
61
72
|
expect(Post.search_by('recip').pluck(:title)).to match_array(%w[ax1 ax2 bx1 bx2 ab1])
|
62
73
|
end
|
63
74
|
|
75
|
+
it 'supports min term length in context' do
|
76
|
+
# values are discarded - too short for bio
|
77
|
+
expect(User.search_by('+be')).to match_array(USERS.values_at(:a, :b))
|
78
|
+
expect(User.search_by('is')).to match_array(USERS.values_at(:a, :b))
|
79
|
+
|
80
|
+
# value is used to scope
|
81
|
+
expect(User.search_by('ear')).to match_array(USERS.values_at(:a))
|
82
|
+
|
83
|
+
# one used, one discarded
|
84
|
+
expect(User.search_by('beard is')).to match_array(USERS.values_at(:a))
|
85
|
+
end
|
86
|
+
|
64
87
|
it 'searches within scopes' do
|
65
88
|
expect(Post.where(title: 'ax1').search_by('ALICE').pluck(:title)).to match_array(%w[ax1])
|
66
89
|
expect(Post.where(title: 'ax1').search_by('bOb').pluck(:title)).to be_empty
|
@@ -69,4 +92,10 @@ describe SearchableBy do
|
|
69
92
|
it 'searches integers' do
|
70
93
|
expect(Post.search_by(POSTS[:ab1].id.to_s).count).to eq(1)
|
71
94
|
end
|
95
|
+
|
96
|
+
it 'supports wildcard searching' do
|
97
|
+
expect(User.search_by('*uni*dom')).to match_array(USERS.values_at(:a))
|
98
|
+
expect(User.search_by('*uni*o*')).to match_array(USERS.values_at(:a, :b))
|
99
|
+
expect(User.search_by('*uni*of*dom')).to be_empty
|
100
|
+
end
|
72
101
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,8 @@ ActiveRecord::Base.establish_connection :test
|
|
8
8
|
ActiveRecord::Base.connection.instance_eval do
|
9
9
|
create_table :users do |t|
|
10
10
|
t.string :name
|
11
|
+
t.string :bio
|
12
|
+
t.string :country
|
11
13
|
end
|
12
14
|
create_table :posts do |t|
|
13
15
|
t.integer :author_id, null: false
|
@@ -27,6 +29,11 @@ end
|
|
27
29
|
|
28
30
|
class User < AbstractModel
|
29
31
|
has_many :posts, foreign_key: :author_id
|
32
|
+
|
33
|
+
searchable_by min_length: 3 do
|
34
|
+
column :bio
|
35
|
+
column :country, wildcard: '*', match: :full
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
class Post < AbstractModel
|
@@ -37,6 +44,7 @@ class Post < AbstractModel
|
|
37
44
|
column :title, match: :prefix, match_phrase: :exact
|
38
45
|
column :body
|
39
46
|
column proc { User.arel_table[:name] }, match: :exact
|
47
|
+
column proc { User.arel_table[:country] }, wildcard: '*', match: :full
|
40
48
|
column { User.arel_table.alias('reviewers_posts')[:name] }
|
41
49
|
|
42
50
|
scope do
|
@@ -46,8 +54,8 @@ class Post < AbstractModel
|
|
46
54
|
end
|
47
55
|
|
48
56
|
USERS = {
|
49
|
-
a: User.create!(name: 'Alice'),
|
50
|
-
b: User.create!(name: 'Bob'),
|
57
|
+
a: User.create!(name: 'Alice', bio: "Chuck Norris' beard is immutable.", country: 'United Kingdom'),
|
58
|
+
b: User.create!(name: 'Bob', bio: 'Chuck Norris can divide by zero.', country: 'United States of America'),
|
51
59
|
}.freeze
|
52
60
|
|
53
61
|
POSTS = {
|
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.6.1
|
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-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: activesupport
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: bundler
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,35 +81,7 @@ dependencies:
|
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop-
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop-rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: rubocop-rspec
|
84
|
+
name: rubocop-bsm
|
127
85
|
requirement: !ruby/object:Gem::Requirement
|
128
86
|
requirements:
|
129
87
|
- - ">="
|
@@ -157,9 +115,9 @@ executables: []
|
|
157
115
|
extensions: []
|
158
116
|
extra_rdoc_files: []
|
159
117
|
files:
|
118
|
+
- ".github/workflows/test.yml"
|
160
119
|
- ".gitignore"
|
161
120
|
- ".rubocop.yml"
|
162
|
-
- ".travis.yml"
|
163
121
|
- Gemfile
|
164
122
|
- Gemfile.lock
|
165
123
|
- LICENSE
|
@@ -177,7 +135,7 @@ files:
|
|
177
135
|
- spec/spec_helper.rb
|
178
136
|
homepage: https://github.com/bsm/sortable-by
|
179
137
|
licenses:
|
180
|
-
-
|
138
|
+
- Apache-2.0
|
181
139
|
metadata: {}
|
182
140
|
post_install_message:
|
183
141
|
rdoc_options: []
|
@@ -187,14 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
145
|
requirements:
|
188
146
|
- - ">="
|
189
147
|
- !ruby/object:Gem::Version
|
190
|
-
version: '2.
|
148
|
+
version: '2.6'
|
191
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
150
|
requirements:
|
193
151
|
- - ">="
|
194
152
|
- !ruby/object:Gem::Version
|
195
153
|
version: '0'
|
196
154
|
requirements: []
|
197
|
-
rubygems_version: 3.
|
155
|
+
rubygems_version: 3.2.15
|
198
156
|
signing_key:
|
199
157
|
specification_version: 4
|
200
158
|
summary: Generate search scopes
|