mongodoc 0.2.2 → 0.2.4

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 (57) hide show
  1. data/Rakefile +21 -0
  2. data/TODO +6 -1
  3. data/VERSION +1 -1
  4. data/features/finders.feature +1 -1
  5. data/features/mongodoc_base.feature +11 -2
  6. data/features/{named_scopes.feature → scopes.feature} +0 -0
  7. data/features/step_definitions/document_steps.rb +15 -4
  8. data/features/step_definitions/documents.rb +3 -3
  9. data/features/step_definitions/query_steps.rb +17 -14
  10. data/features/step_definitions/{named_scope_steps.rb → scope_steps.rb} +0 -0
  11. data/features/using_criteria.feature +22 -43
  12. data/lib/mongodoc.rb +1 -1
  13. data/lib/mongodoc/associations/collection_proxy.rb +3 -1
  14. data/lib/mongodoc/associations/document_proxy.rb +4 -1
  15. data/lib/mongodoc/associations/hash_proxy.rb +3 -1
  16. data/lib/mongodoc/associations/proxy_base.rb +6 -4
  17. data/lib/mongodoc/attributes.rb +6 -6
  18. data/lib/mongodoc/contexts.rb +24 -0
  19. data/lib/mongodoc/contexts/enumerable.rb +132 -0
  20. data/lib/mongodoc/contexts/mongo.rb +215 -0
  21. data/lib/mongodoc/criteria.rb +36 -479
  22. data/lib/mongodoc/document.rb +3 -2
  23. data/lib/mongodoc/finders.rb +31 -11
  24. data/lib/mongodoc/matchers.rb +35 -0
  25. data/lib/mongodoc/scope.rb +64 -0
  26. data/lib/mongoid/contexts/paging.rb +42 -0
  27. data/lib/mongoid/criteria.rb +264 -0
  28. data/lib/mongoid/criterion/complex.rb +21 -0
  29. data/lib/mongoid/criterion/exclusion.rb +65 -0
  30. data/lib/mongoid/criterion/inclusion.rb +92 -0
  31. data/lib/mongoid/criterion/optional.rb +136 -0
  32. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  33. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  34. data/lib/mongoid/matchers/all.rb +11 -0
  35. data/lib/mongoid/matchers/default.rb +26 -0
  36. data/lib/mongoid/matchers/exists.rb +13 -0
  37. data/lib/mongoid/matchers/gt.rb +11 -0
  38. data/lib/mongoid/matchers/gte.rb +11 -0
  39. data/lib/mongoid/matchers/in.rb +11 -0
  40. data/lib/mongoid/matchers/lt.rb +11 -0
  41. data/lib/mongoid/matchers/lte.rb +11 -0
  42. data/lib/mongoid/matchers/ne.rb +11 -0
  43. data/lib/mongoid/matchers/nin.rb +11 -0
  44. data/lib/mongoid/matchers/size.rb +11 -0
  45. data/mongodoc.gemspec +39 -9
  46. data/spec/attributes_spec.rb +16 -2
  47. data/spec/contexts/enumerable_spec.rb +335 -0
  48. data/spec/contexts/mongo_spec.rb +148 -0
  49. data/spec/contexts_spec.rb +28 -0
  50. data/spec/criteria_spec.rb +15 -766
  51. data/spec/finders_spec.rb +28 -36
  52. data/spec/matchers_spec.rb +342 -0
  53. data/spec/scope_spec.rb +79 -0
  54. metadata +40 -10
  55. data/features/step_definitions/criteria_steps.rb +0 -42
  56. data/lib/mongodoc/named_scope.rb +0 -68
  57. data/spec/named_scope_spec.rb +0 -82
@@ -7,73 +7,65 @@ describe MongoDoc::Finders do
7
7
  key :data
8
8
  end
9
9
 
10
- context ".criteria" do
11
- it "creates a new criteria for the document" do
12
- FindersTest.criteria.should be_a_kind_of(MongoDoc::Criteria)
13
- end
14
-
15
- it "sets the criteria klass" do
16
- FindersTest.criteria.klass.should == FindersTest
17
- end
18
- end
10
+ let(:criteria) { stub('criteria').as_null_object }
19
11
 
20
12
  context ".find" do
21
13
  before do
22
- @criteria = stub('criteria').as_null_object
23
- @conditions = {:where => 'this.a > 3'}
24
- MongoDoc::Criteria.stub(:translate).and_return(@criteria)
14
+ FindersTest.stub(:criteria).and_return(criteria)
25
15
  end
