scoped_search 4.1.4 → 4.1.5
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/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
|