searchable-by 0.5.0 → 0.5.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/Gemfile.lock +1 -1
- data/lib/searchable_by.rb +49 -28
- data/searchable-by.gemspec +1 -1
- data/spec/searchable_by_spec.rb +6 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c1c5cfdea465a6a9ff73159a062558c5475889d27e0119e81212bb8bb37bbc1
|
4
|
+
data.tar.gz: c77c158c890b37b67d1243c93b4d5c982731b55fb48d284ecc404de58142da26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ba79022ae7056fc1cd6f6ef7af109ed6e0a7228601241ac2bc8f501818b6f487a6fd929f77bc3ce0dba9956b879def3dc705159c3696246d4653e3197f3d71f
|
7
|
+
data.tar.gz: c023dff5eb1bb4685dcfe7d10b7164242a090a930189ccc1b336c6de3437ab05d1de0dc90d13f52412e8e15b16a0a1386d5dacb289b208e00eefca5eab0cc2f7
|
data/Gemfile.lock
CHANGED
data/lib/searchable_by.rb
CHANGED
@@ -3,24 +3,42 @@ require 'shellwords'
|
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
module SearchableBy
|
6
|
-
class
|
6
|
+
class Column
|
7
|
+
attr_reader :attr, :type
|
8
|
+
attr_accessor :node
|
9
|
+
|
10
|
+
def initialize(attr, type: :string)
|
11
|
+
@attr = attr
|
12
|
+
@type = type.to_sym
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Config
|
17
|
+
attr_reader :columns, :scoping
|
18
|
+
attr_accessor :max_terms
|
19
|
+
|
7
20
|
def initialize
|
8
|
-
|
21
|
+
@columns = []
|
22
|
+
@max_terms = 5
|
9
23
|
scope { all }
|
10
24
|
end
|
11
25
|
|
26
|
+
def initialize_copy(other)
|
27
|
+
@columns = other.columns.dup
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
12
31
|
def column(*attrs, &block)
|
13
32
|
opts = attrs.extract_options!
|
14
|
-
cols = self[:columns]
|
15
33
|
attrs.each do |attr|
|
16
|
-
|
34
|
+
columns.push Column.new(attr, opts)
|
17
35
|
end
|
18
|
-
|
19
|
-
|
36
|
+
columns.push Column.new(block, opts) if block
|
37
|
+
columns
|
20
38
|
end
|
21
39
|
|
22
40
|
def scope(&block)
|
23
|
-
|
41
|
+
@scoping = block
|
24
42
|
end
|
25
43
|
end
|
26
44
|
|
@@ -32,27 +50,30 @@ module ActiveRecord
|
|
32
50
|
values
|
33
51
|
end
|
34
52
|
|
35
|
-
def self.build_clauses(
|
53
|
+
def self.build_clauses(columns, values)
|
36
54
|
clauses = values.map do |value|
|
37
55
|
negate = value[0] == '-'
|
38
56
|
value.slice!(0) if negate || value[0] == '+'
|
39
57
|
|
40
|
-
|
41
|
-
build_condition(
|
42
|
-
end
|
43
|
-
|
58
|
+
grouping = columns.map do |column|
|
59
|
+
build_condition(column, value)
|
60
|
+
end
|
61
|
+
grouping.compact!
|
62
|
+
next if grouping.empty?
|
44
63
|
|
45
|
-
|
64
|
+
clause = grouping.inject(&:or)
|
65
|
+
clause = clause.not if negate
|
66
|
+
clause
|
46
67
|
end
|
47
68
|
clauses.compact!
|
48
69
|
clauses
|
49
70
|
end
|
50
71
|
|
51
|
-
def self.build_condition(
|
52
|
-
case
|
72
|
+
def self.build_condition(column, value)
|
73
|
+
case column.type
|
53
74
|
when :int, :integer
|
54
75
|
begin
|
55
|
-
|
76
|
+
column.node.eq(Integer(value))
|
56
77
|
rescue ArgumentError
|
57
78
|
nil
|
58
79
|
end
|
@@ -60,7 +81,7 @@ module ActiveRecord
|
|
60
81
|
value = value.dup
|
61
82
|
value.gsub!('%', '\%')
|
62
83
|
value.gsub!('_', '\_')
|
63
|
-
|
84
|
+
column.node.matches("%#{value}%")
|
64
85
|
end
|
65
86
|
end
|
66
87
|
|
@@ -72,35 +93,35 @@ module ActiveRecord
|
|
72
93
|
end
|
73
94
|
|
74
95
|
def inherited(base) # :nodoc:
|
75
|
-
base._searchable_by_config = _searchable_by_config.
|
96
|
+
base._searchable_by_config = _searchable_by_config.dup
|
76
97
|
super
|
77
98
|
end
|
78
99
|
|
79
100
|
def searchable_by(max_terms: 5, &block)
|
80
101
|
_searchable_by_config.instance_eval(&block)
|
81
|
-
_searchable_by_config
|
102
|
+
_searchable_by_config.max_terms = max_terms if max_terms
|
82
103
|
end
|
83
104
|
|
84
105
|
# @param [String] query the search query
|
85
106
|
# @return [ActiveRecord::Relation] the scoped relation
|
86
107
|
def search_by(query)
|
87
|
-
columns = _searchable_by_config
|
108
|
+
columns = _searchable_by_config.columns
|
88
109
|
return all if columns.empty?
|
89
110
|
|
90
|
-
values = SearchableBy.norm_values(query).first(_searchable_by_config
|
111
|
+
values = SearchableBy.norm_values(query).first(_searchable_by_config.max_terms)
|
91
112
|
return all if values.empty?
|
92
113
|
|
93
|
-
|
94
|
-
|
95
|
-
opts.merge(rel: rel)
|
114
|
+
columns.each do |col|
|
115
|
+
col.node ||= col.attr.is_a?(Proc) ? col.attr.call : arel_table[col.attr]
|
96
116
|
end
|
97
|
-
clauses = SearchableBy.build_clauses(
|
117
|
+
clauses = SearchableBy.build_clauses(columns, values)
|
98
118
|
return all if clauses.empty?
|
99
119
|
|
100
|
-
scope = instance_exec(&_searchable_by_config
|
101
|
-
clauses.
|
102
|
-
|
120
|
+
scope = instance_exec(&_searchable_by_config.scoping)
|
121
|
+
clauses.each do |clause|
|
122
|
+
scope = scope.where(clause)
|
103
123
|
end
|
124
|
+
scope
|
104
125
|
end
|
105
126
|
end
|
106
127
|
end
|
data/searchable-by.gemspec
CHANGED
data/spec/searchable_by_spec.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ActiveRecord::SearchableBy do
|
4
|
+
|
4
5
|
it 'should ignore bad inputs' do
|
5
6
|
expect(Post.search_by(nil).count).to eq(4)
|
6
7
|
expect(Post.search_by('').count).to eq(4)
|
7
8
|
end
|
8
9
|
|
10
|
+
it 'should configure correctly' do
|
11
|
+
expect(AbstractModel._searchable_by_config.columns.size).to eq(1)
|
12
|
+
expect(Post._searchable_by_config.columns.size).to eq(4)
|
13
|
+
end
|
14
|
+
|
9
15
|
it 'should generate SQL' do
|
10
16
|
sql = Post.search_by('123').to_sql
|
11
17
|
expect(sql).to include(%("posts"."id" = 123))
|