26
16
 
27
- it "creates a criteria" do
28
- MongoDoc::Criteria.should_receive(:translate).with(FindersTest, @conditions).and_return(@criteria)
29
- FindersTest.find(:first, @conditions)
17
+ it "delegates to id for the criteria" do
18
+ args = [1, 2, 3]
19
+ criteria.should_receive(:id).with(*args)
20
+ FindersTest.find(*args)
30
21
  end
22
+ end
31
23
 
32
- [:all, :first, :last].each do |which|
33
- it "calls #{which} on the criteria" do
34
- @criteria.should_receive(which)
35
- FindersTest.find(which, @conditions)
36
- end
24
+ context ".find_all" do
25
+ it "delegates to an empty criteria" do
26
+ FindersTest.should_receive(:criteria)
27
+ FindersTest.find_all
28
+ end
29
+
30
+ it "returns the empty criteria" do
31
+ FindersTest.stub(:criteria).and_return(criteria)
32
+ FindersTest.find_all.should == criteria
37
33
  end
38
34
  end
39
35
 
40
36
  context ".find_one" do
41
37
  context "with an id" do
42
- it "calls translate with the id" do
38
+ it "delegates to translate" do
43
39
  id = 'an id'
44
- MongoDoc::Criteria.should_receive(:translate).with(FindersTest, id)
40
+ Mongoid::Criteria.should_receive(:translate).with(FindersTest, id)
45
41
  FindersTest.find_one(id)
46
42
  end
47
43
  end
48
44
 
49
45
  context "with conditions" do
50
- before do
51
- @criteria = stub('criteria').as_null_object
52
- @conditions = {:where => 'this.a > 3'}
53
- end
46
+ let(:conditions) { {:where => 'this.a > 3'} }
54
47
 
55
48
  it "calls translate with the conditions" do
56
- MongoDoc::Criteria.should_receive(:translate).with(FindersTest, @conditions).and_return(@criteria)
57
- FindersTest.find_one(@conditions)
49
+ Mongoid::Criteria.should_receive(:translate).with(FindersTest, conditions).and_return(criteria)
50
+ FindersTest.find_one(conditions)
58
51
  end
59
52
 
60
- it "call :one on the result" do
61
- MongoDoc::Criteria.stub(:translate).and_return(@criteria)
62
- @criteria.should_receive(:one)
63
- FindersTest.find_one(@conditions)
53
+ it "call one on the result" do
54
+ Mongoid::Criteria.stub(:translate).and_return(criteria)
55
+ criteria.should_receive(:one)
56
+ FindersTest.find_one(conditions)
64
57
  end
65
58
  end
66
59
  end
67
60
 
68
61
  context "all other finders" do
69
62
  before do
70
- @criteria = stub('criteria').as_null_object
71
- MongoDoc::Criteria.stub(:new).and_return(@criteria)
63
+ FindersTest.stub(:criteria).and_return(criteria)
72
64
  end
73
65
 
74
- [:all, :count, :first, :last].each do |which|
66
+ %w(count first last).each do |which|
75
67
  it "calls #{which} on the new criteria" do
76
- @criteria.should_receive(which)
68
+ criteria.should_receive(which)
77
69
  FindersTest.send(which)
78
70
  end
79
71
  end
