lazy-searchlogic 2.4.10

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.
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe "Or conditions" 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 "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,416 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe "Search" do
4
+ context "implementation" do
5
+ it "should create a search proxy" do
6
+ User.search(:username => "joe").should be_kind_of(Searchlogic::Search)
7
+ end
8
+
9
+ it "should create a search proxy using the same class" do
10
+ User.search.klass.should == User
11
+ end
12
+
13
+ it "should pass on the current scope to the proxy" do
14
+ company = Company.create
15
+ user = company.users.create
16
+ search = company.users.search
17
+ search.current_scope.should == company.users.scope(:find)
18
+ end
19
+ end
20
+
21
+ context "initialization" do
22
+ it "should require a class" do
23
+ lambda { Searchlogic::Search.new }.should raise_error(ArgumentError)
24
+ end
25
+
26
+ it "should set the conditions" do
27
+ search = User.search(:username => "bjohnson")
28
+ search.conditions.should == {:username => "bjohnson"}
29
+ end
30
+ end
31
+
32
+ it "should clone properly" do
33
+ company = Company.create
34
+ user1 = company.users.create(:age => 5)
35
+ user2 = company.users.create(:age => 25)
36
+ search1 = company.users.search(:age_gt => 10)
37
+ search2 = search1.clone
38
+ search2.age_gt = 1
39
+ search2.all.should == User.all
40
+ search1.all.should == [user2]
41
+ end
42
+
43
+ it "should clone properly without scope" do
44
+ user1 = User.create(:age => 5)
45
+ user2 = User.create(:age => 25)
46
+ search1 = User.search(:age_gt => 10)
47
+ search2 = search1.clone
48
+ search2.age_gt = 1
49
+ search2.all.should == User.all
50
+ search1.all.should == [user2]
51
+ end
52
+
53
+ it "should delete the condition" do
54
+ search = User.search(:username_like => "bjohnson")
55
+ search.delete("username_like")
56
+ search.username_like.should be_nil
57
+ end
58
+
59
+ context "conditions" do
60
+ it "should set the conditions and be accessible individually" do
61
+ search = User.search
62
+ search.conditions = {:username => "bjohnson"}
63
+ search.username.should == "bjohnson"
64
+ end
65
+
66
+ it "should set the conditions and allow string keys" do
67
+ search = User.search
68
+ search.conditions = {"username" => "bjohnson"}
69
+ search.username.should == "bjohnson"
70
+ end
71
+
72
+ it "should use custom scopes before normalizing" do
73
+ User.create(:username => "bjohnson")
74
+ User.named_scope :username, lambda { |value| {:conditions => {:username => value.reverse}} }
75
+ search1 = User.search(:username => "bjohnson")
76
+ search2 = User.search(:username => "nosnhojb")
77
+ search1.count.should == 0
78
+ search2.count.should == 1
79
+ end
80
+
81
+ # We ignore them upon execution. But we still want to accept the condition so that returning the conditions
82
+ # preserves the values.
83
+ it "should ignore blank values but still return on conditions" do
84
+ search = User.search
85
+ search.conditions = {"username" => ""}
86
+ search.username.should be_nil
87
+ search.conditions.should == {:username => ""}
88
+ end
89
+
90
+ it "should not ignore blank values and should not cast them" do
91
+ search = User.search
92
+ search.conditions = {"id_equals" => ""}
93
+ search.id_equals.should be_nil
94
+ search.conditions.should == {:id_equals => ""}
95
+ end
96
+
97
+ it "should ignore blank values in arrays" do
98
+ search = User.search
99
+ search.conditions = {"username_equals_any" => [""]}
100
+ search.username_equals_any.should be_nil
101
+
102
+ search.conditions = {"id_equals_any" => ["", "1"]}
103
+ search.id_equals_any.should == [1]
104
+ end
105
+ end
106
+
107
+ context "condition accessors" do
108
+ it "should allow setting exact columns individually" do
109
+ search = User.search
110
+ search.username = "bjohnson"
111
+ search.username.should == "bjohnson"
112
+ end
113
+
114
+ it "should allow setting local column conditions individually" do
115
+ search = User.search
116
+ search.username_gt = "bjohnson"
117
+ search.username_gt.should == "bjohnson"
118
+ end
119
+
120
+ it "should allow chaining conditions" do
121
+ user = User.create(:username => "bjohnson", :age => 20)
122
+ User.create(:username => "bjohnson", :age => 5)
123
+ search = User.search
124
+ search.username_equals("bjohnson").age_gt(10)
125
+ search.all.should == [user]
126
+ end
127
+
128
+ it "should allow setting association conditions" do
129
+ search = User.search
130
+ search.orders_total_gt = 10
131
+ search.orders_total_gt.should == 10
132
+ end
133
+
134
+ it "should allow setting pre-existing association conditions" do
135
+ User.named_scope :uname, lambda { |value| {:conditions => ["users.username = ?", value]} }
136
+ search = Company.search
137
+ search.users_uname = "bjohnson"
138
+ search.users_uname.should == "bjohnson"
139
+ end
140
+
141
+ it "should allow setting pre-existing association alias conditions" do
142
+ User.alias_scope :username_has, lambda { |value| User.username_like(value) }
143
+ search = Company.search
144
+ search.users_username_has = "bjohnson"
145
+ search.users_username_has.should == "bjohnson"
146
+ end
147
+
148
+ it "should allow using custom conditions" do
149
+ User.named_scope(:four_year_olds, { :conditions => { :age => 4 } })
150
+ search = User.search
151
+ search.four_year_olds = true
152
+ search.four_year_olds.should == true
153
+ search.proxy_options.should == User.four_year_olds.proxy_options
154
+ end
155
+
156
+ it "should not merge conflicting conditions into one value" do
157
+ # This class should JUST be a proxy. It should not do anything more than that.
158
+ # A user would be allowed to call both named scopes if they wanted.
159
+ search = User.search
160
+ search.username_greater_than = "bjohnson1"
161
+ search.username_gt = "bjohnson2"
162
+ search.username_greater_than.should == "bjohnson1"
163
+ search.username_gt.should == "bjohnson2"
164
+ end
165
+
166
+ it "should allow setting custom conditions individually with an arity of 0" do
167
+ User.named_scope(:four_year_olds, :conditions => {:age => 4})
168
+ search = User.search
169
+ search.four_year_olds = true
170
+ search.four_year_olds.should == true
171
+ end
172
+
173
+ it "should allow setting custom conditions individually with an arity of 1" do
174
+ User.named_scope(:username_should_be, lambda { |u| {:conditions => {:username => u}} })
175
+ search = User.search
176
+ search.username_should_be = "bjohnson"
177
+ search.username_should_be.should == "bjohnson"
178
+ end
179
+
180
+ it "should not allow setting conditions that are not scopes" do
181
+ search = User.search
182
+ lambda { search.unknown = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
183
+ end
184
+
185
+ it "should not allow setting conditions on sensitive methods" do
186
+ search = User.search
187
+ lambda { search.destroy = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
188
+ end
189
+
190
+ it "should not use the ruby implementation of the id method" do
191
+ search = User.search
192
+ search.id.should be_nil
193
+ end
194
+
195
+ context "type casting" do
196
+ it "should be a Boolean given true" do
197
+ search = User.search
198
+ search.id_nil = true
199
+ search.id_nil.should == true
200
+ end
201
+
202
+ it "should be a Boolean given 'true'" do
203
+ search = User.search
204
+ search.id_nil = "true"
205
+ search.id_nil.should == true
206
+ end
207
+
208
+ it "should be a Boolean given '1'" do
209
+ search = User.search
210
+ search.id_nil = "1"
211
+ search.id_nil.should == true
212
+ end
213
+
214
+ it "should be a Boolean given false" do
215
+ search = User.search
216
+ search.id_nil = false
217
+ search.id_nil.should == false
218
+ end
219
+
220
+ it "should be a Boolean given 'false'" do
221
+ search = User.search
222
+ search.id_nil = "false"
223
+ search.id_nil.should == false
224
+ end
225
+
226
+ it "should be a Boolean given '0'" do
227
+ search = User.search
228
+ search.id_nil = "0"
229
+ search.id_nil.should == false
230
+ end
231
+
232
+ it "should be an Integer given ''" do
233
+ search = User.search
234
+ search.id_gt = ''
235
+ search.id_gt.should == 0
236
+ end
237
+
238
+ it "should be an Integer given 1" do
239
+ search = User.search
240
+ search.id_gt = 1
241
+ search.id_gt.should == 1
242
+ end
243
+
244
+ it "should be an Integer given '1'" do
245
+ search = User.search
246
+ search.id_gt = "1"
247
+ search.id_gt.should == 1
248
+ end
249
+
250
+ it "should be a Float given 1.0" do
251
+ search = Order.search
252
+ search.total_gt = 1.0
253
+ search.total_gt.should == 1.0
254
+ end
255
+
256
+ it "should be a Float given '1'" do
257
+ search = Order.search
258
+ search.total_gt = "1"
259
+ search.total_gt.should == 1.0
260
+ end
261
+
262
+ it "should be a Float given '1.5'" do
263
+ search = Order.search
264
+ search.total_gt = "1.5"
265
+ search.total_gt.should == 1.5
266
+ end
267
+
268
+ it "should be a Range given 1..3" do
269
+ search = Order.search
270
+ search.total_eq = (1..3)
271
+ search.total_eq.should == (1..3)
272
+ end
273
+
274
+ it "should be a Date given 'Jan 1, 2009'" do
275
+ search = Order.search
276
+ search.shipped_on_after = "Jan 1, 2009"
277
+ search.shipped_on_after.should == Date.parse("Jan 1, 2009")
278
+ end
279
+
280
+ it "should be a Time given 'Jan 1, 2009'" do
281
+ search = Order.search
282
+ search.created_at_after = "Jan 1, 2009"
283
+ search.created_at_after.should == Time.zone.parse("Jan 1, 2009")
284
+ end
285
+
286
+ it "should be a Time given 'Jan 1, 2009 9:33AM'" do
287
+ search = Order.search
288
+ search.created_at_after = "Jan 1, 2009 9:33AM"
289
+ search.created_at_after.should == Time.zone.parse("Jan 1, 2009 9:33AM")
290
+ end
291
+
292
+ it "should convert the time to the current zone" do
293
+ search = Order.search
294
+ now = Time.now
295
+ search.created_at_after = now
296
+ search.created_at_after.should == now.in_time_zone
297
+ end
298
+
299
+ it "should be an Array and cast it's values given ['1', '2', '3']" do
300
+ search = Order.search
301
+ search.id_equals_any = ["1", "2", "3"]
302
+ search.id_equals_any.should == [1, 2, 3]
303
+ end
304
+
305
+ it "should type cast association conditions" do
306
+ search = User.search
307
+ search.orders_total_gt = "10"
308
+ search.orders_total_gt.should == 10
309
+ end
310
+
311
+ it "should type cast deep association conditions" do
312
+ search = Company.search
313
+ search.users_orders_total_gt = "10"
314
+ search.users_orders_total_gt.should == 10
315
+ end
316
+ end
317
+ end
318
+
319
+ context "taking action" do
320
+ it "should return all when not given any conditions" do
321
+ 3.times { User.create }
322
+ User.search.all.length.should == 3
323
+ end
324
+
325
+ it "should implement the current scope based on an association" do
326
+ User.create
327
+ company = Company.create
328
+ user = company.users.create
329
+ company.users.search.all.should == [user]
330
+ end
331
+
332
+ it "should implement the current scope based on a named scope" do
333
+ User.named_scope(:four_year_olds, :conditions => {:age => 4})
334
+ (3..5).each { |age| User.create(:age => age) }
335
+ User.four_year_olds.search.all.should == User.find_all_by_age(4)
336
+ end
337
+
338
+ it "should call named scopes for conditions" do
339
+ User.search(:age_less_than => 5).proxy_options.should == User.age_less_than(5).proxy_options
340
+ end
341
+
342
+ it "should alias exact column names to use equals" do
343
+ User.search(:username => "joe").proxy_options.should == User.username_equals("joe").proxy_options
344
+ end
345
+
346
+ it "should recognize conditions with a value of true where the named scope has an arity of 0" do
347
+ User.search(:username_nil => true).proxy_options.should == User.username_nil.proxy_options
348
+ end
349
+
350
+ it "should ignore conditions with a value of false where the named scope has an arity of 0" do
351
+ User.search(:username_nil => false).proxy_options.should == {}
352
+ end
353
+
354
+ it "should not ignore conditions with a value of false where the named scope does not have an arity of 0" do
355
+ User.search(:username_is => false).proxy_options.should == User.username_is(false).proxy_options
356
+ end
357
+
358
+ it "should recognize the order condition" do
359
+ User.search(:order => "ascend_by_username").proxy_options.should == User.ascend_by_username.proxy_options
360
+ end
361
+
362
+ it "should pass array values as multiple arguments with arity -1" do
363
+ User.named_scope(:multiple_args, lambda { |*args|
364
+ raise "This should not be an array, it should be 1" if args.first.is_a?(Array)
365
+ {:conditions => ["id IN (?)", args]}
366
+ })
367
+ User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args(1,2).proxy_options
368
+ end
369
+
370
+ it "should pass array as a single value with arity >= 0" do
371
+ User.named_scope(:multiple_args, lambda { |args|
372
+ raise "This should be an array" if !args.is_a?(Array)
373
+ {:conditions => ["id IN (?)", args]}
374
+ })
375
+ User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args(1,2).proxy_options
376
+ end
377
+
378
+ it "should not split out dates or times (big fix)" do
379
+ s = User.search
380
+ s.created_at_after = Time.now
381
+ lambda { s.count }.should_not raise_error
382
+ end
383
+
384
+ it "should not include blank values" do
385
+ s = User.search
386
+ s.conditions = {"id_equals" => ""}
387
+ s.proxy_options.should == {}
388
+ end
389
+ end
390
+
391
+ context "method delegation" do
392
+ it "should respond to count" do
393
+ User.create(:username => "bjohnson")
394
+ search1 = User.search(:username => "bjohnson")
395
+ search2 = User.search(:username => "nosnhojb")
396
+ search1.count.should == 1
397
+ search2.count.should == 0
398
+ end
399
+
400
+ it "should respond to empty?" do
401
+ User.create(:username => "bjohnson")
402
+ search1 = User.search(:username => "bjohnson")
403
+ search2 = User.search(:username => "nosnhojb")
404
+ search1.empty?.should == false
405
+ search2.empty?.should == true
406
+ end
407
+
408
+ it "should delegate to named scopes with arity > 1" do
409
+ User.named_scope :paged, lambda {|start, limit| { :limit => limit, :offset => start }}
410
+ User.create(:username => "bjohnson")
411
+ search = User.search(:username => "bjohnson")
412
+ search.paged(0, 1).count.should == 1
413
+ search.paged(0, 0).count.should == 0
414
+ end
415
+ end
416
+ end