scoped_search 4.1.4 → 4.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +5 -1
- data/lib/scoped_search/auto_complete_builder.rb +1 -1
- data/lib/scoped_search/definition.rb +16 -10
- data/lib/scoped_search/query_builder.rb +4 -4
- data/lib/scoped_search/version.rb +1 -1
- data/spec/unit/auto_complete_builder_spec.rb +17 -1
- data/spec/unit/query_builder_spec.rb +5 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25198636d3a83a3be37b174722b43786bfb66c40
|
4
|
+
data.tar.gz: 2d51410c045dd98edffd782900a960f5111c47f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 467be1c841cb5a0ce8eff10af66df07db0527a8b7423f386ad8a5ea29bea2ab4e3d02edb0b480ff427bfbdc0078ca1ac138690866db4fb67f13c31322334320b
|
7
|
+
data.tar.gz: fbc5a32d17479d8e919ca7b9e198416a0acb60bcbf0e1b2b3b7b850ad97af135a7cb5d57b0f93d3fee7a1b27c8ee7b47871367506ebe100e8beb58179041c01d
|
data/CHANGELOG.rdoc
CHANGED
@@ -6,7 +6,11 @@ Please add an entry to the "Unreleased changes" section in your pull requests.
|
|
6
6
|
|
7
7
|
=== Unreleased changes
|
8
8
|
|
9
|
-
|
9
|
+
- Nothing yet
|
10
|
+
|
11
|
+
=== Version 4.1.5
|
12
|
+
|
13
|
+
- Bugfix related to auto-completion of virtual fields (#182)
|
10
14
|
|
11
15
|
=== Version 4.1.4
|
12
16
|
|
@@ -270,7 +270,7 @@ module ScopedSearch
|
|
270
270
|
|
271
271
|
# This method complete infix operators by field type
|
272
272
|
def complete_operator(node)
|
273
|
-
definition.operator_by_field_name(node.value)
|
273
|
+
definition.operator_by_field_name(node.value).map { |o| o.end_with?(' ') ? o : "#{o} " }
|
274
274
|
end
|
275
275
|
end
|
276
276
|
end
|
@@ -107,6 +107,11 @@ module ScopedSearch
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
# Returns true if this is a virtual field.
|
111
|
+
def virtual?
|
112
|
+
!ext_method.nil?
|
113
|
+
end
|
114
|
+
|
110
115
|
# Returns the ActiveRecord column definition that corresponds to this field.
|
111
116
|
def column
|
112
117
|
@column ||= begin
|
@@ -120,15 +125,15 @@ module ScopedSearch
|
|
120
125
|
|
121
126
|
# Returns the column type of this field.
|
122
127
|
def type
|
123
|
-
@type ||= column.type
|
128
|
+
@type ||= virtual? ? :virtual : column.type
|
124
129
|
end
|
125
130
|
|
126
|
-
# Returns true if this field is a datetime-like column
|
131
|
+
# Returns true if this field is a datetime-like column.
|
127
132
|
def datetime?
|
128
133
|
[:datetime, :time, :timestamp].include?(type)
|
129
134
|
end
|
130
135
|
|
131
|
-
# Returns true if this field is a date-like column
|
136
|
+
# Returns true if this field is a date-like column.
|
132
137
|
def date?
|
133
138
|
type == :date
|
134
139
|
end
|
@@ -167,7 +172,7 @@ module ScopedSearch
|
|
167
172
|
return "#{field} #{order}"
|
168
173
|
end
|
169
174
|
|
170
|
-
# Return 'table'.'column' with the correct database quotes
|
175
|
+
# Return 'table'.'column' with the correct database quotes.
|
171
176
|
def quoted_field
|
172
177
|
c = klass.connection
|
173
178
|
"#{c.quote_table_name(klass.table_name)}.#{c.quote_column_name(field)}"
|
@@ -231,11 +236,12 @@ module ScopedSearch
|
|
231
236
|
def operator_by_field_name(name)
|
232
237
|
field = field_by_name(name)
|
233
238
|
return [] if field.nil?
|
234
|
-
return field.operators
|
235
|
-
return ['=
|
236
|
-
return ['=
|
237
|
-
return ['=
|
238
|
-
return ['= ', '
|
239
|
+
return field.operators if field.operators
|
240
|
+
return ['=', '!=', '>', '<', '<=', '>=', '~', '!~', '^', '!^'] if field.virtual?
|
241
|
+
return ['=', '!='] if field.set?
|
242
|
+
return ['=', '>', '<', '<=', '>=', '!=', '^', '!^'] if field.numerical?
|
243
|
+
return ['=', '!=', '~', '!~', '^', '!^'] if field.textual?
|
244
|
+
return ['=', '>', '<'] if field.temporal?
|
239
245
|
raise ScopedSearch::QueryNotSupported, "Unsupported type '#{field.type.inspect}')' for field '#{name}'. This can be a result of a search definition problem."
|
240
246
|
end
|
241
247
|
|
@@ -245,7 +251,7 @@ module ScopedSearch
|
|
245
251
|
# Returns a list of appropriate fields to search in given a search keyword and operator.
|
246
252
|
def default_fields_for(value, operator = nil)
|
247
253
|
|
248
|
-
column_types = []
|
254
|
+
column_types = [:virtual]
|
249
255
|
column_types += [:string, :text] if [nil, :like, :unlike, :ne, :eq].include?(operator)
|
250
256
|
column_types += [:double, :float, :decimal] if value =~ NUMERICAL_REGXP
|
251
257
|
column_types += [:integer] if value =~ INTEGER_REGXP
|
@@ -113,7 +113,7 @@ module ScopedSearch
|
|
113
113
|
# By default, it will simply look up the correct SQL operator in the SQL_OPERATORS
|
114
114
|
# hash, but this can be overridden by a database adapter.
|
115
115
|
def sql_operator(operator, field)
|
116
|
-
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.
|
116
|
+
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.virtual? and [:like, :unlike].include?(operator) and !field.textual?
|
117
117
|
SQL_OPERATORS[operator]
|
118
118
|
end
|
119
119
|
|
@@ -210,7 +210,7 @@ module ScopedSearch
|
|
210
210
|
# <tt>operator</tt>:: The operator used for comparison.
|
211
211
|
# <tt>value</tt>:: The value to compare the field with.
|
212
212
|
def sql_test(field, operator, value, lhs, &block) # :yields: finder_option_type, value
|
213
|
-
return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block) if field.
|
213
|
+
return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block) if field.virtual?
|
214
214
|
|
215
215
|
yield(:keyparameter, lhs.sub(/^.*\./,'')) if field.key_field
|
216
216
|
|
@@ -403,7 +403,7 @@ module ScopedSearch
|
|
403
403
|
def to_ext_method_sql(key, operator, value, &block)
|
404
404
|
raise ScopedSearch::QueryNotSupported, "'#{definition.klass}' doesn't respond to '#{ext_method}'" unless definition.klass.respond_to?(ext_method)
|
405
405
|
begin
|
406
|
-
conditions = definition.klass.send(ext_method.to_sym, key, operator, value)
|
406
|
+
conditions = definition.klass.send(ext_method.to_sym, key, operator, value)
|
407
407
|
rescue StandardError => e
|
408
408
|
raise ScopedSearch::QueryNotSupported, "external method '#{ext_method}' failed with error: #{e}"
|
409
409
|
end
|
@@ -554,7 +554,7 @@ module ScopedSearch
|
|
554
554
|
# Switches out the default LIKE operator in the default <tt>sql_operator</tt>
|
555
555
|
# method for ILIKE or @@ if full text searching is enabled.
|
556
556
|
def sql_operator(operator, field)
|
557
|
-
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.
|
557
|
+
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.virtual? and [:like, :unlike].include?(operator) and !field.textual?
|
558
558
|
return '@@' if [:like, :unlike].include?(operator) && field.full_text_search
|
559
559
|
case operator
|
560
560
|
when :like then 'ILIKE'
|
@@ -2,9 +2,11 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe ScopedSearch::AutoCompleteBuilder do
|
4
4
|
|
5
|
+
let(:klass) { Class.new(ActiveRecord::Base) }
|
6
|
+
|
5
7
|
before(:each) do
|
6
8
|
@definition = double('ScopedSearch::Definition')
|
7
|
-
@definition.stub(:klass).and_return(
|
9
|
+
@definition.stub(:klass).and_return(klass)
|
8
10
|
@definition.stub(:profile).and_return(:default)
|
9
11
|
@definition.stub(:profile=).and_return(true)
|
10
12
|
end
|
@@ -17,4 +19,18 @@ describe ScopedSearch::AutoCompleteBuilder do
|
|
17
19
|
ScopedSearch::AutoCompleteBuilder.auto_complete(@definition, "").should == []
|
18
20
|
end
|
19
21
|
|
22
|
+
context "with ext_method" do
|
23
|
+
before do
|
24
|
+
@definition = ScopedSearch::Definition.new(klass)
|
25
|
+
@definition.define(:test_field, ext_method: :ext_test)
|
26
|
+
@definition.klass.stub(:connection).and_return(double())
|
27
|
+
@definition.klass.stub(:columns_hash).and_return({})
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should support operator auto-completion on a virtual field" do
|
31
|
+
klass.should_receive(:ext_test).with('', '=', 'test_field').and_return(conditions: '')
|
32
|
+
ScopedSearch::AutoCompleteBuilder.auto_complete(@definition, 'test_field ').should eq(["test_field = ", "test_field != ", "test_field > ", "test_field < ", "test_field <= ", "test_field >= ", "test_field ~ ", "test_field !~ ", "test_field ^ ", "test_field !^ "])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
20
36
|
end
|
@@ -38,6 +38,7 @@ describe ScopedSearch::QueryBuilder do
|
|
38
38
|
|
39
39
|
it "should validate value if validator selected" do
|
40
40
|
field = double('field')
|
41
|
+
field.stub(:virtual?).and_return(false)
|
41
42
|
field.stub(:only_explicit).and_return(true)
|
42
43
|
field.stub(:field).and_return(:test_field)
|
43
44
|
field.stub(:validator).and_return(->(_value) { false })
|
@@ -49,6 +50,7 @@ describe ScopedSearch::QueryBuilder do
|
|
49
50
|
|
50
51
|
it "should validate value if validator selected" do
|
51
52
|
field = double('field')
|
53
|
+
field.stub(:virtual?).and_return(false)
|
52
54
|
field.stub(:only_explicit).and_return(true)
|
53
55
|
field.stub(:field).and_return(:test_field)
|
54
56
|
field.stub(:ext_method).and_return(nil)
|
@@ -65,6 +67,7 @@ describe ScopedSearch::QueryBuilder do
|
|
65
67
|
|
66
68
|
it "should display custom error from validator" do
|
67
69
|
field = double('field')
|
70
|
+
field.stub(:virtual?).and_return(false)
|
68
71
|
field.stub(:only_explicit).and_return(true)
|
69
72
|
field.stub(:field).and_return(:test_field)
|
70
73
|
field.stub(:validator).and_return(->(_value) { raise ScopedSearch::QueryNotSupported, 'my custom message' })
|
@@ -90,7 +93,7 @@ describe ScopedSearch::QueryBuilder do
|
|
90
93
|
ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val').should eq(include: ['test1'], joins: ['test2'])
|
91
94
|
end
|
92
95
|
|
93
|
-
it "should support LIKE query
|
96
|
+
it "should support LIKE query on a virtual field" do
|
94
97
|
klass.should_receive(:ext_test).with('test_field', 'LIKE', 'test_val').and_return(conditions: 'field LIKE ?', parameter: ['%test_val%'])
|
95
98
|
ScopedSearch::QueryBuilder.build_query(@definition, 'test_field ~ test_val').should eq(conditions: ['(field LIKE ?)', '%test_val%'])
|
96
99
|
end
|
@@ -100,7 +103,7 @@ describe ScopedSearch::QueryBuilder do
|
|
100
103
|
lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported, /should return hash/)
|
101
104
|
end
|
102
105
|
|
103
|
-
it "should raise error when
|
106
|
+
it "should raise error when ext_method doesn't exist" do
|
104
107
|
lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported, /doesn't respond to 'ext_test'/)
|
105
108
|
end
|
106
109
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scoped_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.1.
|
4
|
+
version: 4.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amos Benari
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-09-
|
13
|
+
date: 2018-09-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
157
|
version: '0'
|
158
158
|
requirements: []
|
159
159
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.6.
|
160
|
+
rubygems_version: 2.6.11
|
161
161
|
signing_key:
|
162
162
|
specification_version: 4
|
163
163
|
summary: Easily search you ActiveRecord models with a simple query language using
|