@@ -0,0 +1,342 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoDoc::Matchers do
4
+
5
+ class Address
6
+ include MongoDoc::Matchers
7
+
8
+ attr_accessor :number
9
+ attr_accessor :services
10
+ attr_accessor :street
11
+
12
+ def initialize(attrs = {})
13
+ attrs.each {|key, value| send("#{key}=", value)}
14
+ end
15
+ end
16
+
17
+ describe "#matches?" do
18
+
19
+ context "when performing simple matching" do
20
+
21
+ before do
22
+ @document = Address.new(:street => "Clarkenwell Road")
23
+ end
24
+
25
+ context "when the attributes match" do
26
+
27
+ before do
28
+ @selector = { :street => "Clarkenwell Road" }
29
+ end
30
+
31
+ it "returns true" do
32
+ @document.matches?(@selector).should be_true
33
+ end
34
+
35
+ end
36
+
37
+ context "when the attributes dont match" do
38
+
39
+ before do
40
+ @selector = { :street => "Broadway Ave" }
41
+ end
42
+
43
+ it "returns false" do
44
+ @document.matches?(@selector).should be_false
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ context "when performing complex matching" do
52
+
53
+ before do
54
+ @document = Address.new(:services => ["first", "second"], :number => 100)
55
+ end
56
+
57
+ context "with an $all selector" do
58
+
59
+ context "when the attributes match" do
60
+
61
+ before do
62
+ @selector = { :services => { "$all" => [ "first", "second" ] } }
63
+ end
64
+
65
+ it "returns true" do
66
+ @document.matches?(@selector).should be_true
67
+ end
68
+
69
+ end
70
+
71
+ context "when the attributes do not match" do
72
+
73
+ before do
74
+ @selector = { :services => { "$all" => [ "first" ] } }
75
+ end
76
+
77
+ it "returns false" do
78
+ @document.matches?(@selector).should be_false
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ context "with an $exists selector" do
86
+
87
+ context "when the attributes match" do
88
+
89
+ before do
90
+ @selector = { :services => { "$exists" => true } }
91
+ end
92
+
93
+ it "returns true" do
94
+ @document.matches?(@selector).should be_true
95
+ end
96
+
97
+ end
98
+
99
+ context "when the attributes do not match" do
100
+
101
+ before do
102
+ @selector = { :services => { "$exists" => false } }
103
+ end
104
+
105
+ it "returns false" do
106
+ @document.matches?(@selector).should be_false
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ context "with a $gt selector" do
114
+
115
+ context "when the attributes match" do
116
+
117
+ before do
118
+ @selector = { :number => { "$gt" => 50 } }
119
+ end
120
+
121
+ it "returns true" do
122
+ @document.matches?(@selector).should be_true
123
+ end
124
+
125
+ end
126
+
127
+ context "when the attributes do not match" do
128
+
129
+ before do
130
+ @selector = { :number => { "$gt" => 200 } }
131
+ end
132
+
133
+ it "returns false" do
134
+ @document.matches?(@selector).should be_false
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ context "with a $gte selector" do
142
+
143
+ context "when the attributes match" do
144
+
145
+ before do
146
+ @selector = { :number => { "$gte" => 100 } }
147
+ end
148
+
149
+ it "returns true" do
150
+ @document.matches?(@selector).should be_true
151
+ end
152
+
153
+ end
154
+
155
+ context "when the attributes do not match" do
156
+
157
+ before do
158
+ @selector = { :number => { "$gte" => 200 } }
159
+ end
160
+
161
+ it "returns false" do
162
+ @document.matches?(@selector).should be_false
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ context "with an $in selector" do
170
+
171
+ context "when the attributes match" do
172
+
173
+ before do
174
+ @selector = { :number => { "$in" => [ 100, 200 ] } }
175
+ end
176
+
177
+ it "returns true" do
178
+ @document.matches?(@selector).should be_true
179
+ end
180
+
181
+ end
182
+
183
+ context "when the attributes do not match" do
184
+
185
+ before do
186
+ @selector = { :number => { "$in" => [ 200, 300 ] } }
187
+ end
188
+
189
+ it "returns false" do
190
+ @document.matches?(@selector).should be_false
191
+ end
192
+
193
+ end
194
+
195
+ end
196
+
197
+ context "with a $lt selector" do
198
+
199
+ context "when the attributes match" do
200
+
201
+ before do
202
+ @selector = { :number => { "$lt" => 200 } }
203
+ end
204
+
205
+ it "returns true" do
206
+ @document.matches?(@selector).should be_true
207
+ end
208
+
209
+ end
210
+
211
+ context "when the attributes do not match" do
212
+
213
+ before do
214
+ @selector = { :number => { "$lt" => 50 } }
215
+ end
216
+
217
+ it "returns false" do
218
+ @document.matches?(@selector).should be_false
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
225
+ context "with a $lte selector" do
226
+
227
+ context "when the attributes match" do
228
+
229
+ before do
230
+ @selector = { :number => { "$lte" => 200 } }
231
+ end
232
+
233
+ it "returns true" do
234
+ @document.matches?(@selector).should be_true
235
+ end
236
+
237
+ end
238
+
239
+ context "when the attributes do not match" do
240
+
241
+ before do
242
+ @selector = { :number => { "$lte" => 50 } }
243
+ end
244
+
245
+ it "returns false" do
246
+ @document.matches?(@selector).should be_false
247
+ end
248
+
249
+ end
250
+
251
+ end
252
+
253
+ context "with an $ne selector" do
254
+
255
+ context "when the attributes match" do
256
+
257
+ before do
258
+ @selector = { :number => { "$ne" => 200 } }
259
+ end
260
+
261
+ it "returns true" do
262
+ @document.matches?(@selector).should be_true
263
+ end
264
+
265
+ end
266
+
267
+ context "when the attributes do not match" do
268
+
269
+ before do
270
+ @selector = { :number => { "$ne" => 100 } }
271
+ end
272
+
273
+ it "returns false" do
274
+ @document.matches?(@selector).should be_false
275
+ end
276
+
277
+ end
278
+
279
+ end
280
+
281
+ context "with a $nin selector" do
282
+
283
+ context "when the attributes match" do
284
+
285
+ before do
286
+ @selector = { :number => { "$nin" => [ 1, 2, 3 ] } }
287
+ end
288
+
289
+ it "returns true" do
290
+ @document.matches?(@selector).should be_true
291
+ end
292
+
293
+ end
294
+
295
+ context "when the attributes do not match" do
296
+
297
+ before do
298
+ @selector = { :number => { "$nin" => [ 100 ] } }
299
+ end
300
+
301
+ it "returns false" do
302
+ @document.matches?(@selector).should be_false
303
+ end
304
+
305
+ end
306
+
307
+ end
308
+
309
+ context "with a $size selector" do
310
+
311
+ context "when the attributes match" do
312
+
313
+ before do
314
+ @selector = { :services => { "$size" => 2 } }
315
+ end
316
+
317
+ it "returns true" do
318
+ @document.matches?(@selector).should be_true
319
+ end
320
+
321
+ end
322
+
323
+ context "when the attributes do not match" do
324
+
325
+ before do
326
+ @selector = { :services => { "$size" => 5 } }
327
+ end
328
+
329
+ it "returns false" do
330
+ @document.matches?(@selector).should be_false
331
+ end
332
+
333
+ end
334
+
335
+ end
336
+
337
+ end
338
+
339
+ end
340
+
341
+ end
342
+
@@ -0,0 +1,79 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper.rb"))
2
+
3
+ describe MongoDoc::Scope do
4
+
5
+ module Extension
6
+ def extension_module_method
7
+ "extension module method"
8
+ end
9
+ end
10
+
11
+ class ScopeTest
12
+ include MongoDoc::Document
13
+
14
+ key :active
15
+ key :count
16
+
17
+ scope :active, where(:active => true)
18
+ scope :count_lte_one, where(:count.lte => 1) do
19
+ def extension_method
20
+ "extension method"
21
+ end
22
+ end
23
+ scope :count_gt_one, where(:count.gt => 1), :extend => Extension
24
+ scope :at_least_count, lambda {|count| where(:count.gt => count)}
25
+ end
26
+
27
+ context ".scope" do
28
+ it "adds the named scope to the hash of scopes" do
29
+ ScopeTest.scopes.should have_key(:active)
30
+ end
31
+
32
+ it "creates a class method for the named scope" do
33
+ ScopeTest.should respond_to(:active)
34
+ end
35
+ end
36
+
37
+ context "accessing a named scope" do
38
+ it "is a criteria proxy" do
39
+ MongoDoc::Scope::CriteriaProxy.should === ScopeTest.active
40
+ end
41
+
42
+ it "responds like a criteria" do
43
+ ScopeTest.active.should respond_to(:selector)
44
+ end
45
+
46
+ it "has set the conditions on the criteria" do
47
+ ScopeTest.active.selector.should has_entry(:active => true)
48
+ end
49
+
50
+ it "sets the association extension by block" do
51
+ ScopeTest.count_lte_one.extension_method.should == "extension method"
52
+ end
53
+
54
+ it "sets the association extension by :extend" do
55
+ ScopeTest.count_gt_one.extension_module_method.should == "extension module method"
56
+ end
57
+
58
+ context "when using a lambda" do
59
+ it "accepts parameters to the criteria" do
60
+ ScopeTest.at_least_count(3).selector.should has_entry(:count => {'$gt' => 3})
61
+ end
62
+ end
63
+ end
64
+
65
+ context "chained scopes" do
66
+ it "is a criteria proxy" do
67
+ MongoDoc::Scope::CriteriaProxy.should === ScopeTest.active.count_gt_one
68
+ end
69
+
70
+ it "responds like a criteria" do
71
+ ScopeTest.active.count_gt_one.should respond_to(:selector)
72
+ end
73
+
74
+ it "merges the criteria" do
75
+ ScopeTest.active.count_gt_one.selector.should has_entry(:count => {'$gt' => 1}, :active => true)
76
+ end
77
+ end
78
+ end
79
+