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.
Files changed (35) hide show
  1. data/.gitignore +7 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +308 -0
  4. data/Rakefile +35 -0
  5. data/VERSION.yml +5 -0
  6. data/init.rb +1 -0
  7. data/lib/searchlogic.rb +56 -0
  8. data/lib/searchlogic/active_record/association_proxy.rb +19 -0
  9. data/lib/searchlogic/active_record/consistency.rb +49 -0
  10. data/lib/searchlogic/active_record/named_scope_tools.rb +101 -0
  11. data/lib/searchlogic/core_ext/object.rb +43 -0
  12. data/lib/searchlogic/core_ext/proc.rb +17 -0
  13. data/lib/searchlogic/named_scopes/alias_scope.rb +67 -0
  14. data/lib/searchlogic/named_scopes/association_conditions.rb +131 -0
  15. data/lib/searchlogic/named_scopes/association_ordering.rb +44 -0
  16. data/lib/searchlogic/named_scopes/conditions.rb +226 -0
  17. data/lib/searchlogic/named_scopes/or_conditions.rb +141 -0
  18. data/lib/searchlogic/named_scopes/ordering.rb +48 -0
  19. data/lib/searchlogic/rails_helpers.rb +79 -0
  20. data/lib/searchlogic/search.rb +251 -0
  21. data/rails/init.rb +1 -0
  22. data/searchlogic.gemspec +89 -0
  23. data/spec/searchlogic/active_record/association_proxy_spec.rb +23 -0
  24. data/spec/searchlogic/active_record/consistency_spec.rb +28 -0
  25. data/spec/searchlogic/core_ext/object_spec.rb +9 -0
  26. data/spec/searchlogic/core_ext/proc_spec.rb +8 -0
  27. data/spec/searchlogic/named_scopes/alias_scope_spec.rb +23 -0
  28. data/spec/searchlogic/named_scopes/association_conditions_spec.rb +198 -0
  29. data/spec/searchlogic/named_scopes/association_ordering_spec.rb +27 -0
  30. data/spec/searchlogic/named_scopes/conditions_spec.rb +319 -0
  31. data/spec/searchlogic/named_scopes/or_conditions_spec.rb +66 -0
  32. data/spec/searchlogic/named_scopes/ordering_spec.rb +34 -0
  33. data/spec/searchlogic/search_spec.rb +459 -0
  34. data/spec/spec_helper.rb +132 -0
  35. 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