searchlogic-heroku 2.4.19
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 +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +308 -0
- data/Rakefile +35 -0
- data/VERSION.yml +5 -0
- data/init.rb +1 -0
- data/lib/searchlogic.rb +56 -0
- data/lib/searchlogic/active_record/association_proxy.rb +19 -0
- data/lib/searchlogic/active_record/consistency.rb +49 -0
- data/lib/searchlogic/active_record/named_scope_tools.rb +101 -0
- data/lib/searchlogic/core_ext/object.rb +43 -0
- data/lib/searchlogic/core_ext/proc.rb +17 -0
- data/lib/searchlogic/named_scopes/alias_scope.rb +67 -0
- data/lib/searchlogic/named_scopes/association_conditions.rb +131 -0
- data/lib/searchlogic/named_scopes/association_ordering.rb +44 -0
- data/lib/searchlogic/named_scopes/conditions.rb +226 -0
- data/lib/searchlogic/named_scopes/or_conditions.rb +141 -0
- data/lib/searchlogic/named_scopes/ordering.rb +48 -0
- data/lib/searchlogic/rails_helpers.rb +79 -0
- data/lib/searchlogic/search.rb +251 -0
- data/rails/init.rb +1 -0
- data/searchlogic.gemspec +89 -0
- data/spec/searchlogic/active_record/association_proxy_spec.rb +23 -0
- data/spec/searchlogic/active_record/consistency_spec.rb +28 -0
- data/spec/searchlogic/core_ext/object_spec.rb +9 -0
- data/spec/searchlogic/core_ext/proc_spec.rb +8 -0
- data/spec/searchlogic/named_scopes/alias_scope_spec.rb +23 -0
- data/spec/searchlogic/named_scopes/association_conditions_spec.rb +198 -0
- data/spec/searchlogic/named_scopes/association_ordering_spec.rb +27 -0
- data/spec/searchlogic/named_scopes/conditions_spec.rb +319 -0
- data/spec/searchlogic/named_scopes/or_conditions_spec.rb +66 -0
- data/spec/searchlogic/named_scopes/ordering_spec.rb +34 -0
- data/spec/searchlogic/search_spec.rb +459 -0
- data/spec/spec_helper.rb +132 -0
- metadata +128 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe Searchlogic::NamedScopes::Ordering do
|
4
|
+
it "should allow ascending" do
|
5
|
+
Company.ascend_by_users_username.proxy_options.should == User.ascend_by_username.proxy_options.merge(:joins => :users)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should allow descending" do
|
9
|
+
Company.descend_by_users_username.proxy_options.should == User.descend_by_username.proxy_options.merge(:joins => :users)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should allow deep ascending" do
|
13
|
+
Company.ascend_by_users_orders_total.proxy_options.should == Order.ascend_by_total.proxy_options.merge(:joins => {:users => :orders})
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should allow deep descending" do
|
17
|
+
Company.descend_by_users_orders_total.proxy_options.should == Order.descend_by_total.proxy_options.merge(:joins => {:users => :orders})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should ascend with a belongs to" do
|
21
|
+
User.ascend_by_company_name.proxy_options.should == Company.ascend_by_name.proxy_options.merge(:joins => :company)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should work through #order" do
|
25
|
+
Company.order('ascend_by_users_username').proxy_options.should == Company.ascend_by_users_username.proxy_options
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe Searchlogic::NamedScopes::Conditions do
|
4
|
+
it "should be dynamically created and then cached" do
|
5
|
+
User.should_not respond_to(:age_less_than)
|
6
|
+
User.age_less_than(5)
|
7
|
+
User.should respond_to(:age_less_than)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not allow conditions on non columns" do
|
11
|
+
lambda { User.whatever_equals(2) }.should raise_error(NoMethodError)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "comparison conditions" do
|
15
|
+
it "should have equals" do
|
16
|
+
(5..7).each { |age| User.create(:age => age) }
|
17
|
+
User.age_equals(6).all.should == User.find_all_by_age(6)
|
18
|
+
User.age_equals(5..6).all.should == User.find_all_by_age(5..6)
|
19
|
+
User.age_equals([5, 7]).all.should == User.find_all_by_age([5, 7])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have does not equal" do
|
23
|
+
(5..7).each { |age| User.create(:age => age) }
|
24
|
+
User.age_does_not_equal(6).all.should == User.find_all_by_age([5,7])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have less than" do
|
28
|
+
(5..7).each { |age| User.create(:age => age) }
|
29
|
+
User.age_less_than(6).all.should == User.find_all_by_age(5)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have less than or equal to" do
|
33
|
+
(5..7).each { |age| User.create(:age => age) }
|
34
|
+
User.age_less_than_or_equal_to(6).all.should == User.find_all_by_age([5, 6])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have greater than" do
|
38
|
+
(5..7).each { |age| User.create(:age => age) }
|
39
|
+
User.age_greater_than(6).all.should == User.find_all_by_age(7)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have greater than or equal to" do
|
43
|
+
(5..7).each { |age| User.create(:age => age) }
|
44
|
+
User.age_greater_than_or_equal_to(6).all.should == User.find_all_by_age([6, 7])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "wildcard conditions" do
|
49
|
+
it "should have like" do
|
50
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
51
|
+
User.username_like("john").all.should == User.find_all_by_username("bjohnson")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have not like" do
|
55
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
56
|
+
User.username_not_like("john").all.should == User.find_all_by_username("thunt")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should have begins with" do
|
60
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
61
|
+
User.username_begins_with("bj").all.should == User.find_all_by_username("bjohnson")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have not begin with" do
|
65
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
66
|
+
User.username_not_begin_with("bj").all.should == User.find_all_by_username("thunt")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have ends with" do
|
70
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
71
|
+
User.username_ends_with("son").all.should == User.find_all_by_username("bjohnson")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have not end with" do
|
75
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
76
|
+
User.username_not_end_with("son").all.should == User.find_all_by_username("thunt")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "boolean conditions" do
|
81
|
+
it "should have scopes for boolean columns" do
|
82
|
+
female = User.create(:male => false)
|
83
|
+
male = User.create(:male => true)
|
84
|
+
User.male.all.should == [male]
|
85
|
+
User.not_male.all.should == [female]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have null" do
|
89
|
+
["bjohnson", nil].each { |username| User.create(:username => username) }
|
90
|
+
User.username_null.all.should == User.find_all_by_username(nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should have not null" do
|
94
|
+
["bjohnson", nil].each { |username| User.create(:username => username) }
|
95
|
+
User.username_not_null.all.should == User.find_all_by_username("bjohnson")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should have empty" do
|
99
|
+
["bjohnson", ""].each { |username| User.create(:username => username) }
|
100
|
+
User.username_empty.all.should == User.find_all_by_username("")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should have blank" do
|
104
|
+
["bjohnson", "", nil].each { |username| User.create(:username => username) }
|
105
|
+
User.username_blank.all.should == [User.find_by_username(""), User.find_by_username(nil)]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should have not blank" do
|
109
|
+
["bjohnson", "", nil].each { |username| User.create(:username => username) }
|
110
|
+
User.username_not_blank.all.should == User.find_all_by_username("bjohnson")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "any and all conditions" do
|
115
|
+
it "should do nothing if no arguments are passed" do
|
116
|
+
User.username_equals_any.proxy_options.should == {}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should treat an array and multiple arguments the same" do
|
120
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
121
|
+
User.username_like_any("bjohnson", "thunt").should == User.username_like_any(["bjohnson", "thunt"])
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should have equals any" do
|
125
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
126
|
+
User.username_equals_any("bjohnson", "thunt").all.should == User.find_all_by_username(["bjohnson", "thunt"])
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should have equals all" do
|
130
|
+
%w(bjohnson thunt dainor).each { |username| User.create(:username => username) }
|
131
|
+
User.username_equals_all("bjohnson", "thunt").all.should == []
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should have does not equal any" do
|
135
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
136
|
+
User.username_does_not_equal_any("bjohnson", "thunt").all.should == User.find_all_by_username(["bjohnson", "thunt", "dgainor"])
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should have does not equal all" do
|
140
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
141
|
+
User.username_does_not_equal_all("bjohnson", "thunt").all.should == User.find_all_by_username("dgainor")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should have less than any" do
|
145
|
+
(5..7).each { |age| User.create(:age => age) }
|
146
|
+
User.age_less_than_any(7,6).all.should == User.find_all_by_age([5, 6])
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should have less than all" do
|
150
|
+
(5..7).each { |age| User.create(:age => age) }
|
151
|
+
User.age_less_than_all(7,6).all.should == User.find_all_by_age(5)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should have less than or equal to any" do
|
155
|
+
(5..7).each { |age| User.create(:age => age) }
|
156
|
+
User.age_less_than_or_equal_to_any(7,6).all.should == User.find_all_by_age([5, 6, 7])
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should have less than or equal to all" do
|
160
|
+
(5..7).each { |age| User.create(:age => age) }
|
161
|
+
User.age_less_than_or_equal_to_all(7,6).all.should == User.find_all_by_age([5, 6])
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should have less than any" do
|
165
|
+
(5..7).each { |age| User.create(:age => age) }
|
166
|
+
User.age_greater_than_any(5,6).all.should == User.find_all_by_age([6, 7])
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have greater than all" do
|
170
|
+
(5..7).each { |age| User.create(:age => age) }
|
171
|
+
User.age_greater_than_all(5,6).all.should == User.find_all_by_age(7)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should have greater than or equal to any" do
|
175
|
+
(5..7).each { |age| User.create(:age => age) }
|
176
|
+
User.age_greater_than_or_equal_to_any(5,6).all.should == User.find_all_by_age([5, 6, 7])
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should have greater than or equal to all" do
|
180
|
+
(5..7).each { |age| User.create(:age => age) }
|
181
|
+
User.age_greater_than_or_equal_to_all(5,6).all.should == User.find_all_by_age([6, 7])
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should have like all" do
|
185
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
186
|
+
User.username_like_all("bjohnson", "thunt").all.should == []
|
187
|
+
User.username_like_all("n", "o").all.should == User.find_all_by_username(["bjohnson", "dgainor"])
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should have like any" do
|
191
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
192
|
+
User.username_like_any("bjohnson", "thunt").all.should == User.find_all_by_username(["bjohnson", "thunt"])
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should have begins with all" do
|
196
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
197
|
+
User.username_begins_with_all("bjohnson", "thunt").all.should == []
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should have begins with any" do
|
201
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
202
|
+
User.username_begins_with_any("bj", "th").all.should == User.find_all_by_username(["bjohnson", "thunt"])
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should have ends with all" do
|
206
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
207
|
+
User.username_ends_with_all("n", "r").all.should == []
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should have ends with any" do
|
211
|
+
%w(bjohnson thunt dgainor).each { |username| User.create(:username => username) }
|
212
|
+
User.username_ends_with_any("n", "r").all.should == User.find_all_by_username(["bjohnson", "dgainor"])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context "alias conditions" do
|
217
|
+
it "should have is" do
|
218
|
+
User.age_is(5).proxy_options.should == User.age_equals(5).proxy_options
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should have eq" do
|
222
|
+
User.age_eq(5).proxy_options.should == User.age_equals(5).proxy_options
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should have not_equal_to" do
|
226
|
+
User.age_not_equal_to(5).proxy_options.should == User.age_does_not_equal(5).proxy_options
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should have is_not" do
|
230
|
+
User.age_is_not(5).proxy_options.should == User.age_does_not_equal(5).proxy_options
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should have not" do
|
234
|
+
User.age_not(5).proxy_options.should == User.age_does_not_equal(5).proxy_options
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should have ne" do
|
238
|
+
User.age_ne(5).proxy_options.should == User.age_does_not_equal(5).proxy_options
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should have lt" do
|
242
|
+
User.age_lt(5).proxy_options.should == User.age_less_than(5).proxy_options
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should have lte" do
|
246
|
+
User.age_lte(5).proxy_options.should == User.age_less_than_or_equal_to(5).proxy_options
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should have gt" do
|
250
|
+
User.age_gt(5).proxy_options.should == User.age_greater_than(5).proxy_options
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should have gte" do
|
254
|
+
User.age_gte(5).proxy_options.should == User.age_greater_than_or_equal_to(5).proxy_options
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should have contains" do
|
258
|
+
User.username_contains(5).proxy_options.should == User.username_like(5).proxy_options
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should have contains" do
|
262
|
+
User.username_includes(5).proxy_options.should == User.username_like(5).proxy_options
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should have bw" do
|
266
|
+
User.username_bw(5).proxy_options.should == User.username_begins_with(5).proxy_options
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should have ew" do
|
270
|
+
User.username_ew(5).proxy_options.should == User.username_ends_with(5).proxy_options
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should have nil" do
|
274
|
+
User.username_nil.proxy_options.should == User.username_nil.proxy_options
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context "group conditions" do
|
279
|
+
it "should have in" do
|
280
|
+
(5..7).each { |age| User.create(:age => age) }
|
281
|
+
User.age_in([5,6]).all.should == User.find(:all, :conditions => ["users.age IN (?)", [5, 6]])
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should have not_in" do
|
285
|
+
(5..7).each { |age| User.create(:age => age) }
|
286
|
+
User.age_not_in([5,6]).all.should == User.find(:all, :conditions => ["users.age NOT IN (?)", [5, 6]])
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
context "searchlogic lambda" do
|
291
|
+
it "should be a string" do
|
292
|
+
User.username_like("test")
|
293
|
+
User.named_scope_options(:username_like).searchlogic_options[:type].should == :string
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should be an integer" do
|
297
|
+
User.id_gt(10)
|
298
|
+
User.named_scope_options(:id_gt).searchlogic_options[:type].should == :integer
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should be a float" do
|
302
|
+
Order.total_gt(10)
|
303
|
+
Order.named_scope_options(:total_gt).searchlogic_options[:type].should == :float
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should have priorty to columns over conflicting association conditions" do
|
308
|
+
Company.users_count_gt(10)
|
309
|
+
User.create
|
310
|
+
User.company_id_null.count.should == 1
|
311
|
+
User.company_id_not_null.count.should == 0
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should fix bug for issue 26" do
|
315
|
+
count1 = User.id_ne(10).username_not_like("root").count
|
316
|
+
count2 = User.id_ne(10).username_not_like("root").count
|
317
|
+
count1.should == count2
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe Searchlogic::NamedScopes::OrConditions do
|
4
|
+
it "should define a scope by the exact same name as requested by the code" do
|
5
|
+
User.name_or_username_like('Test')
|
6
|
+
User.respond_to?(:name_or_username_like).should be_true
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should match username or name" do
|
10
|
+
User.username_or_name_like("ben").proxy_options.should == {:conditions => "(users.username LIKE '%ben%') OR (users.name LIKE '%ben%')"}
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should use the specified condition" do
|
14
|
+
User.username_begins_with_or_name_like("ben").proxy_options.should == {:conditions => "(users.username LIKE 'ben%') OR (users.name LIKE '%ben%')"}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should use the last specified condition" do
|
18
|
+
User.username_or_name_like_or_id_or_age_lt(10).proxy_options.should == {:conditions => "(users.username LIKE '%10%') OR (users.name LIKE '%10%') OR (users.id < 10) OR (users.age < 10)"}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error on unknown conditions" do
|
22
|
+
lambda { User.usernme_begins_with_or_name_like("ben") }.should raise_error(Searchlogic::NamedScopes::OrConditions::UnknownConditionError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should work well with _or_equal_to" do
|
26
|
+
User.id_less_than_or_equal_to_or_age_gt(10).proxy_options.should == {:conditions => "(users.id <= 10) OR (users.age > 10)"}
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should work well with _or_equal_to_any" do
|
30
|
+
User.id_less_than_or_equal_to_all_or_age_gt(10).proxy_options.should == {:conditions => "(users.id <= 10) OR (users.age > 10)"}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should work well with _or_equal_to_all" do
|
34
|
+
User.id_less_than_or_equal_to_any_or_age_gt(10).proxy_options.should == {:conditions => "(users.id <= 10) OR (users.age > 10)"}
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should play nice with other scopes" do
|
38
|
+
User.username_begins_with("ben").id_gt(10).age_not_nil.username_or_name_ends_with("ben").scope(:find).should ==
|
39
|
+
{:conditions => "((users.username LIKE '%ben') OR (users.name LIKE '%ben')) AND ((users.age IS NOT NULL) AND ((users.id > 10) AND (users.username LIKE 'ben%')))"}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should play nice with scopes on associations" do
|
43
|
+
lambda { User.name_or_company_name_like("ben") }.should_not raise_error(Searchlogic::NamedScopes::OrConditions::NoConditionSpecifiedError)
|
44
|
+
User.name_or_company_name_like("ben").proxy_options.should == {:joins => :company, :conditions => "(users.name LIKE '%ben%') OR (companies.name LIKE '%ben%')"}
|
45
|
+
User.company_name_or_name_like("ben").proxy_options.should == {:joins => :company, :conditions => "(companies.name LIKE '%ben%') OR (users.name LIKE '%ben%')"}
|
46
|
+
User.company_name_or_company_description_like("ben").proxy_options.should == {:joins =>[:company], :conditions => "(companies.name LIKE '%ben%') OR (companies.description LIKE '%ben%')"}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not get confused by the 'or' in find_or_create_by_* methods" do
|
50
|
+
User.create(:name => "Fred")
|
51
|
+
User.find_or_create_by_name("Fred").should be_a_kind_of User
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not get confused by the 'or' in compound find_or_create_by_* methods" do
|
55
|
+
User.create(:name => "Fred", :username => "fredb")
|
56
|
+
User.find_or_create_by_name_and_username("Fred", "fredb").should be_a_kind_of User
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should work with User.search(conditions) method" do
|
60
|
+
User.search(:username_or_name_like => 'ben').proxy_options.should == {:conditions => "(users.username LIKE '%ben%') OR (users.name LIKE '%ben%')"}
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should convert types properly when used with User.search(conditions) method" do
|
64
|
+
User.search(:id_or_age_lte => '10').proxy_options.should == {:conditions => "(users.id <= 10) OR (users.age <= 10)"}
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
|
2
|
+
|
3
|
+
describe Searchlogic::NamedScopes::Ordering do
|
4
|
+
it "should be dynamically created and then cached" do
|
5
|
+
User.should_not respond_to(:ascend_by_username)
|
6
|
+
User.ascend_by_username
|
7
|
+
User.should respond_to(:ascend_by_username)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have ascending" do
|
11
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
12
|
+
User.ascend_by_username.all.should == User.all(:order => "username ASC")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have descending" do
|
16
|
+
%w(bjohnson thunt).each { |username| User.create(:username => username) }
|
17
|
+
User.descend_by_username.all.should == User.all(:order => "username DESC")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have order" do
|
21
|
+
User.order("ascend_by_username").proxy_options.should == User.ascend_by_username.proxy_options
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have order by custom scope" do
|
25
|
+
User.column_names.should_not include("custom")
|
26
|
+
%w(bjohnson thunt fisons).each { |username| User.create(:username => username) }
|
27
|
+
User.named_scope(:ascend_by_custom, :order => "username ASC, name DESC")
|
28
|
+
User.order("ascend_by_custom").proxy_options.should == User.ascend_by_custom.proxy_options
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should have priorty to columns over conflicting association columns" do
|
32
|
+
Company.ascend_by_users_count
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
|
3
|
+
describe Searchlogic::Search do
|
4
|
+
describe "Implementation" do
|
5
|
+
context "#searchlogic" do
|
6
|
+
it "should create a search proxy" do
|
7
|
+
User.search(:username => "joe").should be_kind_of(Searchlogic::Search)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should create a search proxy using the same class" do
|
11
|
+
User.search.klass.should == User
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should pass on the current scope to the proxy" do
|
15
|
+
company = Company.create
|
16
|
+
user = company.users.create
|
17
|
+
search = company.users.search
|
18
|
+
search.current_scope.should == company.users.scope(:find)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "#initialize" do
|
24
|
+
it "should require a class" do
|
25
|
+
lambda { Searchlogic::Search.new }.should raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should set the conditions" do
|
29
|
+
search = User.search(:username => "bjohnson")
|
30
|
+
search.conditions.should == {:username => "bjohnson"}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "#clone" do
|
35
|
+
it "should clone properly" do
|
36
|
+
company = Company.create
|
37
|
+
user1 = company.users.create(:age => 5)
|
38
|
+
user2 = company.users.create(:age => 25)
|
39
|
+
search1 = company.users.search(:age_gt => 10)
|
40
|
+
search2 = search1.clone
|
41
|
+
search2.age_gt = 1
|
42
|
+
search2.all.should == User.all
|
43
|
+
search1.all.should == [user2]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should clone properly without scope" do
|
47
|
+
user1 = User.create(:age => 5)
|
48
|
+
user2 = User.create(:age => 25)
|
49
|
+
search1 = User.search(:age_gt => 10)
|
50
|
+
search2 = search1.clone
|
51
|
+
search2.age_gt = 1
|
52
|
+
search2.all.should == User.all
|
53
|
+
search1.all.should == [user2]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "#conditions" do
|
58
|
+
it "should set the conditions and be accessible individually" do
|
59
|
+
search = User.search
|
60
|
+
search.conditions = {:username => "bjohnson"}
|
61
|
+
search.username.should == "bjohnson"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set the conditions and allow string keys" do
|
65
|
+
search = User.search
|
66
|
+
search.conditions = {"username" => "bjohnson"}
|
67
|
+
search.username.should == "bjohnson"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should use custom scopes before normalizing" do
|
71
|
+
User.create(:username => "bjohnson")
|
72
|
+
User.named_scope :username, lambda { |value| {:conditions => {:username => value.reverse}} }
|
73
|
+
search1 = User.search(:username => "bjohnson")
|
74
|
+
search2 = User.search(:username => "nosnhojb")
|
75
|
+
search1.count.should == 0
|
76
|
+
search2.count.should == 1
|
77
|
+
end
|
78
|
+
|
79
|
+
# We ignore them upon execution. But we still want to accept the condition so that returning the conditions
|
80
|
+
# preserves the values.
|
81
|
+
it "should ignore blank values but still return on conditions" do
|
82
|
+
search = User.search
|
83
|
+
search.conditions = {"username" => ""}
|
84
|
+
search.username.should be_nil
|
85
|
+
search.conditions.should == {:username => ""}
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not ignore blank values and should not cast them" do
|
89
|
+
search = User.search
|
90
|
+
search.conditions = {"id_equals" => ""}
|
91
|
+
search.id_equals.should be_nil
|
92
|
+
search.conditions.should == {:id_equals => ""}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should ignore blank values in arrays" do
|
96
|
+
search = User.search
|
97
|
+
search.conditions = {"username_equals_any" => [""]}
|
98
|
+
search.username_equals_any.should be_nil
|
99
|
+
|
100
|
+
search.conditions = {"id_equals_any" => ["", "1"]}
|
101
|
+
search.id_equals_any.should == [1]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "condition accessors" do
|
106
|
+
it "should allow setting exact columns individually" do
|
107
|
+
search = User.search
|
108
|
+
search.username = "bjohnson"
|
109
|
+
search.username.should == "bjohnson"
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should allow setting local column conditions individually" do
|
113
|
+
search = User.search
|
114
|
+
search.username_gt = "bjohnson"
|
115
|
+
search.username_gt.should == "bjohnson"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should allow chaining conditions" do
|
119
|
+
user = User.create(:username => "bjohnson", :age => 20)
|
120
|
+
User.create(:username => "bjohnson", :age => 5)
|
121
|
+
search = User.search
|
122
|
+
search.username_equals("bjohnson").age_gt(10)
|
123
|
+
search.all.should == [user]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should allow setting association conditions" do
|
127
|
+
search = User.search
|
128
|
+
search.orders_total_gt = 10
|
129
|
+
search.orders_total_gt.should == 10
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should allow setting pre-existing association conditions" do
|
133
|
+
User.named_scope :uname, lambda { |value| {:conditions => ["users.username = ?", value]} }
|
134
|
+
search = Company.search
|
135
|
+
search.users_uname = "bjohnson"
|
136
|
+
search.users_uname.should == "bjohnson"
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should allow setting pre-existing association alias conditions" do
|
140
|
+
User.alias_scope :username_has, lambda { |value| User.username_like(value) }
|
141
|
+
search = Company.search
|
142
|
+
search.users_username_has = "bjohnson"
|
143
|
+
search.users_username_has.should == "bjohnson"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should allow using custom conditions" do
|
147
|
+
User.named_scope(:four_year_olds, { :conditions => { :age => 4 } })
|
148
|
+
search = User.search
|
149
|
+
search.four_year_olds = true
|
150
|
+
search.four_year_olds.should == true
|
151
|
+
search.proxy_options.should == User.four_year_olds.proxy_options
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should not merge conflicting conditions into one value" do
|
155
|
+
# This class should JUST be a proxy. It should not do anything more than that.
|
156
|
+
# A user would be allowed to call both named scopes if they wanted.
|
157
|
+
search = User.search
|
158
|
+
search.username_greater_than = "bjohnson1"
|
159
|
+
search.username_gt = "bjohnson2"
|
160
|
+
search.username_greater_than.should == "bjohnson1"
|
161
|
+
search.username_gt.should == "bjohnson2"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should allow setting custom conditions individually with an arity of 0" do
|
165
|
+
User.named_scope(:four_year_olds, :conditions => {:age => 4})
|
166
|
+
search = User.search
|
167
|
+
search.four_year_olds = true
|
168
|
+
search.four_year_olds.should == true
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should allow setting custom conditions individually with an arity of 1" do
|
172
|
+
User.named_scope(:username_should_be, lambda { |u| {:conditions => {:username => u}} })
|
173
|
+
search = User.search
|
174
|
+
search.username_should_be = "bjohnson"
|
175
|
+
search.username_should_be.should == "bjohnson"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should not allow setting conditions that are not scopes" do
|
179
|
+
search = User.search
|
180
|
+
lambda { search.unknown = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should not allow setting conditions on sensitive methods" do
|
184
|
+
search = User.search
|
185
|
+
lambda { search.destroy = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should not use the ruby implementation of the id method" do
|
189
|
+
search = User.search
|
190
|
+
search.id.should be_nil
|
191
|
+
end
|
192
|
+
|
193
|
+
context "type casting" do
|
194
|
+
it "should be a Boolean given true" do
|
195
|
+
search = User.search
|
196
|
+
search.id_nil = true
|
197
|
+
search.id_nil.should == true
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should be a Boolean given 'true'" do
|
201
|
+
search = User.search
|
202
|
+
search.id_nil = "true"
|
203
|
+
search.id_nil.should == true
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should be a Boolean given '1'" do
|
207
|
+
search = User.search
|
208
|
+
search.id_nil = "1"
|
209
|
+
search.id_nil.should == true
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should be a Boolean given false" do
|
213
|
+
search = User.search
|
214
|
+
search.id_nil = false
|
215
|
+
search.id_nil.should == false
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should be a Boolean given 'false'" do
|
219
|
+
search = User.search
|
220
|
+
search.id_nil = "false"
|
221
|
+
search.id_nil.should == false
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should be a Boolean given '0'" do
|
225
|
+
search = User.search
|
226
|
+
search.id_nil = "0"
|
227
|
+
search.id_nil.should == false
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should be an Integer given ''" do
|
231
|
+
search = User.search
|
232
|
+
search.id_gt = ''
|
233
|
+
search.id_gt.should == 0
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should be an Integer given 1" do
|
237
|
+
search = User.search
|
238
|
+
search.id_gt = 1
|
239
|
+
search.id_gt.should == 1
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should be an Integer given '1'" do
|
243
|
+
search = User.search
|
244
|
+
search.id_gt = "1"
|
245
|
+
search.id_gt.should == 1
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should be a Float given 1.0" do
|
249
|
+
search = Order.search
|
250
|
+
search.total_gt = 1.0
|
251
|
+
search.total_gt.should == 1.0
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should be a Float given '1'" do
|
255
|
+
search = Order.search
|
256
|
+
search.total_gt = "1"
|
257
|
+
search.total_gt.should == 1.0
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should be a Float given '1.5'" do
|
261
|
+
search = Order.search
|
262
|
+
search.total_gt = "1.5"
|
263
|
+
search.total_gt.should == 1.5
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should be a Range given 1..3" do
|
267
|
+
search = Order.search
|
268
|
+
search.total_eq = (1..3)
|
269
|
+
search.total_eq.should == (1..3)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should be a Date given 'Jan 1, 2009'" do
|
273
|
+
search = Order.search
|
274
|
+
search.shipped_on_after = "Jan 1, 2009"
|
275
|
+
search.shipped_on_after.should == Date.parse("Jan 1, 2009")
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should be a Time given 'Jan 1, 2009'" do
|
279
|
+
search = Order.search
|
280
|
+
search.created_at_after = "Jan 1, 2009"
|
281
|
+
search.created_at_after.should == Time.zone.parse("Jan 1, 2009")
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should be a Time given 'Jan 1, 2009 9:33AM'" do
|
285
|
+
search = Order.search
|
286
|
+
search.created_at_after = "Jan 1, 2009 9:33AM"
|
287
|
+
search.created_at_after.should == Time.zone.parse("Jan 1, 2009 9:33AM")
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should skip time zone conversion for attributes skipped" do
|
291
|
+
search = User.search
|
292
|
+
search.whatever_at_after = "Jan 1, 2009 9:33AM"
|
293
|
+
search.whatever_at_after.should == Time.parse("Jan 1, 2009 9:33AM").utc
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should convert the time to the current zone" do
|
297
|
+
search = Order.search
|
298
|
+
now = Time.now
|
299
|
+
search.created_at_after = now
|
300
|
+
search.created_at_after.should == now.in_time_zone
|
301
|
+
end
|
302
|
+
|
303
|
+
it "should be an Array and cast it's values given ['1', '2', '3']" do
|
304
|
+
search = Order.search
|
305
|
+
search.id_equals_any = ["1", "2", "3"]
|
306
|
+
search.id_equals_any.should == [1, 2, 3]
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should type cast association conditions" do
|
310
|
+
search = User.search
|
311
|
+
search.orders_total_gt = "10"
|
312
|
+
search.orders_total_gt.should == 10
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should type cast deep association conditions" do
|
316
|
+
search = Company.search
|
317
|
+
search.users_orders_total_gt = "10"
|
318
|
+
search.users_orders_total_gt.should == 10
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should support Rails' date_select and datetime_select out of the box" do
|
322
|
+
search = Company.search('created_at_after(1i)' => 2000, 'created_at_after(2i)' => 1, 'created_at_after(3i)' => 1)
|
323
|
+
search.created_at_after.should_not be_nil
|
324
|
+
search.created_at_after.should == Time.zone.local(2000, 1, 1)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context "#delete" do
|
330
|
+
it "should delete the condition" do
|
331
|
+
search = User.search(:username_like => "bjohnson")
|
332
|
+
search.delete("username_like")
|
333
|
+
search.username_like.should be_nil
|
334
|
+
search.conditions["username_like"].should be_nil
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context "#ordering_by" do
|
339
|
+
it "should return nil if we aren't ordering" do
|
340
|
+
search = User.search
|
341
|
+
search.ordering_by.should be_nil
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should return the column name for ascending" do
|
345
|
+
search = User.search(:order => "ascend_by_first_name")
|
346
|
+
search.ordering_by.should == "first_name"
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should return the column name for descending" do
|
350
|
+
search = User.search(:order => "descend_by_first_name")
|
351
|
+
search.ordering_by.should == "first_name"
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should handle symbols" do
|
355
|
+
search = User.search(:order => :descend_by_first_name)
|
356
|
+
search.ordering_by.should == "first_name"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context "#method_missing" do
|
361
|
+
context "setting" do
|
362
|
+
it "should call named scopes for conditions" do
|
363
|
+
User.search(:age_less_than => 5).proxy_options.should == User.age_less_than(5).proxy_options
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should alias exact column names to use equals" do
|
367
|
+
User.search(:username => "joe").proxy_options.should == User.username_equals("joe").proxy_options
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should recognize conditions with a value of true where the named scope has an arity of 0" do
|
371
|
+
User.search(:username_nil => true).proxy_options.should == User.username_nil.proxy_options
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should ignore conditions with a value of false where the named scope has an arity of 0" do
|
375
|
+
User.search(:username_nil => false).proxy_options.should == {}
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should not ignore conditions with a value of false where the named scope does not have an arity of 0" do
|
379
|
+
User.search(:username_is => false).proxy_options.should == User.username_is(false).proxy_options
|
380
|
+
end
|
381
|
+
|
382
|
+
it "should recognize the order condition" do
|
383
|
+
User.search(:order => "ascend_by_username").proxy_options.should == User.ascend_by_username.proxy_options
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should pass array values as multiple arguments with arity -1" do
|
387
|
+
User.named_scope(:multiple_args, lambda { |*args|
|
388
|
+
raise "This should not be an array, it should be 1" if args.first.is_a?(Array)
|
389
|
+
{:conditions => ["id IN (?)", args]}
|
390
|
+
})
|
391
|
+
User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args(1,2).proxy_options
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should pass array as a single value with arity >= 0" do
|
395
|
+
User.named_scope(:multiple_args, lambda { |args|
|
396
|
+
raise "This should be an array" if !args.is_a?(Array)
|
397
|
+
{:conditions => ["id IN (?)", args]}
|
398
|
+
})
|
399
|
+
User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args([1,2]).proxy_options
|
400
|
+
end
|
401
|
+
|
402
|
+
it "should not split out dates or times (big fix)" do
|
403
|
+
s = User.search
|
404
|
+
s.created_at_after = Time.now
|
405
|
+
lambda { s.count }.should_not raise_error
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should not include blank values" do
|
409
|
+
s = User.search
|
410
|
+
s.conditions = {"id_equals" => ""}
|
411
|
+
s.proxy_options.should == {}
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context "delegation" do
|
417
|
+
it "should return all when not given any conditions" do
|
418
|
+
3.times { User.create }
|
419
|
+
User.search.all.length.should == 3
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should implement the current scope based on an association" do
|
423
|
+
User.create
|
424
|
+
company = Company.create
|
425
|
+
user = company.users.create
|
426
|
+
company.users.search.all.should == [user]
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should implement the current scope based on a named scope" do
|
430
|
+
User.named_scope(:four_year_olds, :conditions => {:age => 4})
|
431
|
+
(3..5).each { |age| User.create(:age => age) }
|
432
|
+
User.four_year_olds.search.all.should == User.find_all_by_age(4)
|
433
|
+
end
|
434
|
+
|
435
|
+
it "should respond to count" do
|
436
|
+
User.create(:username => "bjohnson")
|
437
|
+
search1 = User.search(:username => "bjohnson")
|
438
|
+
search2 = User.search(:username => "nosnhojb")
|
439
|
+
search1.count.should == 1
|
440
|
+
search2.count.should == 0
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should respond to empty?" do
|
444
|
+
User.create(:username => "bjohnson")
|
445
|
+
search1 = User.search(:username => "bjohnson")
|
446
|
+
search2 = User.search(:username => "nosnhojb")
|
447
|
+
search1.empty?.should == false
|
448
|
+
search2.empty?.should == true
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should delegate to named scopes with arity > 1" do
|
452
|
+
User.named_scope :paged, lambda {|start, limit| { :limit => limit, :offset => start }}
|
453
|
+
User.create(:username => "bjohnson")
|
454
|
+
search = User.search(:username => "bjohnson")
|
455
|
+
search.paged(0, 1).count.should == 1
|
456
|
+
search.paged(0, 0).count.should == 0
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|