scoped_search 2.3.0 → 2.3.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.
- data/lib/scoped_search.rb +1 -1
- data/lib/scoped_search/auto_complete_builder.rb +2 -2
- data/lib/scoped_search/query_builder.rb +23 -16
- data/scoped_search.gemspec +2 -2
- data/spec/integration/auto_complete_spec.rb +10 -11
- data/spec/integration/ordinal_querying_spec.rb +0 -1
- data/spec/lib/database.rb +1 -1
- metadata +5 -11
data/lib/scoped_search.rb
CHANGED
@@ -14,7 +14,7 @@ module ScopedSearch
|
|
14
14
|
|
15
15
|
# The current scoped_search version. Do not change thisvalue by hand,
|
16
16
|
# because it will be updated automatically by the gem release script.
|
17
|
-
VERSION = "2.3.
|
17
|
+
VERSION = "2.3.1"
|
18
18
|
|
19
19
|
# The ClassMethods module will be included into the ActiveRecord::Base class
|
20
20
|
# to add the <tt>ActiveRecord::Base.scoped_search</tt> method and the
|
@@ -144,7 +144,7 @@ module ScopedSearch
|
|
144
144
|
}
|
145
145
|
end
|
146
146
|
|
147
|
-
suggestions.uniq.map {|m| "#{q} #{m}"
|
147
|
+
suggestions.uniq.map {|m| "#{q} #{m}"}
|
148
148
|
end
|
149
149
|
|
150
150
|
# suggest all searchable field names.
|
@@ -230,7 +230,7 @@ module ScopedSearch
|
|
230
230
|
else
|
231
231
|
opts.merge!(key_opts)
|
232
232
|
end
|
233
|
-
return field.klass.all(opts.merge(:limit => 20)).map(&field.field)
|
233
|
+
return field.klass.all(opts.merge(:limit => 20)).map(&field.field).compact.map{|v| v.to_s =~ /\s+/ ? "\"#{v}\"" : v}
|
234
234
|
end
|
235
235
|
|
236
236
|
#this method returns conditions for selecting completion from partial value
|
@@ -104,9 +104,15 @@ module ScopedSearch
|
|
104
104
|
# By default, it will simply look up the correct SQL operator in the SQL_OPERATORS
|
105
105
|
# hash, but this can be overridden by a database adapter.
|
106
106
|
def sql_operator(operator, field)
|
107
|
+
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if [:like, :unlike].include?(operator) and !field.textual?
|
107
108
|
SQL_OPERATORS[operator]
|
108
109
|
end
|
109
110
|
|
111
|
+
# Returns a NOT (...) SQL fragment that negates the current AST node's children
|
112
|
+
def to_not_sql(rhs, definition, &block)
|
113
|
+
"NOT COALESCE(#{rhs.to_sql(self, definition, &block)}, 0)"
|
114
|
+
end
|
115
|
+
|
110
116
|
# Perform a comparison between a field and a Date(Time) value.
|
111
117
|
#
|
112
118
|
# This function makes sure the date is valid and adjust the comparison in
|
@@ -129,7 +135,8 @@ module ScopedSearch
|
|
129
135
|
# but the field is of datetime type. Change the comparison to return
|
130
136
|
# more logical results.
|
131
137
|
if field.datetime?
|
132
|
-
span =
|
138
|
+
span = 1.minute if(value =~ /\A\s*\d+\s+\bminutes?\b\s+\bago\b\s*\z/i)
|
139
|
+
span ||= (timestamp.day_fraction == 0) ? 1.day : 1.hour
|
133
140
|
if [:eq, :ne].include?(operator)
|
134
141
|
# Instead of looking for an exact (non-)match, look for dates that
|
135
142
|
# fall inside/outside the range of timestamps of that day.
|
@@ -187,12 +194,11 @@ module ScopedSearch
|
|
187
194
|
# <tt>operator</tt>:: The operator used for comparison.
|
188
195
|
# <tt>value</tt>:: The value to compare the field with.
|
189
196
|
def sql_test(field, operator, value, lhs, &block) # :yields: finder_option_type, value
|
190
|
-
if field.
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
elsif [:like, :unlike].include?(operator)
|
197
|
+
return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block) if field.ext_method
|
198
|
+
|
199
|
+
yield(:parameter, lhs.sub(/^.*\./,'')) if field.key_field
|
200
|
+
|
201
|
+
if [:like, :unlike].include?(operator)
|
196
202
|
yield(:parameter, (value !~ /^\%|\*/ && value !~ /\%|\*$/) ? "%#{value}%" : value.tr_s('%*', '%'))
|
197
203
|
return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?"
|
198
204
|
elsif field.temporal?
|
@@ -339,11 +345,6 @@ module ScopedSearch
|
|
339
345
|
# Defines the to_sql method for AST operator nodes
|
340
346
|
module OperatorNode
|
341
347
|
|
342
|
-
# Returns a NOT (...) SQL fragment that negates the current AST node's children
|
343
|
-
def to_not_sql(builder, definition, &block)
|
344
|
-
"NOT COALESCE(#{rhs.to_sql(builder, definition, &block)}, 0)"
|
345
|
-
end
|
346
|
-
|
347
348
|
# Returns an IS (NOT) NULL SQL fragment
|
348
349
|
def to_null_sql(builder, definition, &block)
|
349
350
|
field = definition.field_by_name(rhs.value)
|
@@ -387,7 +388,7 @@ module ScopedSearch
|
|
387
388
|
# Convert this AST node to an SQL fragment.
|
388
389
|
def to_sql(builder, definition, &block)
|
389
390
|
if operator == :not && children.length == 1
|
390
|
-
to_not_sql(
|
391
|
+
builder.to_not_sql(rhs, definition, &block)
|
391
392
|
elsif [:null, :notnull].include?(operator)
|
392
393
|
to_null_sql(builder, definition, &block)
|
393
394
|
elsif children.length == 1
|
@@ -447,12 +448,18 @@ module ScopedSearch
|
|
447
448
|
# Switches out the default LIKE operator for ILIKE in the default
|
448
449
|
# <tt>sql_operator</tt> method.
|
449
450
|
def sql_operator(operator, field)
|
451
|
+
raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if [:like, :unlike].include?(operator) and !field.textual?
|
450
452
|
case operator
|
451
|
-
|
452
|
-
|
453
|
-
|
453
|
+
when :like then 'ILIKE'
|
454
|
+
when :unlike then 'NOT ILIKE'
|
455
|
+
else super(operator, field)
|
454
456
|
end
|
455
457
|
end
|
458
|
+
|
459
|
+
# Returns a NOT (...) SQL fragment that negates the current AST node's children
|
460
|
+
def to_not_sql(rhs, definition, &block)
|
461
|
+
"NOT COALESCE(#{rhs.to_sql(self, definition, &block)}, false)"
|
462
|
+
end
|
456
463
|
end
|
457
464
|
|
458
465
|
# The Oracle adapter also requires some tweaks to make the case insensitive LIKE work.
|
data/scoped_search.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not change the version and date fields by hand. This will be done
|
5
5
|
# automatically by the gem release script.
|
6
|
-
s.version = "2.3.
|
7
|
-
s.date = "2011-
|
6
|
+
s.version = "2.3.1"
|
7
|
+
s.date = "2011-06-22"
|
8
8
|
|
9
9
|
s.summary = "Easily search you ActiveRecord models with a simple query language using a named scope."
|
10
10
|
s.description = <<-EOS
|
@@ -34,7 +34,6 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
34
34
|
|
35
35
|
after(:all) do
|
36
36
|
ScopedSearch::RSpec::Database.drop_model(Foo)
|
37
|
-
ScopedSearch::RSpec::Database.drop_model(Bar)
|
38
37
|
ScopedSearch::RSpec::Database.close_connection
|
39
38
|
end
|
40
39
|
|
@@ -48,15 +47,15 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
48
47
|
end
|
49
48
|
|
50
49
|
it "should complete the string comparators" do
|
51
|
-
Foo.complete_for('string ').should =~ (["string
|
50
|
+
Foo.complete_for('string ').should =~ (["string != ", "string !~ ", "string = ", "string ~ "])
|
52
51
|
end
|
53
52
|
|
54
53
|
it "should complete the numerical comparators" do
|
55
|
-
Foo.complete_for('int ').should =~ (["int
|
54
|
+
Foo.complete_for('int ').should =~ (["int != ", "int < ", "int <= ", "int = ", "int > ", "int >= "])
|
56
55
|
end
|
57
56
|
|
58
57
|
it "should complete the temporal (date) comparators" do
|
59
|
-
Foo.complete_for('date ').should =~ (["date
|
58
|
+
Foo.complete_for('date ').should =~ (["date = ", "date < ", "date > "])
|
60
59
|
end
|
61
60
|
|
62
61
|
it "should raise error for unindexed field" do
|
@@ -68,11 +67,11 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
68
67
|
end
|
69
68
|
|
70
69
|
it "should complete logical comparators" do
|
71
|
-
Foo.complete_for('string ~ fo ').should contain("string ~ fo
|
70
|
+
Foo.complete_for('string ~ fo ').should contain("string ~ fo and", "string ~ fo or")
|
72
71
|
end
|
73
72
|
|
74
73
|
it "should complete prefix operators" do
|
75
|
-
Foo.complete_for(' ').should contain("
|
74
|
+
Foo.complete_for(' ').should contain(" has", " not")
|
76
75
|
end
|
77
76
|
|
78
77
|
it "should not complete logical infix operators" do
|
@@ -96,7 +95,7 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
96
95
|
end
|
97
96
|
|
98
97
|
it "should complete values should contain baz" do
|
99
|
-
Foo.complete_for('explicit = ').should contain('explicit =
|
98
|
+
Foo.complete_for('explicit = ').should contain('explicit = baz')
|
100
99
|
end
|
101
100
|
end
|
102
101
|
|
@@ -113,19 +112,19 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
|
|
113
112
|
context 'using null prefix operators queries' do
|
114
113
|
|
115
114
|
it "should complete has operator" do
|
116
|
-
Foo.complete_for('has strin').should eql(['has
|
115
|
+
Foo.complete_for('has strin').should eql(['has string '])
|
117
116
|
end
|
118
117
|
|
119
118
|
it "should complete null? operator" do
|
120
|
-
Foo.complete_for('null? st').should eql(['null?
|
119
|
+
Foo.complete_for('null? st').should eql(['null? string '])
|
121
120
|
end
|
122
121
|
|
123
122
|
it "should complete set? operator" do
|
124
|
-
Foo.complete_for('set? exp').should eql(['set?
|
123
|
+
Foo.complete_for('set? exp').should eql(['set? explicit '])
|
125
124
|
end
|
126
125
|
|
127
126
|
it "should complete null? operator for explicit field" do
|
128
|
-
Foo.complete_for('null? explici').should eql(['null?
|
127
|
+
Foo.complete_for('null? explici').should eql(['null? explicit '])
|
129
128
|
end
|
130
129
|
|
131
130
|
it "should not complete comparators after prefix statement" do
|
data/spec/lib/database.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scoped_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 2
|
8
7
|
- 3
|
9
|
-
-
|
10
|
-
version: 2.3.
|
8
|
+
- 1
|
9
|
+
version: 2.3.1
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Willem van Bergen
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2011-
|
18
|
+
date: 2011-06-22 00:00:00 -04:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -27,7 +26,6 @@ dependencies:
|
|
27
26
|
requirements:
|
28
27
|
- - ">="
|
29
28
|
- !ruby/object:Gem::Version
|
30
|
-
hash: 11
|
31
29
|
segments:
|
32
30
|
- 2
|
33
31
|
- 1
|
@@ -43,7 +41,6 @@ dependencies:
|
|
43
41
|
requirements:
|
44
42
|
- - ~>
|
45
43
|
- !ruby/object:Gem::Version
|
46
|
-
hash: 3
|
47
44
|
segments:
|
48
45
|
- 2
|
49
46
|
- 0
|
@@ -58,7 +55,6 @@ dependencies:
|
|
58
55
|
requirements:
|
59
56
|
- - ">="
|
60
57
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 3
|
62
58
|
segments:
|
63
59
|
- 0
|
64
60
|
version: "0"
|
@@ -131,7 +127,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
127
|
requirements:
|
132
128
|
- - ">="
|
133
129
|
- !ruby/object:Gem::Version
|
134
|
-
hash: 3
|
135
130
|
segments:
|
136
131
|
- 0
|
137
132
|
version: "0"
|
@@ -140,14 +135,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
135
|
requirements:
|
141
136
|
- - ">="
|
142
137
|
- !ruby/object:Gem::Version
|
143
|
-
hash: 3
|
144
138
|
segments:
|
145
139
|
- 0
|
146
140
|
version: "0"
|
147
141
|
requirements: []
|
148
142
|
|
149
143
|
rubyforge_project:
|
150
|
-
rubygems_version: 1.
|
144
|
+
rubygems_version: 1.3.7
|
151
145
|
signing_key:
|
152
146
|
specification_version: 3
|
153
147
|
summary: Easily search you ActiveRecord models with a simple query language using a named scope.
|