scoped_search 2.0.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/.gitignore +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +107 -0
- data/Rakefile +4 -0
- data/init.rb +1 -0
- data/lib/scoped_search.rb +91 -0
- data/lib/scoped_search/definition.rb +145 -0
- data/lib/scoped_search/query_builder.rb +296 -0
- data/lib/scoped_search/query_language.rb +38 -0
- data/lib/scoped_search/query_language/ast.rb +141 -0
- data/lib/scoped_search/query_language/parser.rb +120 -0
- data/lib/scoped_search/query_language/tokenizer.rb +78 -0
- data/scoped_search.gemspec +32 -0
- data/spec/database.yml +25 -0
- data/spec/integration/api_spec.rb +82 -0
- data/spec/integration/ordinal_querying_spec.rb +158 -0
- data/spec/integration/relation_querying_spec.rb +262 -0
- data/spec/integration/string_querying_spec.rb +192 -0
- data/spec/lib/database.rb +49 -0
- data/spec/lib/matchers.rb +40 -0
- data/spec/lib/mocks.rb +19 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/ast_spec.rb +197 -0
- data/spec/unit/definition_spec.rb +24 -0
- data/spec/unit/parser_spec.rb +104 -0
- data/spec/unit/query_builder_spec.rb +22 -0
- data/spec/unit/tokenizer_spec.rb +97 -0
- data/tasks/github-gem.rake +323 -0
- metadata +117 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
# These specs will run on all databases that are defined in the spec/database.yml file.
|
4
|
+
# Comment out any databases that you do not have available for testing purposes if needed.
|
5
|
+
ScopedSearch::Spec::Database.test_databases.each do |db|
|
6
|
+
|
7
|
+
describe ScopedSearch, "using a #{db} database" do
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
ScopedSearch::Spec::Database.establish_named_connection(db)
|
11
|
+
|
12
|
+
@class = ScopedSearch::Spec::Database.create_model(:int => :integer, :timestamp => :datetime, :date => :date, :unindexed => :integer) do |klass|
|
13
|
+
klass.scoped_search :on => [:int, :timestamp]
|
14
|
+
klass.scoped_search :on => :date, :only_explicit => true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
after(:all) do
|
19
|
+
ScopedSearch::Spec::Database.drop_model(@class)
|
20
|
+
ScopedSearch::Spec::Database.close_connection
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'quering numerical fields' do
|
24
|
+
|
25
|
+
before(:all) do
|
26
|
+
@record = @class.create!(:int => 9)
|
27
|
+
end
|
28
|
+
|
29
|
+
after(:all) do
|
30
|
+
@record.destroy
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should find the record with an exact integer match" do
|
34
|
+
@class.search_for('9').should have(1).item
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should find the record with an exact integer match with an explicit operator" do
|
38
|
+
@class.search_for('= 9').should have(1).item
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should find the record with an exact integer match with an explicit field name" do
|
42
|
+
@class.search_for('int = 9').should have(1).item
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should find the record with an exact integer match with an explicit field name" do
|
46
|
+
@class.search_for('int > 8').should have(1).item
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should find the record with a grater than operator and explicit field" do
|
50
|
+
@class.search_for('int > 9').should have(0).item
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should find the record with an >= operator with an implicit field name" do
|
54
|
+
@class.search_for('>= 9').should have(1).item
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not return the record if only one predicate is true and AND is used (by default)" do
|
58
|
+
@class.search_for('int <= 8, int > 8').should have(0).item
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return the record in only one predicate is true and OR is used as operator" do
|
62
|
+
@class.search_for('int <= 8 || int > 8').should have(1).item
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'querying unindexed fields' do
|
67
|
+
|
68
|
+
before(:all) do
|
69
|
+
@record = @class.create!(:int => 9, :unindexed => 10)
|
70
|
+
end
|
71
|
+
|
72
|
+
after(:all) do
|
73
|
+
@record.destroy
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should raise an error when explicitly searching in the non-indexed column" do
|
77
|
+
lambda { @class.search_for('unindexed = 10') }.should raise_error(ScopedSearch::Exception)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should not return records for which the query matches unindex records" do
|
81
|
+
@class.search_for('= 10').should have(0).item
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'querying date and time fields' do
|
86
|
+
|
87
|
+
before(:all) do
|
88
|
+
@record = @class.create!(:timestamp => Time.parse('2009-01-02 14:51:44'), :date => Date.parse('2009-01-02'))
|
89
|
+
@nil_record = @class.create!(:timestamp => nil, :date => nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
after(:all) do
|
93
|
+
@record.destroy
|
94
|
+
@nil_record.destroy
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should accept YYYY-MM-DD as date format" do
|
98
|
+
@class.search_for('date = 2009-01-02').should have(1).item
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should accept YY-MM-DD as date format" do
|
102
|
+
@class.search_for('date = 09-01-02').should have(1).item
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should accept MM/DD/YY as date format" do
|
106
|
+
@class.search_for('date = 01/02/09').should have(1).item
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should accept YYYY/MM/DD as date format" do
|
110
|
+
@class.search_for('date = 2009/01/02').should have(1).item
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should accept MM/DD/YYYY as date format" do
|
114
|
+
@class.search_for('date = 01/02/2009').should have(1).item
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should ignore an invalid date and thus return all records" do
|
118
|
+
@class.search_for('>= 2009-14-57').should have(2).items
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should find the records with a timestamp set some point on the provided date" do
|
122
|
+
@class.search_for('>= 2009-01-02').should have(1).item
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should support full timestamps" do
|
126
|
+
@class.search_for('> "2009-01-02 02:02:02"').should have(1).item
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should find no record with a timestamp in the past" do
|
130
|
+
@class.search_for('< 2009-01-02').should have(0).item
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should find all timestamps on a date if no time is given using the = operator" do
|
134
|
+
@class.search_for('= 2009-01-02').should have(1).item
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should find all timestamps on a date if no time is when no operator is given" do
|
138
|
+
@class.search_for('2009-01-02').should have(1).item
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should find all timestamps not on a date if no time is given using the != operator" do
|
142
|
+
@class.search_for('!= 2009-01-02').should have(0).item
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should find the records when the date part of a timestamp matches a date" do
|
146
|
+
@class.search_for('>= 2009-01-02').should have(1).item
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should find the record with the timestamp today or in the past" do
|
150
|
+
@class.search_for('<= 2009-01-02').should have(1).item
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should find no record with a timestamp later than today" do
|
154
|
+
@class.search_for('> 2009-01-02').should have(0).item
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
# These specs will run on all databases that are defined in the spec/database.yml file.
|
4
|
+
# Comment out any databases that you do not have available for testing purposes if needed.
|
5
|
+
ScopedSearch::Spec::Database.test_databases.each do |db|
|
6
|
+
|
7
|
+
describe ScopedSearch, "using a #{db} database" do
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
ScopedSearch::Spec::Database.establish_named_connection(db)
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
ScopedSearch::Spec::Database.close_connection
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'querying a :belongs_to relation' do
|
18
|
+
|
19
|
+
before(:all) do
|
20
|
+
|
21
|
+
# The related class
|
22
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related }
|
23
|
+
class Bar < ActiveRecord::Base; has_many :foos; end
|
24
|
+
|
25
|
+
# The class on which to call search_for
|
26
|
+
Foo = ScopedSearch::Spec::Database.create_model(:foo => :string, :bar_id => :integer) do |klass|
|
27
|
+
klass.belongs_to :bar
|
28
|
+
klass.scoped_search :in => :bar, :on => :related
|
29
|
+
end
|
30
|
+
|
31
|
+
@bar_record = Bar.create!(:related => 'bar')
|
32
|
+
|
33
|
+
Foo.create!(:foo => 'foo', :bar => @bar_record)
|
34
|
+
Foo.create!(:foo => 'foo too', :bar => @bar_record)
|
35
|
+
Foo.create!(:foo => 'foo three', :bar => Bar.create!(:related => 'another bar'))
|
36
|
+
Foo.create!(:foo => 'foo four')
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:all) do
|
40
|
+
ScopedSearch::Spec::Database.drop_model(Bar)
|
41
|
+
ScopedSearch::Spec::Database.drop_model(Foo)
|
42
|
+
Object.send :remove_const, :Foo
|
43
|
+
Object.send :remove_const, :Bar
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should find all records with a related bar record containing bar" do
|
47
|
+
Foo.search_for('bar').should have(3).items
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should find all records with a related bar record having an exact value of bar" do
|
51
|
+
Foo.search_for('= bar').should have(2).items
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should find all records with a related bar record having an exact value of bar with an explicit field" do
|
55
|
+
Foo.search_for('related = bar').should have(2).items
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should find records for which the bar relation is not set using null?" do
|
59
|
+
Foo.search_for('null? related').should have(1).items
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'querying a :has_many relation' do
|
64
|
+
|
65
|
+
before(:all) do
|
66
|
+
|
67
|
+
# The related class
|
68
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
|
69
|
+
class Bar < ActiveRecord::Base; belongs_to :foo; end
|
70
|
+
|
71
|
+
# The class on which to call search_for
|
72
|
+
Foo = ScopedSearch::Spec::Database.create_model(:foo => :string, :bar_id => :integer) do |klass|
|
73
|
+
klass.has_many :bars
|
74
|
+
klass.scoped_search :in => :bars, :on => :related
|
75
|
+
end
|
76
|
+
|
77
|
+
@foo_1 = Foo.create!(:foo => 'foo')
|
78
|
+
@foo_2 = Foo.create!(:foo => 'foo too')
|
79
|
+
@foo_3 = Foo.create!(:foo => 'foo three')
|
80
|
+
|
81
|
+
Bar.create!(:related => 'bar', :foo => @foo_1)
|
82
|
+
Bar.create!(:related => 'another bar', :foo => @foo_1)
|
83
|
+
Bar.create!(:related => 'other bar', :foo => @foo_2)
|
84
|
+
end
|
85
|
+
|
86
|
+
after(:all) do
|
87
|
+
ScopedSearch::Spec::Database.drop_model(Bar)
|
88
|
+
ScopedSearch::Spec::Database.drop_model(Foo)
|
89
|
+
Object.send :remove_const, :Foo
|
90
|
+
Object.send :remove_const, :Bar
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should find all records with at least one bar record containing 'bar'" do
|
94
|
+
Foo.search_for('bar').should have(2).items
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should find the only record with at least one bar record having the exact value 'bar'" do
|
98
|
+
Foo.search_for('= bar').should have(1).item
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should find all records for which at least one related bar record exists" do
|
102
|
+
Foo.search_for('set? related').should have(2).items
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should find all records for which none related bar records exist" do
|
106
|
+
Foo.search_for('null? related').should have(1).items
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'querying a :has_one relation' do
|
112
|
+
|
113
|
+
before(:all) do
|
114
|
+
|
115
|
+
# The related class
|
116
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related; t.integer :foo_id }
|
117
|
+
class Bar < ActiveRecord::Base; belongs_to :foo; end
|
118
|
+
|
119
|
+
# The class on which to call search_for
|
120
|
+
Foo = ScopedSearch::Spec::Database.create_model(:foo => :string) do |klass|
|
121
|
+
klass.has_one :bar
|
122
|
+
klass.scoped_search :in => :bar, :on => :related
|
123
|
+
end
|
124
|
+
|
125
|
+
@foo_1 = Foo.create!(:foo => 'foo')
|
126
|
+
@foo_2 = Foo.create!(:foo => 'foo too')
|
127
|
+
@foo_3 = Foo.create!(:foo => 'foo three')
|
128
|
+
|
129
|
+
Bar.create!(:related => 'bar', :foo => @foo_1)
|
130
|
+
Bar.create!(:related => 'other bar', :foo => @foo_2)
|
131
|
+
end
|
132
|
+
|
133
|
+
after(:all) do
|
134
|
+
ScopedSearch::Spec::Database.drop_model(Bar)
|
135
|
+
ScopedSearch::Spec::Database.drop_model(Foo)
|
136
|
+
Object.send :remove_const, :Foo
|
137
|
+
Object.send :remove_const, :Bar
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should find all records with a bar record containing 'bar" do
|
141
|
+
Foo.search_for('bar').should have(2).items
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should find the only record with the bar record has the exact value 'bar" do
|
145
|
+
Foo.search_for('= bar').should have(1).item
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should find all records for which the related bar record exists" do
|
149
|
+
Foo.search_for('set? related').should have(2).items
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should find all records for which the related bar record does not exist" do
|
153
|
+
Foo.search_for('null? related').should have(1).items
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'querying a :has_and_belongs_to_many relation' do
|
158
|
+
|
159
|
+
before(:all) do
|
160
|
+
|
161
|
+
# Create some tables
|
162
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.string :related }
|
163
|
+
ActiveRecord::Migration.create_table(:bars_foos, :id => false) { |t| t.integer :foo_id; t.integer :bar_id }
|
164
|
+
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
165
|
+
|
166
|
+
# The related class
|
167
|
+
class Bar < ActiveRecord::Base; end
|
168
|
+
|
169
|
+
# The class on which to call search_for
|
170
|
+
class Foo < ActiveRecord::Base
|
171
|
+
has_and_belongs_to_many :bars
|
172
|
+
scoped_search :in => :bars, :on => :related
|
173
|
+
end
|
174
|
+
|
175
|
+
@foo_1 = Foo.create!(:foo => 'foo')
|
176
|
+
@foo_2 = Foo.create!(:foo => 'foo too')
|
177
|
+
@foo_3 = Foo.create!(:foo => 'foo three')
|
178
|
+
|
179
|
+
@bar_1 = Bar.create!(:related => 'bar')
|
180
|
+
@bar_2 = Bar.create!(:related => 'other bar')
|
181
|
+
@bar_3 = Bar.create!(:related => 'last bar')
|
182
|
+
|
183
|
+
@foo_1.bars << @bar_1 << @bar_2
|
184
|
+
@foo_2.bars << @bar_2 << @bar_3
|
185
|
+
end
|
186
|
+
|
187
|
+
after(:all) do
|
188
|
+
ActiveRecord::Migration.drop_table(:bars_foos)
|
189
|
+
ActiveRecord::Migration.drop_table(:bars)
|
190
|
+
ActiveRecord::Migration.drop_table(:foos)
|
191
|
+
Object.send :remove_const, :Foo
|
192
|
+
Object.send :remove_const, :Bar
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should find all records with at least one associated bar record containing 'bar'" do
|
196
|
+
Foo.search_for('bar').should have(2).items
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should find record which is related to @bar_1" do
|
200
|
+
Foo.search_for('= bar').should have(1).items
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should find the only record related to @bar_3" do
|
204
|
+
Foo.search_for('last').should have(1).items
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should find all records that are related to @bar_2" do
|
208
|
+
Foo.search_for('other').should have(2).items
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context 'querying a :has_many => :through relation' do
|
213
|
+
|
214
|
+
before(:all) do
|
215
|
+
|
216
|
+
# Create some tables
|
217
|
+
ActiveRecord::Migration.create_table(:bars) { |t| t.integer :foo_id; t.integer :baz_id }
|
218
|
+
ActiveRecord::Migration.create_table(:bazs) { |t| t.string :related }
|
219
|
+
ActiveRecord::Migration.create_table(:foos) { |t| t.string :foo }
|
220
|
+
|
221
|
+
# The related classes
|
222
|
+
class Bar < ActiveRecord::Base; belongs_to :baz; belongs_to :foo; end
|
223
|
+
class Baz < ActiveRecord::Base; has_many :bars; end
|
224
|
+
|
225
|
+
# The class on which to call search_for
|
226
|
+
class Foo < ActiveRecord::Base
|
227
|
+
has_many :bars
|
228
|
+
has_many :bazs, :through => :bars
|
229
|
+
|
230
|
+
scoped_search :in => :bazs, :on => :related
|
231
|
+
end
|
232
|
+
|
233
|
+
@foo_1 = Foo.create!(:foo => 'foo')
|
234
|
+
@foo_2 = Foo.create!(:foo => 'foo too')
|
235
|
+
@foo_3 = Foo.create!(:foo => 'foo three')
|
236
|
+
|
237
|
+
@baz_1 = Baz.create(:related => 'baz')
|
238
|
+
@baz_2 = Baz.create(:related => 'baz too!')
|
239
|
+
|
240
|
+
@bar_1 = Bar.create!(:foo => @foo_1, :baz => @baz_1)
|
241
|
+
@bar_2 = Bar.create!(:foo => @foo_1)
|
242
|
+
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_1)
|
243
|
+
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
244
|
+
@bar_3 = Bar.create!(:foo => @foo_2, :baz => @baz_2)
|
245
|
+
@bar_4 = Bar.create!(:foo => @foo_3)
|
246
|
+
end
|
247
|
+
|
248
|
+
after(:all) do
|
249
|
+
ActiveRecord::Migration.drop_table(:bazs)
|
250
|
+
ActiveRecord::Migration.drop_table(:bars)
|
251
|
+
ActiveRecord::Migration.drop_table(:foos)
|
252
|
+
Object.send :remove_const, :Foo
|
253
|
+
Object.send :remove_const, :Bar
|
254
|
+
Object.send :remove_const, :Baz
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should find the two records that are related to a baz record" do
|
258
|
+
Foo.search_for('baz').should have(2).items
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
# These specs will run on all databases that are defined in the spec/database.yml file.
|
4
|
+
# Comment out any databases that you do not have available for testing purposes if needed.
|
5
|
+
ScopedSearch::Spec::Database.test_databases.each do |db|
|
6
|
+
|
7
|
+
describe ScopedSearch, "using a #{db} database" do
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
ScopedSearch::Spec::Database.establish_named_connection(db)
|
11
|
+
|
12
|
+
@class = ScopedSearch::Spec::Database.create_model(:string => :string, :another => :string, :explicit => :string) do |klass|
|
13
|
+
klass.scoped_search :on => :string
|
14
|
+
klass.scoped_search :on => :another, :default_operator => :eq, :alias => :alias
|
15
|
+
klass.scoped_search :on => :explicit, :only_explicit => true
|
16
|
+
end
|
17
|
+
|
18
|
+
@class.create!(:string => 'foo', :another => 'temp 1', :explicit => 'baz')
|
19
|
+
@class.create!(:string => 'bar', :another => 'temp 2', :explicit => 'baz')
|
20
|
+
@class.create!(:string => 'baz', :another => 'temp 3', :explicit => nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:all) do
|
24
|
+
ScopedSearch::Spec::Database.drop_model(@class)
|
25
|
+
ScopedSearch::Spec::Database.close_connection
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'in an implicit string field' do
|
29
|
+
it "should find the record with an exact string match" do
|
30
|
+
@class.search_for('foo').should have(1).item
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should find the opther two records using NOT with an exact string match" do
|
34
|
+
@class.search_for('-foo').should have(2).item
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should find the record with an exact string match and an explicit field operator" do
|
38
|
+
@class.search_for('string = foo').should have(1).item
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should find the record with an exact string match and an explicit field operator" do
|
42
|
+
@class.search_for('another = foo').should have(0).items
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should find the record with an partial string match" do
|
46
|
+
@class.search_for('fo').should have(1).item
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should find the other two records using NOT with an partial string match" do
|
50
|
+
@class.search_for('-fo').should have(2).item
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not find the record with an explicit equals operator and a partial match" do
|
54
|
+
@class.search_for('= fo').should have(0).items
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should find the record with an explicit LIKE operator and a partial match" do
|
58
|
+
@class.search_for('~ fo').should have(1).items
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should find the all other record with an explicit NOT LIKE operator and a partial match" do
|
62
|
+
@class.search_for('string !~ fo').should have(@class.count - 1).items
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not find a record with a non-match" do
|
66
|
+
@class.search_for('nonsense').should have(0).items
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should find two records if it partially matches them" do
|
70
|
+
@class.search_for('ba').should have(2).item
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should find no records starting with an a" do
|
74
|
+
@class.search_for('a%').should have(0).item
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should find one records ending with an oo" do
|
78
|
+
@class.search_for('%oo').should have(1).item
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should find records without case sensitivity when using the LIKE operator" do
|
82
|
+
@class.search_for('string ~ FOO').should have(1).item
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not find records without case sensitivity when using the = operator" do
|
86
|
+
@class.search_for('string = FOO').should have(0).items
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should find records without case sensitivity when using the != operator" do
|
90
|
+
@class.search_for('string != FOO').should have(3).items
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should find records without case sensitivity when using the NOT LIKE operator" do
|
94
|
+
@class.search_for('string !~ FOO').should have(2).items
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should find the record if one of the query words match using OR" do
|
98
|
+
@class.search_for('foo OR nonsense').should have(1).item
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should find no records in one of the AND conditions isn't met" do
|
102
|
+
@class.search_for('foo AND nonsense').should have(0).item
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should find two records every single OR conditions matches one single record" do
|
106
|
+
@class.search_for('foo OR baz').should have(2).item
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should find two records every single AND conditions matches one single record" do
|
110
|
+
@class.search_for('foo AND baz').should have(0).item
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'in a field with a different default operator' do
|
115
|
+
it "should find an exact match" do
|
116
|
+
@class.search_for('"temp 1"').should have(1).item
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should find the orther records using NOT and an exact match" do
|
120
|
+
@class.search_for('-"temp 1"').should have(2).item
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should find an explicit match" do
|
124
|
+
@class.search_for('another = "temp 1"').should have(1).item
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should not find a partial match" do
|
128
|
+
@class.search_for('temp').should have(0).item
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should find all records using a NOT with a partial match on all records" do
|
132
|
+
@class.search_for('-temp"').should have(3).item
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should find a partial match when the like operator is given" do
|
136
|
+
@class.search_for('~ temp').should have(3).item
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should find a partial match when the like operator and the field name is given" do
|
140
|
+
@class.search_for('another ~ temp').should have(3).item
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'using an aliased field' do
|
145
|
+
it "should find an explicit match using its alias" do
|
146
|
+
@class.search_for('alias = "temp 1"').should have(1).item
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'in an explicit string field' do
|
151
|
+
|
152
|
+
it "should not find the records if the explicit field is not given in the query" do
|
153
|
+
@class.search_for('= baz').should have(1).item
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should find all records when searching on the explicit field" do
|
157
|
+
@class.search_for('explicit = baz').should have(2).items
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should find no records if the value in the explicit field is not an exact match" do
|
161
|
+
@class.search_for('explicit = ba').should have(0).item
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should find all records when searching on the explicit field" do
|
165
|
+
@class.search_for('explicit ~ ba').should have(2).items
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should only find the record with string = foo and explicit = baz" do
|
169
|
+
@class.search_for('foo, explicit = baz').should have(1).item
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'using null? and set? queries' do
|
174
|
+
|
175
|
+
it "should return all records if the string field is being checked with set?" do
|
176
|
+
@class.search_for('set? string').should have(3).items
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return no records if the string field is being checked with null?" do
|
180
|
+
@class.search_for('null? string').should have(0).items
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should return all records with a value if the string field is being checked with set?" do
|
184
|
+
@class.search_for('set? explicit').should have(2).items
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should return all records without a value if the string field is being checked with null?" do
|
188
|
+
@class.search_for('null? explicit').should have(1).items
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|