scoped_search 3.2.0 → 3.2.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/lib/scoped_search/auto_complete_builder.rb +8 -6
- data/lib/scoped_search/definition.rb +1 -1
- data/lib/scoped_search/query_builder.rb +13 -6
- data/lib/scoped_search/rails_helper.rb +3 -3
- data/lib/scoped_search/version.rb +1 -1
- data/spec/integration/auto_complete_spec.rb +4 -0
- data/spec/integration/key_value_querying_spec.rb +4 -0
- data/spec/integration/string_querying_spec.rb +45 -0
- data/spec/unit/rails_helper_spec.rb +22 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8e91bf7d864d576d7020bd56184d9ed7173e5c3
|
4
|
+
data.tar.gz: 502a182f6303fb040a4b3e77f54d984a85d54093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce108bace0ec727d852a4e0d9db9d330bab9d157a4dd985d0bb77e88eff186553462451beaee8fc532ac8d0b95361174b60772511ee7e1016be5c6f3640fe16e
|
7
|
+
data.tar.gz: c5dcd4e411820161628a61cf0485bf457121ba4ab8338f12d3723f83d8a2938bb1b85469eab096bce6f96f9b76bfb65af58723973de9d63f8e996692cfa4c3b4
|
@@ -176,11 +176,12 @@ module ScopedSearch
|
|
176
176
|
|
177
177
|
field.key_klass
|
178
178
|
.where(value_conditions(field_name, val))
|
179
|
-
.select(
|
179
|
+
.select(field_name)
|
180
180
|
.limit(20)
|
181
181
|
.map(&field.key_field)
|
182
182
|
.compact
|
183
183
|
.map { |f| "#{name}.#{f} " }
|
184
|
+
.uniq
|
184
185
|
end
|
185
186
|
|
186
187
|
# this method auto-completes values of fields that have a :complete_value marker
|
@@ -201,12 +202,13 @@ module ScopedSearch
|
|
201
202
|
return complete_key_value(field, token, val) if field.key_field
|
202
203
|
|
203
204
|
completer_scope(field)
|
204
|
-
.where(value_conditions(field, val))
|
205
|
-
.select(
|
205
|
+
.where(value_conditions(field.quoted_field, val))
|
206
|
+
.select(field.quoted_field)
|
206
207
|
.limit(20)
|
207
208
|
.map(&field.field)
|
208
209
|
.compact
|
209
210
|
.map { |v| v.to_s =~ /\s/ ? "\"#{v}\"" : v }
|
211
|
+
.uniq
|
210
212
|
end
|
211
213
|
|
212
214
|
def completer_scope(field)
|
@@ -251,7 +253,7 @@ module ScopedSearch
|
|
251
253
|
end
|
252
254
|
|
253
255
|
query
|
254
|
-
.where(value_conditions(field, val))
|
256
|
+
.where(value_conditions(field.quoted_field, val))
|
255
257
|
.select("DISTINCT #{field.quoted_field}")
|
256
258
|
.limit(20)
|
257
259
|
.map(&field.field)
|
@@ -260,8 +262,8 @@ module ScopedSearch
|
|
260
262
|
end
|
261
263
|
|
262
264
|
# This method returns conditions for selecting completion from partial value
|
263
|
-
def value_conditions(
|
264
|
-
val.blank? ? nil : "CAST(#{
|
265
|
+
def value_conditions(field_name, val)
|
266
|
+
val.blank? ? nil : "CAST(#{field_name} as CHAR(50)) LIKE '#{val.gsub("'","''")}%'".tr_s('%*', '%')
|
265
267
|
end
|
266
268
|
|
267
269
|
# This method complete infix operators by field type
|
@@ -250,7 +250,7 @@ module ScopedSearch
|
|
250
250
|
def register_named_scope! # :nodoc
|
251
251
|
definition = self
|
252
252
|
@klass.scope(:search_for, proc { |query, options|
|
253
|
-
search_scope = ActiveRecord::VERSION::MAJOR == 3 ? @klass.scoped : @klass
|
253
|
+
search_scope = ActiveRecord::VERSION::MAJOR == 3 ? @klass.scoped : (ActiveRecord::VERSION::MINOR < 1 ? @klass.where(nil) : @klass.all)
|
254
254
|
|
255
255
|
find_options = ScopedSearch::QueryBuilder.build_query(definition, query || '', options || {})
|
256
256
|
search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
|
@@ -83,17 +83,21 @@ module ScopedSearch
|
|
83
83
|
return find_attributes
|
84
84
|
end
|
85
85
|
|
86
|
-
def
|
86
|
+
def find_field_for_order_by(order, &block)
|
87
87
|
order ||= definition.default_order
|
88
|
-
return nil if order.blank?
|
88
|
+
return [nil, nil] if order.blank?
|
89
89
|
field_name, direction_name = order.to_s.split(/\s+/, 2)
|
90
90
|
field = definition.field_by_name(field_name)
|
91
91
|
raise ScopedSearch::QueryNotSupported, "the field '#{field_name}' in the order statement is not valid field for search" unless field
|
92
|
+
return field, direction_name
|
93
|
+
end
|
94
|
+
|
95
|
+
def order_by(order, &block)
|
96
|
+
field, direction_name = find_field_for_order_by(order, &block)
|
97
|
+
return nil if field.nil?
|
92
98
|
sql = field.to_sql(&block)
|
93
99
|
direction = (!direction_name.nil? && direction_name.downcase.eql?('desc')) ? " DESC" : " ASC"
|
94
|
-
|
95
|
-
|
96
|
-
return order
|
100
|
+
return sql + direction
|
97
101
|
end
|
98
102
|
|
99
103
|
# A hash that maps the operators of the query language with the corresponding SQL operator.
|
@@ -516,7 +520,10 @@ module ScopedSearch
|
|
516
520
|
|
517
521
|
def order_by(order, &block)
|
518
522
|
sql = super(order, &block)
|
519
|
-
|
523
|
+
if sql
|
524
|
+
field, _ = find_field_for_order_by(order, &block)
|
525
|
+
sql += sql.include?('DESC') ? ' NULLS LAST ' : ' NULLS FIRST ' if !field.nil? && field.column.null
|
526
|
+
end
|
520
527
|
sql
|
521
528
|
end
|
522
529
|
end
|
@@ -22,7 +22,7 @@ module ScopedSearch
|
|
22
22
|
|
23
23
|
ascend = "#{field} ASC"
|
24
24
|
descend = "#{field} DESC"
|
25
|
-
|
25
|
+
selected_sort = [ascend, descend].find { |o| o == params[:order] }
|
26
26
|
|
27
27
|
case params[:order]
|
28
28
|
when ascend
|
@@ -33,9 +33,9 @@ module ScopedSearch
|
|
33
33
|
new_sort = ["ASC", "DESC"].include?(options[:default]) ? "#{field} #{options[:default]}" : ascend
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
unless selected_sort.nil?
|
37
37
|
css_classes = html_options[:class] ? html_options[:class].split(" ") : []
|
38
|
-
if
|
38
|
+
if selected_sort == ascend
|
39
39
|
options[:as] = "▲ #{options[:as]}"
|
40
40
|
css_classes << "ascending"
|
41
41
|
else
|
@@ -89,6 +89,10 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
89
89
|
Foo.complete_for('date ').should =~ (["date = ", "date < ", "date > "])
|
90
90
|
end
|
91
91
|
|
92
|
+
it "should complete when query is already distinct" do
|
93
|
+
Foo.uniq.complete_for('int =').length.should > 0
|
94
|
+
end
|
95
|
+
|
92
96
|
it "should raise error for unindexed field" do
|
93
97
|
lambda { Foo.complete_for('unindexed = 10 ')}.should raise_error(ScopedSearch::QueryNotSupported)
|
94
98
|
end
|
@@ -91,6 +91,10 @@ require "spec_helper"
|
|
91
91
|
Item.complete_for('facts.').length.should == 2
|
92
92
|
end
|
93
93
|
|
94
|
+
it "should complete facts names with partial name" do
|
95
|
+
Item.complete_for('facts.c').length.should == 1
|
96
|
+
end
|
97
|
+
|
94
98
|
it "should complete values for fact name = color" do
|
95
99
|
Item.complete_for('facts.color = ').length.should == 2
|
96
100
|
end
|
@@ -31,6 +31,51 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
31
31
|
ScopedSearch::RSpec::Database.close_connection
|
32
32
|
end
|
33
33
|
|
34
|
+
context 'with no scoped_search defaults' do
|
35
|
+
|
36
|
+
before(:all) do
|
37
|
+
@class2 = ScopedSearch::RSpec::Database.create_model(
|
38
|
+
:string => :string,
|
39
|
+
:another => :string,
|
40
|
+
) do |klass|
|
41
|
+
klass.scoped_search :on => :string
|
42
|
+
klass.scoped_search :on => :another
|
43
|
+
end
|
44
|
+
|
45
|
+
@class2.create!(:string => 'foo', :another => 'foo')
|
46
|
+
@class2.create!(:string => 'bar', :another => 'foo')
|
47
|
+
@class2.create!(:string => 'baz', :another => 'bar')
|
48
|
+
end
|
49
|
+
|
50
|
+
after(:all) do
|
51
|
+
ScopedSearch::RSpec::Database.drop_model(@class2)
|
52
|
+
end
|
53
|
+
|
54
|
+
context '#search_for with an empty string' do
|
55
|
+
|
56
|
+
it 'should not remove previous scope' do
|
57
|
+
@class2.where(another: 'foo').search_for('').count.should == 2
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return an ActiveRecord::Relation' do
|
61
|
+
@class2.search_for('').should be_a(ActiveRecord::Relation)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context '#search_for with nil' do
|
67
|
+
it 'should not remove previous scope' do
|
68
|
+
@class2.where(another: 'foo').search_for(nil).count.should == 2
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return an ActiveRecord::Relation' do
|
72
|
+
@class2.search_for(nil).should be_a(ActiveRecord::Relation)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
34
79
|
context 'in an implicit string field' do
|
35
80
|
it "should find the record with an exact string match" do
|
36
81
|
@class.search_for('foo').length.should == 1
|
@@ -70,4 +70,26 @@ describe ScopedSearch::RailsHelper do
|
|
70
70
|
params[:order] = "field ASC"
|
71
71
|
sort("other")
|
72
72
|
end
|
73
|
+
|
74
|
+
it "should add no styling by default" do
|
75
|
+
should_receive(:url_for)
|
76
|
+
should_receive(:a_link).with('Field', anything, hash_excluding(:class))
|
77
|
+
sort("field")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should add ascending style for current ascending sort order " do
|
81
|
+
should_receive(:url_for)
|
82
|
+
should_receive(:a_link).with('▲ Field', anything, hash_including(:class => 'ascending'))
|
83
|
+
|
84
|
+
params[:order] = "field ASC"
|
85
|
+
sort("field")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should add descending style for current descending sort order " do
|
89
|
+
should_receive(:url_for)
|
90
|
+
should_receive(:a_link).with('▼ Field', anything, hash_including(:class => 'descending'))
|
91
|
+
|
92
|
+
params[:order] = "field DESC"
|
93
|
+
sort("field")
|
94
|
+
end
|
73
95
|
end
|
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: 3.2.
|
4
|
+
version: 3.2.1
|
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: 2015-
|
13
|
+
date: 2015-06-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|