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.
- data/Rakefile +21 -0
- data/TODO +6 -1
- data/VERSION +1 -1
- data/features/finders.feature +1 -1
- data/features/mongodoc_base.feature +11 -2
- data/features/{named_scopes.feature → scopes.feature} +0 -0
- data/features/step_definitions/document_steps.rb +15 -4
- data/features/step_definitions/documents.rb +3 -3
- data/features/step_definitions/query_steps.rb +17 -14
- data/features/step_definitions/{named_scope_steps.rb → scope_steps.rb} +0 -0
- data/features/using_criteria.feature +22 -43
- data/lib/mongodoc.rb +1 -1
- data/lib/mongodoc/associations/collection_proxy.rb +3 -1
- data/lib/mongodoc/associations/document_proxy.rb +4 -1
- data/lib/mongodoc/associations/hash_proxy.rb +3 -1
- data/lib/mongodoc/associations/proxy_base.rb +6 -4
- data/lib/mongodoc/attributes.rb +6 -6
- data/lib/mongodoc/contexts.rb +24 -0
- data/lib/mongodoc/contexts/enumerable.rb +132 -0
- data/lib/mongodoc/contexts/mongo.rb +215 -0
- data/lib/mongodoc/criteria.rb +36 -479
- data/lib/mongodoc/document.rb +3 -2
- data/lib/mongodoc/finders.rb +31 -11
- data/lib/mongodoc/matchers.rb +35 -0
- data/lib/mongodoc/scope.rb +64 -0
- data/lib/mongoid/contexts/paging.rb +42 -0
- data/lib/mongoid/criteria.rb +264 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +92 -0
- data/lib/mongoid/criterion/optional.rb +136 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/mongodoc.gemspec +39 -9
- data/spec/attributes_spec.rb +16 -2
- data/spec/contexts/enumerable_spec.rb +335 -0
- data/spec/contexts/mongo_spec.rb +148 -0
- data/spec/contexts_spec.rb +28 -0
- data/spec/criteria_spec.rb +15 -766
- data/spec/finders_spec.rb +28 -36
- data/spec/matchers_spec.rb +342 -0
- data/spec/scope_spec.rb +79 -0
- metadata +40 -10
- data/features/step_definitions/criteria_steps.rb +0 -42
- data/lib/mongodoc/named_scope.rb +0 -68
- data/spec/named_scope_spec.rb +0 -82
data/spec/finders_spec.rb
CHANGED
@@ -7,73 +7,65 @@ describe MongoDoc::Finders do
|
|
7
7
|
key :data
|
8
8
|
end
|
9
9
|
|
10
|
-
|
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
|
-
|
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 "
|
28
|
-
|
29
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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 "
|
38
|
+
it "delegates to translate" do
|
43
39
|
id = 'an id'
|
44
|
-
|
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
|
-
|
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
|
-
|
57
|
-
FindersTest.find_one(
|
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
|
61
|
-
|
62
|
-
|
63
|
-
FindersTest.find_one(
|
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
|
-
|
71
|
-
MongoDoc::Criteria.stub(:new).and_return(@criteria)
|
63
|
+
FindersTest.stub(:criteria).and_return(criteria)
|
72
64
|
end
|
73
65
|
|
74
|
-
|
66
|
+
%w(count first last).each do |which|
|
75
67
|
it "calls #{which} on the new criteria" do
|
76
|
-
|
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
|
+
|
data/spec/scope_spec.rb
ADDED
@@ -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
|
+
|