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
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "MongoDoc::Contexts::MongoDoc" do
|
4
|
+
|
5
|
+
class Address
|
6
|
+
include MongoDoc::Document
|
7
|
+
include MongoDoc::Matchers
|
8
|
+
|
9
|
+
key :number
|
10
|
+
key :street
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:criteria) { Mongoid::Criteria.new(Address) }
|
14
|
+
let(:context) { criteria.context }
|
15
|
+
|
16
|
+
context "#initialize" do
|
17
|
+
it "sets the criteria" do
|
18
|
+
context.criteria.should == criteria
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "#collection" do
|
23
|
+
it "delegates to klass" do
|
24
|
+
klass = mock('klass', :collection => true)
|
25
|
+
context.should_receive(:klass).and_return(klass)
|
26
|
+
context.collection
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "querying" do
|
31
|
+
let(:collection) { stub('collection') }
|
32
|
+
|
33
|
+
before { context.stub(:collection).and_return(collection) }
|
34
|
+
|
35
|
+
context "#aggregate" do
|
36
|
+
it "uses group with the appropriate JS" do
|
37
|
+
collection.should_receive(:group).with(nil, {}, {:count=>0}, MongoDoc::Contexts::Mongo::AGGREGATE_REDUCE, true)
|
38
|
+
context.aggregate
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "#count" do
|
43
|
+
it "uses find and count" do
|
44
|
+
result = stub('result')
|
45
|
+
result.should_receive(:count)
|
46
|
+
collection.should_receive(:find).and_return(result)
|
47
|
+
context.count
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "#execute" do
|
52
|
+
it "uses find" do
|
53
|
+
collection.should_receive(:find)
|
54
|
+
context.execute
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns [] if nothing returned from find" do
|
58
|
+
collection.stub(:find => nil)
|
59
|
+
context.execute.should == []
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns the cursor if one is returned from find" do
|
63
|
+
cursor = stub('cursor')
|
64
|
+
collection.stub(:find => cursor)
|
65
|
+
context.execute.should == cursor
|
66
|
+
end
|
67
|
+
|
68
|
+
it "memoizes the count if paginating" do
|
69
|
+
count = 20
|
70
|
+
cursor = stub('cursor', :count => count)
|
71
|
+
collection.stub(:find => cursor)
|
72
|
+
context.execute
|
73
|
+
context.count.should == count
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "#group" do
|
78
|
+
it "uses group with the appropriate JS" do
|
79
|
+
collection.should_receive(:group).with(nil, {}, {:group=>[]}, MongoDoc::Contexts::Mongo::GROUP_REDUCE, true).and_return([])
|
80
|
+
context.group
|
81
|
+
end
|
82
|
+
|
83
|
+
it "decodes returned documents" do
|
84
|
+
doc = stub('doc')
|
85
|
+
collection.stub(:group).and_return([{:group => [doc]}])
|
86
|
+
MongoDoc::BSON.should_receive(:decode).and_return(doc)
|
87
|
+
context.group
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "#id_criteria" do
|
92
|
+
it "delegates to one if passed a string or ObjectID" do
|
93
|
+
context.should_receive(:one)
|
94
|
+
context.id_criteria('id')
|
95
|
+
end
|
96
|
+
|
97
|
+
it "delegates to entries if passed an array" do
|
98
|
+
criteria.should_receive(:entries)
|
99
|
+
context.id_criteria(['id'])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "#last" do
|
104
|
+
it "delegates to find_one" do
|
105
|
+
collection.should_receive(:find_one).with({}, {:sort=>[[:_id, :desc]]})
|
106
|
+
context.last
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "#max" do
|
111
|
+
it "delegates to grouped" do
|
112
|
+
context.should_receive(:grouped).with(:max, "number", MongoDoc::Contexts::Mongo::MAX_REDUCE)
|
113
|
+
context.max(:number)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "#min" do
|
118
|
+
it "delegates to grouped" do
|
119
|
+
context.should_receive(:grouped).with(:min, "number", MongoDoc::Contexts::Mongo::MIN_REDUCE)
|
120
|
+
context.min(:number)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "#one" do
|
125
|
+
it "delegates to find_one" do
|
126
|
+
collection.should_receive(:find_one).with({}, {})
|
127
|
+
context.one
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "#sum" do
|
132
|
+
it "delegates to grouped" do
|
133
|
+
context.should_receive(:grouped).with(:sum, "number", MongoDoc::Contexts::Mongo::SUM_REDUCE)
|
134
|
+
context.sum(:number)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "#grouped" do
|
139
|
+
it "delegates to group" do
|
140
|
+
op = 'op'
|
141
|
+
field = 'name'
|
142
|
+
reduce = '[field]'
|
143
|
+
collection.should_receive(:group).with(nil, {}, {op =>"start"}, field, true).and_return([])
|
144
|
+
context.send(:grouped, op, field, reduce)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MongoDoc::Contexts do
|
4
|
+
|
5
|
+
context ".context_for" do
|
6
|
+
let(:criteria) { stub('criteria', :klass => klass) }
|
7
|
+
|
8
|
+
context "when criteria is for a top-level MongoDoc::Document" do
|
9
|
+
let(:klass) { stub('klass', :collection => stub('collection')) }
|
10
|
+
|
11
|
+
it "creates a MongoDoc context" do
|
12
|
+
MongoDoc::Contexts::Mongo.should_receive(:new).with(criteria)
|
13
|
+
Mongoid::Contexts.context_for(criteria)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when criteria is for an embedded MongoDoc::Document" do
|
18
|
+
let(:klass) { stub('klass') }
|
19
|
+
|
20
|
+
it "creates an Enumerable context" do
|
21
|
+
MongoDoc::Contexts::Enumerable.should_receive(:new).with(criteria)
|
22
|
+
Mongoid::Contexts.context_for(criteria)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
data/spec/criteria_spec.rb
CHANGED
@@ -1,784 +1,33 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MongoDoc::Criteria do
|
4
|
-
class CountryCode
|
5
|
-
include MongoDoc::Document
|
6
4
|
|
7
|
-
|
5
|
+
class CriteriaTest
|
6
|
+
extend MongoDoc::Criteria
|
8
7
|
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
key :number
|
14
|
-
has_one :country_code
|
15
|
-
end
|
16
|
-
|
17
|
-
class Animal
|
18
|
-
include MongoDoc::Document
|
19
|
-
|
20
|
-
key :name
|
21
|
-
end
|
22
|
-
|
23
|
-
class Address
|
24
|
-
include MongoDoc::Document
|
25
|
-
|
26
|
-
key :street
|
27
|
-
key :city
|
28
|
-
key :state
|
29
|
-
key :post_code
|
30
|
-
end
|
31
|
-
|
32
|
-
class Name
|
33
|
-
include MongoDoc::Document
|
34
|
-
|
35
|
-
key :first_name
|
36
|
-
key :last_name
|
37
|
-
end
|
38
|
-
|
39
|
-
class Person
|
40
|
-
include MongoDoc::Document
|
41
|
-
|
42
|
-
key :title
|
43
|
-
key :terms
|
44
|
-
key :age
|
45
|
-
key :dob
|
46
|
-
key :mixed_drink
|
47
|
-
key :employer_id
|
48
|
-
key :lunch_time
|
49
|
-
|
50
|
-
has_many :addresses
|
51
|
-
has_many :phone_numbers, :class_name => "Phone"
|
52
|
-
|
53
|
-
has_one :name
|
54
|
-
has_one :pet
|
55
|
-
|
56
|
-
def update_addresses
|
57
|
-
addresses.each_with_index do |address, i|
|
58
|
-
address.street = "Updated #{i}"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def employer=(emp)
|
63
|
-
self.employer_id = emp.id
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
before do
|
68
|
-
@criteria = MongoDoc::Criteria.new(Person)
|
69
|
-
end
|
70
|
-
|
71
|
-
describe "#all" do
|
72
|
-
it "calls collect" do
|
73
|
-
@criteria.should_receive(:collect).with(no_args)
|
74
|
-
@criteria.all
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "#aggregate" do
|
79
|
-
before do
|
80
|
-
@reduce = "function(obj, prev) { prev.count++; }"
|
81
|
-
@collection = mock
|
82
|
-
Person.should_receive(:collection).and_return(@collection)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "calls group on the collection with the aggregate js" do
|
86
|
-
@collection.should_receive(:group).with([:field1], {}, {:count => 0}, @reduce, true)
|
87
|
-
@criteria.only(:field1).aggregate
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "#every" do
|
92
|
-
|
93
|
-
it "adds the $all query to the selector" do
|
94
|
-
@criteria.every(:title => ["title1", "title2"])
|
95
|
-
@criteria.selector.should == { :title => { "$all" => ["title1", "title2"] } }
|
96
|
-
end
|
97
|
-
|
98
|
-
it "returns self" do
|
99
|
-
@criteria.every(:title => [ "title1" ]).should == @criteria
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "including Enumerable" do
|
105
|
-
|
106
|
-
before do
|
107
|
-
@cursor = stub('cursor').as_null_object
|
108
|
-
@criteria.stub(:execute).and_return(@cursor)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "calls each" do
|
112
|
-
@criteria.should_receive(:each).and_return(@criteria)
|
113
|
-
@criteria.collect
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
describe "#count" do
|
119
|
-
|
120
|
-
context "when criteria has not been executed" do
|
121
|
-
|
122
|
-
before do
|
123
|
-
@count = 27
|
124
|
-
@collection = mock
|
125
|
-
@cursor = stub('cursor', :count => @count)
|
126
|
-
Person.stub(:collection).and_return(@collection)
|
127
|
-
end
|
128
|
-
|
129
|
-
it "calls through to the collection" do
|
130
|
-
@collection.should_receive(:find).and_return(@cursor)
|
131
|
-
@criteria.count
|
132
|
-
end
|
133
|
-
|
134
|
-
it "returns the count from the cursor" do
|
135
|
-
@collection.stub(:find).and_return(@cursor)
|
136
|
-
@criteria.count.should == @count
|
137
|
-
end
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
context "when criteria has been executed" do
|
142
|
-
|
143
|
-
before do
|
144
|
-
@count = 28
|
145
|
-
@criteria.instance_variable_set(:@count, @count)
|
146
|
-
end
|
147
|
-
|
148
|
-
it "returns the count from the cursor without creating the documents" do
|
149
|
-
@criteria.count.should == @count
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
describe "#each" do
|
157
|
-
|
158
|
-
before do
|
159
|
-
@criteria.where(:title => "Sir")
|
160
|
-
@person = Person.new(:title => "Sir")
|
161
|
-
@cursor = [@person]
|
162
|
-
end
|
163
|
-
|
164
|
-
context "when no block given" do
|
165
|
-
it "executes the criteria" do
|
166
|
-
@criteria.should_receive(:execute).and_return(@cursor)
|
167
|
-
@criteria.each
|
168
|
-
end
|
169
|
-
|
170
|
-
it "has memoized the result of execute" do
|
171
|
-
@criteria.stub(:execute).and_return(@cursor)
|
172
|
-
@criteria.each
|
173
|
-
@criteria.collection.should == @cursor
|
174
|
-
end
|
175
|
-
|
176
|
-
it "returns self" do
|
177
|
-
@criteria.stub(:execute).and_return(@cursor)
|
178
|
-
@criteria.each.should == @criteria
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
context "when a block is given" do
|
183
|
-
class CursorStub
|
184
|
-
include Enumerable
|
185
|
-
|
186
|
-
attr_accessor :data
|
187
|
-
|
188
|
-
def each(*args, &block)
|
189
|
-
data.each(*args, &block)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
context "when the criteria has not been executed" do
|
194
|
-
before do
|
195
|
-
@cursor = CursorStub.new
|
196
|
-
@cursor.data = [@person]
|
197
|
-
end
|
198
|
-
|
199
|
-
it "executes the criteria" do
|
200
|
-
@criteria.should_receive(:execute).and_return(@cursor)
|
201
|
-
@criteria.each do |person|
|
202
|
-
person.should == @person
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
it "yields into the block" do
|
207
|
-
@criteria.stub(:execute).and_return(@cursor)
|
208
|
-
@criteria.each do |person|
|
209
|
-
@result = person
|
210
|
-
end
|
211
|
-
@result.should == @person
|
212
|
-
end
|
213
|
-
|
214
|
-
it "has memoized the cursor iteration" do
|
215
|
-
@criteria.stub(:execute).and_return(@cursor)
|
216
|
-
@criteria.each do |person|
|
217
|
-
@result = person
|
218
|
-
end
|
219
|
-
@criteria.collection.should == [@person]
|
220
|
-
end
|
221
|
-
|
222
|
-
|
223
|
-
it "returns self" do
|
224
|
-
@criteria.stub(:execute).and_return(@cursor)
|
225
|
-
@criteria.each.should == @criteria
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
context "when the criteria has been executed" do
|
230
|
-
before do
|
231
|
-
@criteria.stub(:execute).and_return(@cursor)
|
232
|
-
@criteria.each
|
233
|
-
end
|
234
|
-
|
235
|
-
it "does not execute the criteria" do
|
236
|
-
@criteria.should_not_receive(:execute)
|
237
|
-
@criteria.each do |person|
|
238
|
-
person.should == @person
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
it "yields into the block" do
|
243
|
-
@criteria.each do |person|
|
244
|
-
@result = person
|
245
|
-
end
|
246
|
-
@result.should == @person
|
247
|
-
end
|
248
|
-
|
249
|
-
it "returns self" do
|
250
|
-
@criteria.each.should == @criteria
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
describe "#excludes" do
|
257
|
-
|
258
|
-
it "adds the $ne query to the selector" do
|
259
|
-
@criteria.excludes(:title => "Bad Title", :text => "Bad Text")
|
260
|
-
@criteria.selector.should == { :title => { "$ne" => "Bad Title"}, :text => { "$ne" => "Bad Text" } }
|
261
|
-
end
|
262
|
-
|
263
|
-
it "returns self" do
|
264
|
-
@criteria.excludes(:title => "Bad").should == @criteria
|
265
|
-
end
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
|
-
describe "#extras" do
|
270
|
-
|
271
|
-
context "filtering" do
|
272
|
-
|
273
|
-
context "when page is provided" do
|
274
|
-
|
275
|
-
it "sets the limit and skip options" do
|
276
|
-
@criteria.extras({ :page => "2" })
|
277
|
-
@criteria.page.should == 2
|
278
|
-
@criteria.options.should == { :skip => 20, :limit => 20 }
|
279
|
-
end
|
280
|
-
|
281
|
-
end
|
282
|
-
|
283
|
-
context "when per_page is provided" do
|
284
|
-
|
285
|
-
it "sets the limit and skip options" do
|
286
|
-
@criteria.extras({ :per_page => 45 })
|
287
|
-
@criteria.options.should == { :skip => 0, :limit => 45 }
|
288
|
-
end
|
289
|
-
|
290
|
-
end
|
291
|
-
|
292
|
-
context "when page and per_page both provided" do
|
293
|
-
|
294
|
-
it "sets the limit and skip options" do
|
295
|
-
@criteria.extras({ :per_page => 30, :page => "4" })
|
296
|
-
@criteria.options.should == { :skip => 90, :limit => 30 }
|
297
|
-
@criteria.page.should == 4
|
298
|
-
end
|
299
|
-
|
300
|
-
end
|
301
|
-
|
302
|
-
end
|
303
|
-
|
304
|
-
it "adds the extras to the options" do
|
305
|
-
@criteria.extras({ :skip => 10 })
|
306
|
-
@criteria.options.should == { :skip => 10 }
|
307
|
-
end
|
308
|
-
|
309
|
-
it "returns self" do
|
310
|
-
@criteria.extras({}).should == @criteria
|
311
|
-
end
|
312
|
-
|
313
|
-
it "adds the extras without overwriting existing options" do
|
314
|
-
@criteria.order_by([:field1])
|
315
|
-
@criteria.extras({ :skip => 10 })
|
316
|
-
@criteria.options.should have_key(:sort)
|
317
|
-
end
|
318
|
-
|
319
|
-
end
|
320
|
-
|
321
|
-
describe "#group" do
|
322
|
-
before do
|
323
|
-
@grouping = [{ "title" => "Sir", "group" => [{ "title" => "Sir", "age" => 30 }] }]
|
324
|
-
@reduce = "function(obj, prev) { prev.group.push(obj); }"
|
325
|
-
@collection = mock
|
326
|
-
Person.should_receive(:collection).and_return(@collection)
|
327
|
-
end
|
328
|
-
|
329
|
-
it "calls group on the collection with the aggregate js" do
|
330
|
-
@collection.should_receive(:group).with([:field1], {}, {:group => []}, @reduce, true).and_return(@grouping)
|
331
|
-
@criteria.only(:field1).group
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
describe "#id" do
|
336
|
-
|
337
|
-
it "adds the ObjectID as the _id query to the selector" do
|
338
|
-
id = Mongo::ObjectID.new
|
339
|
-
@criteria.id(id)
|
340
|
-
@criteria.selector.should == { :_id => id }
|
341
|
-
end
|
342
|
-
|
343
|
-
it "when a string adds ObjectID as the _id query to the selector" do
|
344
|
-
id = Mongo::ObjectID.new
|
345
|
-
@criteria.id(id.to_s)
|
346
|
-
@criteria.selector.should == { :_id => id }
|
347
|
-
end
|
348
|
-
|
349
|
-
it "returns self" do
|
350
|
-
id = Mongo::ObjectID.new
|
351
|
-
@criteria.id(id).should == @criteria
|
352
|
-
end
|
353
|
-
|
354
|
-
end
|
355
|
-
|
356
|
-
describe "#in" do
|
357
|
-
|
358
|
-
it "adds the $in clause to the selector" do
|
359
|
-
@criteria.in(:title => ["title1", "title2"], :text => ["test"])
|
360
|
-
@criteria.selector.should == { :title => { "$in" => ["title1", "title2"] }, :text => { "$in" => ["test"] } }
|
361
|
-
end
|
362
|
-
|
363
|
-
it "returns self" do
|
364
|
-
@criteria.in(:title => ["title1"]).should == @criteria
|
365
|
-
end
|
366
|
-
|
367
|
-
end
|
368
|
-
|
369
|
-
describe "#last" do
|
370
|
-
|
371
|
-
context "when documents exist" do
|
372
|
-
|
373
|
-
before do
|
374
|
-
@collection = mock
|
375
|
-
Person.should_receive(:collection).and_return(@collection)
|
376
|
-
@collection.should_receive(:find_one).with(@criteria.selector, { :sort => [[:title, :desc]] }).and_return(Person.new(:title => "Sir"))
|
377
|
-
end
|
378
|
-
|
379
|
-
it "calls find on the collection with the selector and sort options reversed" do
|
380
|
-
@criteria.order_by([[:title, :asc]])
|
381
|
-
@criteria.last.should be_a_kind_of(Person)
|
382
|
-
end
|
383
|
-
|
384
|
-
end
|
385
|
-
|
386
|
-
context "when no documents exist" do
|
387
|
-
|
388
|
-
before do
|
389
|
-
@collection = mock
|
390
|
-
Person.should_receive(:collection).and_return(@collection)
|
391
|
-
@collection.should_receive(:find_one).with(@criteria.selector, { :sort => [[:_id, :desc]] }).and_return(nil)
|
392
|
-
end
|
393
|
-
|
394
|
-
it "returns nil" do
|
395
|
-
@criteria.last.should be_nil
|
396
|
-
end
|
397
|
-
|
398
|
-
end
|
399
|
-
|
400
|
-
context "when no sorting options provided" do
|
401
|
-
|
402
|
-
before do
|
403
|
-
@collection = mock
|
404
|
-
Person.should_receive(:collection).and_return(@collection)
|
405
|
-
@collection.should_receive(:find_one).with(@criteria.selector, { :sort => [[:_id, :desc]] }).and_return({ :title => "Sir" })
|
406
|
-
end
|
407
|
-
|
408
|
-
it "defaults to sort by id" do
|
409
|
-
@criteria.last
|
410
|
-
end
|
411
|
-
|
412
|
-
end
|
413
|
-
|
414
|
-
end
|
415
|
-
|
416
|
-
describe "#limit" do
|
417
|
-
|
418
|
-
context "when value provided" do
|
419
|
-
|
420
|
-
it "adds the limit to the options" do
|
421
|
-
@criteria.limit(100)
|
422
|
-
@criteria.options.should == { :limit => 100 }
|
423
|
-
end
|
424
|
-
|
425
|
-
end
|
426
|
-
|
427
|
-
context "when value not provided" do
|
428
|
-
|
429
|
-
it "defaults to 20" do
|
430
|
-
@criteria.limit
|
431
|
-
@criteria.options.should == { :limit => 20 }
|
432
|
-
end
|
433
|
-
|
434
|
-
end
|
435
|
-
|
436
|
-
it "returns self" do
|
437
|
-
@criteria.limit.should == @criteria
|
438
|
-
end
|
439
|
-
|
440
|
-
end
|
441
|
-
|
442
|
-
describe "#not_in" do
|
443
|
-
|
444
|
-
it "adds the exclusion to the selector" do
|
445
|
-
@criteria.not_in(:title => ["title1", "title2"], :text => ["test"])
|
446
|
-
@criteria.selector.should == { :title => { "$nin" => ["title1", "title2"] }, :text => { "$nin" => ["test"] } }
|
447
|
-
end
|
448
|
-
|
449
|
-
it "returns self" do
|
450
|
-
@criteria.not_in(:title => ["title1"]).should == @criteria
|
451
|
-
end
|
452
|
-
|
453
|
-
end
|
454
|
-
|
455
|
-
describe "#offset" do
|
456
|
-
|
457
|
-
context "when the per_page option exists" do
|
458
|
-
|
459
|
-
before do
|
460
|
-
@criteria.extras({ :per_page => 20, :page => 3 })
|
461
|
-
end
|
462
|
-
|
463
|
-
it "returns the per_page option" do
|
464
|
-
@criteria.offset.should == 40
|
465
|
-
end
|
466
|
-
|
467
|
-
end
|
468
|
-
|
469
|
-
context "when the skip option exists" do
|
470
|
-
|
471
|
-
before do
|
472
|
-
@criteria.extras({ :skip => 20 })
|
473
|
-
end
|
474
|
-
|
475
|
-
it "returns the skip option" do
|
476
|
-
@criteria.offset.should == 20
|
477
|
-
end
|
478
|
-
|
479
|
-
end
|
480
|
-
|
481
|
-
context "when no option exists" do
|
482
|
-
|
483
|
-
context "when page option exists" do
|
484
|
-
|
485
|
-
before do
|
486
|
-
@criteria.extras({ :page => 2 })
|
487
|
-
end
|
488
|
-
|
489
|
-
it "adds the skip option to the options and returns it" do
|
490
|
-
@criteria.offset.should == 20
|
491
|
-
@criteria.options[:skip].should == 20
|
492
|
-
end
|
493
|
-
|
494
|
-
end
|
495
|
-
|
496
|
-
context "when page option does not exist" do
|
497
|
-
|
498
|
-
it "returns nil" do
|
499
|
-
@criteria.offset.should be_nil
|
500
|
-
@criteria.options[:skip].should be_nil
|
501
|
-
end
|
502
|
-
|
503
|
-
end
|
504
|
-
|
505
|
-
end
|
506
|
-
|
507
|
-
end
|
508
|
-
|
509
|
-
describe "#one" do
|
510
|
-
|
511
|
-
context "when documents exist" do
|
512
|
-
|
513
|
-
before do
|
514
|
-
@collection = mock
|
515
|
-
Person.should_receive(:collection).and_return(@collection)
|
516
|
-
@collection.should_receive(:find_one).with(@criteria.selector, @criteria.options).and_return(Person.new(:title => "Sir"))
|
517
|
-
end
|
518
|
-
|
519
|
-
it "calls find on the collection with the selector and options" do
|
520
|
-
@criteria.one.should be_a_kind_of(Person)
|
521
|
-
end
|
522
|
-
|
523
|
-
end
|
524
|
-
|
525
|
-
context "when no documents exist" do
|
526
|
-
|
527
|
-
before do
|
528
|
-
@collection = mock
|
529
|
-
Person.should_receive(:collection).and_return(@collection)
|
530
|
-
@collection.should_receive(:find_one).with(@criteria.selector, @criteria.options).and_return(nil)
|
531
|
-
end
|
532
|
-
|
533
|
-
it "returns nil" do
|
534
|
-
@criteria.one.should be_nil
|
535
|
-
end
|
536
|
-
|
537
|
-
end
|
538
|
-
|
539
|
-
end
|
540
|
-
|
541
|
-
describe "#order_by" do
|
542
|
-
|
543
|
-
context "when field names and direction specified" do
|
544
|
-
|
545
|
-
it "adds the sort to the options" do
|
546
|
-
@criteria.order_by([[:title, :asc], [:text, :desc]])
|
547
|
-
@criteria.options.should == { :sort => [[:title, :asc], [:text, :desc]] }
|
548
|
-
end
|
549
|
-
|
550
|
-
end
|
551
|
-
|
552
|
-
it "returns self" do
|
553
|
-
@criteria.order_by.should == @criteria
|
554
|
-
end
|
555
|
-
|
556
|
-
end
|
557
|
-
|
558
|
-
describe "#page" do
|
559
|
-
|
560
|
-
context "when the page option exists" do
|
561
|
-
|
562
|
-
before do
|
563
|
-
@criteria.extras({ :page => 5 })
|
564
|
-
end
|
565
|
-
|
566
|
-
it "returns the page option" do
|
567
|
-
@criteria.page.should == 5
|
568
|
-
end
|
569
|
-
|
9
|
+
context ".criteria" do
|
10
|
+
it "creates a new criteria for the document" do
|
11
|
+
CriteriaTest.criteria.should be_a_kind_of(Mongoid::Criteria)
|
570
12
|
end
|
571
13
|
|
572
|
-
|
573
|
-
|
574
|
-
it "returns 1" do
|
575
|
-
@criteria.page.should == 1
|
576
|
-
end
|
577
|
-
|
14
|
+
it "sets the criteria klass" do
|
15
|
+
CriteriaTest.criteria.klass.should == CriteriaTest
|
578
16
|
end
|
579
|
-
|
580
17
|
end
|
581
18
|
|
582
|
-
|
19
|
+
context "criteria delegates" do
|
20
|
+
let(:criteria) { stub('criteria').as_null_object }
|
583
21
|
|
584
22
|
before do
|
585
|
-
|
586
|
-
Person.should_receive(:collection).and_return(@collection)
|
587
|
-
@criteria.where(:_id => "1").skip(60).limit(20)
|
588
|
-
@cursor = mock('cursor', :count => 20, :to_a => [])
|
589
|
-
@collection.should_receive(:find).with({:_id => "1"}, :skip => 60, :limit => 20).and_return(@cursor)
|
590
|
-
@results = @criteria.paginate
|
591
|
-
end
|
592
|
-
|
593
|
-
it "executes and paginates the results" do
|
594
|
-
@results.current_page.should == 4
|
595
|
-
@results.per_page.should == 20
|
23
|
+
CriteriaTest.stub(:criteria).and_return(criteria)
|
596
24
|
end
|
597
25
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
context "when the per_page option exists" do
|
603
|
-
|
604
|
-
before do
|
605
|
-
@criteria.extras({ :per_page => 10 })
|
606
|
-
end
|
607
|
-
|
608
|
-
it "returns the per_page option" do
|
609
|
-
@criteria.per_page.should == 10
|
610
|
-
end
|
611
|
-
|
612
|
-
end
|
613
|
-
|
614
|
-
context "when the per_page option does not exist" do
|
615
|
-
|
616
|
-
it "returns 1" do
|
617
|
-
@criteria.per_page.should == 20
|
618
|
-
end
|
619
|
-
|
620
|
-
end
|
621
|
-
|
622
|
-
end
|
623
|
-
|
624
|
-
describe "#only" do
|
625
|
-
|
626
|
-
context "when args are provided" do
|
627
|
-
|
628
|
-
it "adds the options for limiting by fields" do
|
629
|
-
@criteria.only(:title, :text)
|
630
|
-
@criteria.options.should == { :fields => [ :title, :text ] }
|
631
|
-
end
|
632
|
-
|
633
|
-
it "returns self" do
|
634
|
-
@criteria.only.should == @criteria
|
635
|
-
end
|
636
|
-
|
637
|
-
end
|
638
|
-
|
639
|
-
context "when no args provided" do
|
640
|
-
|
641
|
-
it "does not add the field option" do
|
642
|
-
@criteria.only
|
643
|
-
@criteria.options[:fields].should be_nil
|
644
|
-
end
|
645
|
-
|
646
|
-
end
|
647
|
-
|
648
|
-
end
|
649
|
-
|
650
|
-
describe "#skip" do
|
651
|
-
|
652
|
-
context "when value provided" do
|
653
|
-
|
654
|
-
it "adds the skip value to the options" do
|
655
|
-
@criteria.skip(20)
|
656
|
-
@criteria.options.should == { :skip => 20 }
|
657
|
-
end
|
658
|
-
|
659
|
-
end
|
660
|
-
|
661
|
-
context "when value not provided" do
|
662
|
-
|
663
|
-
it "defaults to zero" do
|
664
|
-
@criteria.skip
|
665
|
-
@criteria.options.should == { :skip => 0 }
|
26
|
+
%w(and cache enslave excludes extras id in limit not_in offset only order_by page per_page skip where).each do |criteria_op|
|
27
|
+
it "#{criteria_op} delegates to the criteria" do
|
28
|
+
criteria.should_receive(criteria_op)
|
29
|
+
CriteriaTest.send(criteria_op)
|
666
30
|
end
|
667
|
-
|
668
|
-
end
|
669
|
-
|
670
|
-
it "returns self" do
|
671
|
-
@criteria.skip.should == @criteria
|
672
|
-
end
|
673
|
-
|
674
|
-
end
|
675
|
-
|
676
|
-
describe ".translate" do
|
677
|
-
|
678
|
-
context "with a single argument" do
|
679
|
-
|
680
|
-
before do
|
681
|
-
@id = Mongo::ObjectID.new.to_s
|
682
|
-
@document = stub
|
683
|
-
@criteria = mock
|
684
|
-
end
|
685
|
-
|
686
|
-
it "creates a criteria for a string" do
|
687
|
-
MongoDoc::Criteria.should_receive(:new).and_return(@criteria)
|
688
|
-
@criteria.should_receive(:id).with(@id).and_return(@criteria)
|
689
|
-
@criteria.should_receive(:one).and_return(@document)
|
690
|
-
MongoDoc::Criteria.translate(Person, @id)
|
691
|
-
end
|
692
|
-
|
693
|
-
end
|
694
|
-
|
695
|
-
context "multiple arguments" do
|
696
|
-
|
697
|
-
context "when Person, :conditions => {}" do
|
698
|
-
|
699
|
-
before do
|
700
|
-
@criteria = MongoDoc::Criteria.translate(Person, :conditions => { :title => "Test" })
|
701
|
-
end
|
702
|
-
|
703
|
-
it "returns a criteria with a selector from the conditions" do
|
704
|
-
@criteria.selector.should == { :title => "Test" }
|
705
|
-
end
|
706
|
-
|
707
|
-
it "returns a criteria with klass Person" do
|
708
|
-
@criteria.klass.should == Person
|
709
|
-
end
|
710
|
-
|
711
|
-
end
|
712
|
-
|
713
|
-
context "when :all, :conditions => {}" do
|
714
|
-
|
715
|
-
before do
|
716
|
-
@criteria = MongoDoc::Criteria.translate(Person, :conditions => { :title => "Test" })
|
717
|
-
end
|
718
|
-
|
719
|
-
it "returns a criteria with a selector from the conditions" do
|
720
|
-
@criteria.selector.should == { :title => "Test" }
|
721
|
-
end
|
722
|
-
|
723
|
-
it "returns a criteria with klass Person" do
|
724
|
-
@criteria.klass.should == Person
|
725
|
-
end
|
726
|
-
|
727
|
-
end
|
728
|
-
|
729
|
-
context "when :last, :conditions => {}" do
|
730
|
-
|
731
|
-
before do
|
732
|
-
@criteria = MongoDoc::Criteria.translate(Person, :conditions => { :title => "Test" })
|
733
|
-
end
|
734
|
-
|
735
|
-
it "returns a criteria with a selector from the conditions" do
|
736
|
-
@criteria.selector.should == { :title => "Test" }
|
737
|
-
end
|
738
|
-
|
739
|
-
it "returns a criteria with klass Person" do
|
740
|
-
@criteria.klass.should == Person
|
741
|
-
end
|
742
|
-
end
|
743
|
-
|
744
|
-
context "when options are provided" do
|
745
|
-
|
746
|
-
before do
|
747
|
-
@criteria = MongoDoc::Criteria.translate(Person, :conditions => { :title => "Test" }, :skip => 10)
|
748
|
-
end
|
749
|
-
|
750
|
-
it "adds the criteria and the options" do
|
751
|
-
@criteria.selector.should == { :title => "Test" }
|
752
|
-
@criteria.options.should == { :skip => 10 }
|
753
|
-
end
|
754
|
-
end
|
755
|
-
end
|
756
|
-
end
|
757
|
-
|
758
|
-
describe "#where" do
|
759
|
-
|
760
|
-
it "adds the clause to the selector" do
|
761
|
-
@criteria.where(:title => "Title", :text => "Text")
|
762
|
-
@criteria.selector.should == { :title => "Title", :text => "Text" }
|
763
|
-
end
|
764
|
-
|
765
|
-
it "accepts a js where clause" do
|
766
|
-
@criteria.where("this.a > 3")
|
767
|
-
@criteria.selector.should == { '$where' => "this.a > 3" }
|
768
|
-
end
|
769
|
-
|
770
|
-
it "and return self" do
|
771
|
-
@criteria.where.should == @criteria
|
772
|
-
end
|
773
|
-
|
774
|
-
it "#and is an alias for where" do
|
775
|
-
@criteria.and(:title => "Title", :text => "Text")
|
776
|
-
@criteria.selector.should == { :title => "Title", :text => "Text" }
|
777
|
-
end
|
778
|
-
|
779
|
-
it "#conditions is an alias for where" do
|
780
|
-
@criteria.conditions(:title => "Title", :text => "Text")
|
781
|
-
@criteria.selector.should == { :title => "Title", :text => "Text" }
|
782
31
|
end
|
783
32
|
end
|
784
33
|
end
|