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