scoped_search 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
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.0"
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}".gsub(/\s+/," ")}
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 = (timestamp.day_fraction == 0) ? 1.day : 1.hour
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.key_field
191
- yield(:parameter, lhs.sub(/^.*\./,''))
192
- end
193
- if field.ext_method
194
- return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block)
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(builder, definition, &block)
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
- when :like then 'ILIKE'
452
- when :unlike then 'NOT ILIKE'
453
- else super(operator, field)
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.
@@ -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.0"
7
- s.date = "2011-05-16"
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 != ", "string !~ ", "string = ", "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 != ", "int < ", "int <= ", "int = ", "int > ", "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 = ", "date < ", "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 and", "string ~ fo or")
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(" has", " not")
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 = baz')
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 string '])
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? string '])
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? explicit '])
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? explicit '])
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
@@ -222,7 +222,6 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
222
222
 
223
223
  after(:all) do
224
224
  ScopedSearch::RSpec::Database.drop_model(@foo)
225
- @record.destroy
226
225
  end
227
226
 
228
227
  it "should not find any record because first equal = 2" do
data/spec/lib/database.rb CHANGED
@@ -17,7 +17,7 @@ module ScopedSearch::RSpec::Database
17
17
  end
18
18
 
19
19
  def self.test_databases
20
- test_databases_configuration.keys
20
+ test_databases_configuration.keys.sort
21
21
  end
22
22
 
23
23
  def self.establish_named_connection(name)
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
- hash: 3
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 2
8
7
  - 3
9
- - 0
10
- version: 2.3.0
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-05-16 00:00:00 -04:00
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.6.2
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.