mongoid 1.0.6 → 1.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.
Files changed (79) hide show
  1. data/HISTORY +39 -0
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongoid.rb +3 -1
  5. data/lib/mongoid/associations.rb +5 -5
  6. data/lib/mongoid/associations/has_many.rb +8 -2
  7. data/lib/mongoid/associations/has_many_related.rb +10 -4
  8. data/lib/mongoid/attributes.rb +19 -13
  9. data/lib/mongoid/commands.rb +12 -6
  10. data/lib/mongoid/commands/create.rb +2 -2
  11. data/lib/mongoid/commands/delete_all.rb +1 -1
  12. data/lib/mongoid/commands/save.rb +2 -2
  13. data/lib/mongoid/components.rb +1 -0
  14. data/lib/mongoid/contexts.rb +4 -0
  15. data/lib/mongoid/contexts/enumerable.rb +105 -0
  16. data/lib/mongoid/contexts/mongo.rb +228 -0
  17. data/lib/mongoid/contexts/paging.rb +42 -0
  18. data/lib/mongoid/criteria.rb +42 -191
  19. data/lib/mongoid/document.rb +19 -13
  20. data/lib/mongoid/extensions.rb +1 -0
  21. data/lib/mongoid/extensions/array/accessors.rb +3 -1
  22. data/lib/mongoid/extensions/float/conversions.rb +1 -1
  23. data/lib/mongoid/extensions/hash/accessors.rb +1 -1
  24. data/lib/mongoid/extensions/integer/conversions.rb +1 -0
  25. data/lib/mongoid/fields.rb +6 -5
  26. data/lib/mongoid/matchers.rb +36 -0
  27. data/lib/mongoid/matchers/all.rb +11 -0
  28. data/lib/mongoid/matchers/default.rb +20 -0
  29. data/lib/mongoid/matchers/exists.rb +13 -0
  30. data/lib/mongoid/matchers/gt.rb +11 -0
  31. data/lib/mongoid/matchers/gte.rb +11 -0
  32. data/lib/mongoid/matchers/in.rb +11 -0
  33. data/lib/mongoid/matchers/lt.rb +11 -0
  34. data/lib/mongoid/matchers/lte.rb +11 -0
  35. data/lib/mongoid/matchers/ne.rb +11 -0
  36. data/lib/mongoid/matchers/nin.rb +11 -0
  37. data/lib/mongoid/matchers/size.rb +11 -0
  38. data/lib/mongoid/scope.rb +17 -1
  39. data/mongoid.gemspec +51 -5
  40. data/spec/integration/mongoid/associations_spec.rb +67 -5
  41. data/spec/integration/mongoid/attributes_spec.rb +22 -0
  42. data/spec/integration/mongoid/commands_spec.rb +51 -12
  43. data/spec/integration/mongoid/criteria_spec.rb +3 -3
  44. data/spec/integration/mongoid/document_spec.rb +8 -8
  45. data/spec/integration/mongoid/finders_spec.rb +1 -1
  46. data/spec/integration/mongoid/inheritance_spec.rb +6 -0
  47. data/spec/integration/mongoid/named_scope_spec.rb +1 -1
  48. data/spec/spec_helper.rb +47 -6
  49. data/spec/unit/mongoid/associations/has_many_related_spec.rb +42 -0
  50. data/spec/unit/mongoid/associations/has_many_spec.rb +40 -1
  51. data/spec/unit/mongoid/attributes_spec.rb +1 -1
  52. data/spec/unit/mongoid/commands/create_spec.rb +3 -3
  53. data/spec/unit/mongoid/commands/delete_all_spec.rb +2 -2
  54. data/spec/unit/mongoid/commands/save_spec.rb +2 -2
  55. data/spec/unit/mongoid/commands_spec.rb +12 -12
  56. data/spec/unit/mongoid/contexts/enumerable_spec.rb +208 -0
  57. data/spec/unit/mongoid/contexts/mongo_spec.rb +370 -0
  58. data/spec/unit/mongoid/criteria_spec.rb +182 -21
  59. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +9 -9
  60. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +2 -1
  61. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +4 -4
  62. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +1 -1
  63. data/spec/unit/mongoid/fields_spec.rb +3 -3
  64. data/spec/unit/mongoid/identity_spec.rb +2 -2
  65. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  66. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  67. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  68. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  69. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  70. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  71. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  72. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  73. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  74. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  75. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  76. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  77. data/spec/unit/mongoid/scope_spec.rb +70 -0
  78. data/spec/unit/mongoid/timestamps_spec.rb +2 -2
  79. metadata +50 -4
@@ -4,7 +4,7 @@ describe Mongoid::Associations::HasMany do
4
4
 
5
5
  before do
6
6
  @attributes = { :addresses => [
7
- { :_id => "street-1", :street => "Street 1" },
7
+ { :_id => "street-1", :street => "Street 1", :state => "CA" },
8
8
  { :_id => "street-2", :street => "Street 2" } ] }
9
9
  @document = stub(:attributes => @attributes, :add_observer => true, :update => true)
10
10
  end
@@ -322,6 +322,45 @@ describe Mongoid::Associations::HasMany do
322
322
 
323
323
  end
324
324
 
325
+ describe "#method_missing" do
326
+
327
+ context "when the association class has a criteria class method" do
328
+
329
+ before do
330
+ @association = Mongoid::Associations::HasMany.new(
331
+ @document,
332
+ Mongoid::Associations::Options.new(:name => :addresses)
333
+ )
334
+ end
335
+
336
+ it "returns the criteria" do
337
+ @association.california.should be_a_kind_of(Mongoid::Criteria)
338
+ end
339
+
340
+ it "sets the documents on the criteria" do
341
+ criteria = @association.california
342
+ criteria.documents.should == @association.entries
343
+ end
344
+
345
+ it "returns the scoped documents" do
346
+ addresses = @association.california
347
+ addresses.size.should == 1
348
+ addresses.first.should be_a_kind_of(Address)
349
+ addresses.first.state.should == "CA"
350
+ end
351
+
352
+ end
353
+
354
+ context "when no class method exists" do
355
+
356
+ it "delegates to the array" do
357
+
358
+ end
359
+
360
+ end
361
+
362
+ end
363
+
325
364
  describe "#push" do
326
365
 
327
366
  before do
@@ -223,7 +223,7 @@ describe Mongoid::Attributes do
223
223
  attrs[:age].should == 30
224
224
  attrs[:terms].should == true
225
225
  attrs[:_id].should == "1"
226
- attrs[:score].should == ""
226
+ attrs[:score].should be_nil
227
227
  end
228
228
 
229
229
  end
@@ -9,19 +9,19 @@ describe Mongoid::Commands::Create do
9
9
  end
10
10
 
11
11
  it "executes a save command" do
12
- Mongoid::Commands::Save.expects(:execute).with(@document, true).returns(@document)
12
+ Mongoid::Commands::Save.expects(:execute).with(@document, true, false).returns(@document)
13
13
  Mongoid::Commands::Create.execute(@document)
14
14
  end
15
15
 
16
16
  it "runs the before and after create callbacks" do
17
17
  @document.expects(:run_callbacks).with(:before_create)
18
- Mongoid::Commands::Save.expects(:execute).with(@document, true).returns(@document)
18
+ Mongoid::Commands::Save.expects(:execute).with(@document, true, false).returns(@document)
19
19
  @document.expects(:run_callbacks).with(:after_create)
20
20
  Mongoid::Commands::Create.execute(@document)
21
21
  end
22
22
 
23
23
  it "returns the document" do
24
- Mongoid::Commands::Save.expects(:execute).with(@document, true).returns(@document)
24
+ Mongoid::Commands::Save.expects(:execute).with(@document, true, false).returns(@document)
25
25
  Mongoid::Commands::Create.execute(@document).should == @document
26
26
  end
27
27
 
@@ -33,7 +33,7 @@ describe Mongoid::Commands::DeleteAll do
33
33
 
34
34
  it "drops the collection" do
35
35
  @klass.expects(:collection).returns(@collection)
36
- @collection.expects(:drop)
36
+ @collection.expects(:remove).with(:_type => "Person")
37
37
  Mongoid::Commands::DeleteAll.execute(@klass)
38
38
  end
39
39
 
@@ -47,7 +47,7 @@ describe Mongoid::Commands::DeleteAll do
47
47
 
48
48
  it "drops the collection" do
49
49
  @klass.expects(:collection).returns(@collection)
50
- @collection.expects(:drop)
50
+ @collection.expects(:remove).with(:_type => "Person")
51
51
  Mongoid::Commands::DeleteAll.execute(@klass, {})
52
52
  end
53
53
 
@@ -39,7 +39,7 @@ describe Mongoid::Commands::Save do
39
39
  context "when the document has a parent" do
40
40
 
41
41
  it "executes a save on the parent" do
42
- @parent_collection.expects(:save).with(@parent.attributes)
42
+ @parent_collection.expects(:save).with(@parent.attributes, :safe => false)
43
43
  Mongoid::Commands::Save.execute(@document)
44
44
  end
45
45
 
@@ -52,7 +52,7 @@ describe Mongoid::Commands::Save do
52
52
  end
53
53
 
54
54
  it "calls save on the document collection" do
55
- @doc_collection.expects(:save).with(@document.attributes)
55
+ @doc_collection.expects(:save).with(@document.attributes, :safe => false)
56
56
  Mongoid::Commands::Save.execute(@document)
57
57
  end
58
58
 
@@ -27,7 +27,7 @@ describe Mongoid::Commands do
27
27
  describe "#save" do
28
28
 
29
29
  it "delegates to the Save command" do
30
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
30
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, false).returns(true)
31
31
  @person.save
32
32
  end
33
33
 
@@ -38,13 +38,13 @@ describe Mongoid::Commands do
38
38
  end
39
39
 
40
40
  it "delegates to the save command" do
41
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
41
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, false).returns(true)
42
42
  @person.save
43
43
  end
44
44
 
45
45
  it "runs the before and after create callbacks" do
46
46
  @person.expects(:run_callbacks).with(:before_create)
47
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
47
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, false).returns(true)
48
48
  @person.expects(:run_callbacks).with(:after_create)
49
49
  @person.save
50
50
  end
@@ -58,7 +58,7 @@ describe Mongoid::Commands do
58
58
  end
59
59
 
60
60
  it "passes the validate param to the command" do
61
- Mongoid::Commands::Save.expects(:execute).with(@person, false).returns(true)
61
+ Mongoid::Commands::Save.expects(:execute).with(@person, false, false).returns(true)
62
62
  @person.save(false)
63
63
  end
64
64
 
@@ -71,7 +71,7 @@ describe Mongoid::Commands do
71
71
  context "when validation passes" do
72
72
 
73
73
  it "it returns the person" do
74
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
74
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(true)
75
75
  @person.save!
76
76
  end
77
77
 
@@ -80,7 +80,7 @@ describe Mongoid::Commands do
80
80
  context "when validation fails" do
81
81
 
82
82
  it "it raises an error" do
83
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(false)
83
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(false)
84
84
  lambda { @person.save! }.should raise_error
85
85
  end
86
86
 
@@ -93,14 +93,14 @@ describe Mongoid::Commands do
93
93
  end
94
94
 
95
95
  it "delegates to the save command" do
96
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
96
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(true)
97
97
  @person.save!
98
98
  end
99
99
 
100
100
  context "when validation fails" do
101
101
 
102
102
  it "it raises an error " do
103
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(false)
103
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(false)
104
104
  lambda { @person.save! }.should raise_error
105
105
  end
106
106
 
@@ -108,7 +108,7 @@ describe Mongoid::Commands do
108
108
 
109
109
  it "runs the before and after create callbacks" do
110
110
  @person.expects(:run_callbacks).with(:before_create)
111
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
111
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(true)
112
112
  @person.expects(:run_callbacks).with(:after_create)
113
113
  @person.save!
114
114
  end
@@ -120,7 +120,7 @@ describe Mongoid::Commands do
120
120
  describe "#update_attributes" do
121
121
 
122
122
  it "delegates to the Save command" do
123
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
123
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, false).returns(true)
124
124
  @person.update_attributes({})
125
125
  end
126
126
 
@@ -131,7 +131,7 @@ describe Mongoid::Commands do
131
131
  context "when validation passes" do
132
132
 
133
133
  it "it returns the person" do
134
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(true)
134
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, false).returns(true)
135
135
  @person.update_attributes({}).should be_true
136
136
  end
137
137
 
@@ -140,7 +140,7 @@ describe Mongoid::Commands do
140
140
  context "when validation fails" do
141
141
 
142
142
  it "it raises an error" do
143
- Mongoid::Commands::Save.expects(:execute).with(@person, true).returns(false)
143
+ Mongoid::Commands::Save.expects(:execute).with(@person, true, true).returns(false)
144
144
  lambda { @person.update_attributes!({}) }.should raise_error
145
145
  end
146
146
 
@@ -0,0 +1,208 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts::Enumerable do
4
+
5
+ before do
6
+ @london = Address.new(:number => 1, :street => "Bond Street")
7
+ @shanghai = Address.new(:number => 10, :street => "Nan Jing Dong Lu")
8
+ @melbourne = Address.new(:number => 20, :street => "Bourke Street")
9
+ @new_york = Address.new(:number => 20, :street => "Broadway")
10
+ @docs = [ @london, @shanghai, @melbourne, @new_york ]
11
+ @selector = { :street => "Bond Street" }
12
+ @options = { :fields => [ :number ] }
13
+ @context = Mongoid::Contexts::Enumerable.new(@selector, @options, @docs)
14
+ end
15
+
16
+ describe "#aggregate" do
17
+
18
+ before do
19
+ @counts = @context.aggregate
20
+ end
21
+
22
+ it "groups by the fields provided in the options" do
23
+ @counts.size.should == 3
24
+ end
25
+
26
+ it "stores the counts in proper groups" do
27
+ @counts[1].should == 1
28
+ @counts[10].should == 1
29
+ @counts[20].should == 2
30
+ end
31
+ end
32
+
33
+ describe "#count" do
34
+
35
+ it "returns the size of the enumerable" do
36
+ @context.count.should == 4
37
+ end
38
+
39
+ end
40
+
41
+ describe "#execute" do
42
+
43
+ it "returns the matching documents from the array" do
44
+ @context.execute.should == [ @london ]
45
+ end
46
+
47
+ end
48
+
49
+ describe "#first" do
50
+
51
+ it "returns the first in the enumerable" do
52
+ @context.first.should == @london
53
+ end
54
+
55
+ end
56
+
57
+ describe "#group" do
58
+
59
+ before do
60
+ @group = @context.group
61
+ end
62
+
63
+ it "groups by the fields provided in the options" do
64
+ @group.size.should == 3
65
+ end
66
+
67
+ it "stores the documents in proper groups" do
68
+ @group[1].should == [ @london ]
69
+ @group[10].should == [ @shanghai ]
70
+ @group[20].should == [ @melbourne, @new_york ]
71
+ end
72
+
73
+ end
74
+
75
+ describe ".initialize" do
76
+
77
+ let(:selector) { { :field => "value" } }
78
+ let(:options) { { :skip => 20 } }
79
+ let(:documents) { [stub] }
80
+
81
+ before do
82
+ @context = Mongoid::Contexts::Enumerable.new(selector, options, documents)
83
+ end
84
+
85
+ it "sets the selector" do
86
+ @context.selector.should == selector
87
+ end
88
+
89
+ it "sets the options" do
90
+ @context.options.should == options
91
+ end
92
+
93
+ it "sets the documents" do
94
+ @context.documents.should == documents
95
+ end
96
+
97
+ end
98
+
99
+ describe "#last" do
100
+
101
+ it "returns the last in the enumerable" do
102
+ @context.last.should == @new_york
103
+ end
104
+
105
+ end
106
+
107
+ describe "#max" do
108
+
109
+ it "returns the max value for the supplied field" do
110
+ @context.max(:number).should == 20
111
+ end
112
+
113
+ end
114
+
115
+ describe "#min" do
116
+
117
+ it "returns the min value for the supplied field" do
118
+ @context.min(:number).should == 1
119
+ end
120
+
121
+ end
122
+
123
+ describe "#one" do
124
+
125
+ it "returns the first in the enumerable" do
126
+ @context.one.should == @london
127
+ end
128
+
129
+ end
130
+
131
+ describe "#page" do
132
+
133
+ context "when the page option exists" do
134
+
135
+ before do
136
+ @criteria = Mongoid::Criteria.new(Person).extras({ :page => 5 })
137
+ @context = Mongoid::Contexts::Enumerable.new({}, @criteria.options, [])
138
+ end
139
+
140
+ it "returns the page option" do
141
+ @context.page.should == 5
142
+ end
143
+
144
+ end
145
+
146
+ context "when the page option does not exist" do
147
+
148
+ before do
149
+ @criteria = Mongoid::Criteria.new(Person)
150
+ @context = Mongoid::Contexts::Enumerable.new({}, @criteria.options, [])
151
+ end
152
+
153
+ it "returns 1" do
154
+ @context.page.should == 1
155
+ end
156
+
157
+ end
158
+
159
+ end
160
+
161
+ describe "#paginate" do
162
+
163
+ before do
164
+ @criteria = Person.where(:_id => "1").skip(60).limit(20)
165
+ @context = Mongoid::Contexts::Enumerable.new(@criteria.selector, @criteria.options, [])
166
+ @results = @context.paginate
167
+ end
168
+
169
+ it "executes and paginates the results" do
170
+ @results.current_page.should == 4
171
+ @results.per_page.should == 20
172
+ end
173
+
174
+ end
175
+
176
+ describe "#per_page" do
177
+
178
+ context "when a limit option exists" do
179
+
180
+ it "returns 20" do
181
+ @context.per_page.should == 20
182
+ end
183
+
184
+ end
185
+
186
+ context "when a limit option does not exist" do
187
+
188
+ before do
189
+ @context = Mongoid::Contexts::Enumerable.new({}, { :limit => 50 }, [])
190
+ end
191
+
192
+ it "returns the limit" do
193
+ @context.per_page.should == 50
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+
200
+ describe "#sum" do
201
+
202
+ it "returns the sum of all the field values" do
203
+ @context.sum(:number).should == 51
204
+ end
205
+
206
+ end
207
+
208
+ end
@@ -0,0 +1,370 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts::Mongo do
4
+
5
+ describe "#aggregate" do
6
+
7
+ before do
8
+ @selector = {}
9
+ @options = { :fields => [:field1] }
10
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
11
+ end
12
+
13
+ context "when klass not provided" do
14
+
15
+ before do
16
+ @reduce = "function(obj, prev) { prev.count++; }"
17
+ @collection = mock
18
+ Person.expects(:collection).returns(@collection)
19
+ end
20
+
21
+ it "calls group on the collection with the aggregate js" do
22
+ @collection.expects(:group).with([:field1], {}, {:count => 0}, @reduce, true)
23
+ @context.aggregate
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ describe "#count" do
31
+
32
+ before do
33
+ @selector = { :_type => { "$in" => ["Doctor", "Person"] }, :test => "Testing" }
34
+ @options = {}
35
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
36
+ end
37
+
38
+ context "when criteria has not been executed" do
39
+
40
+ before do
41
+ @context.instance_variable_set(:@count, 34)
42
+ end
43
+
44
+ it "returns a count from the cursor" do
45
+ @context.count.should == 34
46
+ end
47
+
48
+ end
49
+
50
+ context "when criteria has been executed" do
51
+
52
+ before do
53
+ @collection = mock
54
+ @cursor = mock
55
+ Person.expects(:collection).returns(@collection)
56
+ end
57
+
58
+ it "returns the count from the cursor without creating the documents" do
59
+ @collection.expects(:find).with(@selector, {}).returns(@cursor)
60
+ @cursor.expects(:count).returns(10)
61
+ @context.count.should == 10
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ describe "#group" do
69
+
70
+ before do
71
+ @selector = { :_type => { "$in" => ["Doctor", "Person"] } }
72
+ @options = { :fields => [ :field1 ] }
73
+ @grouping = [{ "title" => "Sir", "group" => [{ "title" => "Sir", "age" => 30, "_type" => "Person" }] }]
74
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
75
+ end
76
+
77
+ context "when klass provided" do
78
+
79
+ before do
80
+ @reduce = "function(obj, prev) { prev.group.push(obj); }"
81
+ @collection = mock
82
+ Person.expects(:collection).returns(@collection)
83
+ end
84
+
85
+ it "calls group on the collection with the aggregate js" do
86
+ @collection.expects(:group).with([:field1], {:_type => { "$in" => ["Doctor", "Person"] }}, {:group => []}, @reduce, true).returns(@grouping)
87
+ @context.group
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ describe "#execute" do
95
+
96
+ let(:selector) { { :field => "value" } }
97
+ let(:options) { { :skip => 20 } }
98
+
99
+ before do
100
+ @cursor = stub(:count => 500)
101
+ @collection = mock
102
+ @person = mock
103
+ @klass = stub(:collection => @collection, :hereditary => false, :instantiate => @person)
104
+ @context = Mongoid::Contexts::Mongo.new(selector, options, @klass)
105
+ end
106
+
107
+ it "calls find on the collection" do
108
+ @collection.expects(:find).with(selector, options).returns(@cursor)
109
+ @cursor.expects(:collect).yields({ :title => "Sir" }).returns([@person])
110
+ @context.execute.should == [@person]
111
+ end
112
+
113
+ context "when field options are supplied" do
114
+
115
+ context "when _type not in the field list" do
116
+
117
+ before do
118
+ options[:fields] = [ :title ]
119
+ @expected_options = { :skip => 20, :fields => [ :title, :_type ] }
120
+ end
121
+
122
+ it "adds _type to the fields" do
123
+ @collection.expects(:find).with(selector, @expected_options).returns(@cursor)
124
+ @cursor.expects(:collect).yields({ :title => "Sir" }).returns([@person])
125
+ @context.execute.should == [@person]
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ describe ".initialize" do
135
+
136
+ let(:selector) { { :field => "value" } }
137
+ let(:options) { { :skip => 20 } }
138
+ let(:klass) { Person }
139
+
140
+ before do
141
+ @context = Mongoid::Contexts::Mongo.new(selector, options, klass)
142
+ end
143
+
144
+ it "sets the selector" do
145
+ @context.selector.should == selector
146
+ end
147
+
148
+ it "sets the options" do
149
+ @context.options.should == options
150
+ end
151
+
152
+ it "sets the klass" do
153
+ @context.klass.should == klass
154
+ end
155
+
156
+ end
157
+
158
+ describe "#last" do
159
+
160
+ before do
161
+ @collection = mock
162
+ Person.expects(:collection).returns(@collection)
163
+ end
164
+
165
+ context "when documents exist" do
166
+
167
+ before do
168
+ @selector = {}
169
+ @options = { :sort => [[:title, :asc]] }
170
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
171
+ @collection.expects(:find_one).with(@selector, { :sort => [[:title, :desc]] }).returns(
172
+ { "title" => "Sir", "_type" => "Person" }
173
+ )
174
+ end
175
+
176
+ it "calls find on the collection with the selector and sort options reversed" do
177
+ @context.last.should be_a_kind_of(Person)
178
+ end
179
+
180
+ end
181
+
182
+ context "when no documents exist" do
183
+
184
+ before do
185
+ @selector = {}
186
+ @options = { :sort => [[:_id, :asc]] }
187
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
188
+ @collection.expects(:find_one).with(@selector, { :sort => [[:_id, :desc]] }).returns(nil)
189
+ end
190
+
191
+ it "returns nil" do
192
+ @context.last.should be_nil
193
+ end
194
+
195
+ end
196
+
197
+ context "when no sorting options provided" do
198
+
199
+ before do
200
+ @selector = {}
201
+ @options = { :sort => [[:_id, :asc]] }
202
+ @context = Mongoid::Contexts::Mongo.new(@selector, @options, Person)
203
+ @collection.expects(:find_one).with(@selector, { :sort => [[:_id, :desc]] }).returns(
204
+ { "title" => "Sir", "_type" => "Person" }
205
+ )
206
+ end
207
+
208
+ it "defaults to sort by id" do
209
+ @context.last
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ describe "#max" do
217
+
218
+ before do
219
+ @reduce = Mongoid::Contexts::Mongo::MAX_REDUCE.gsub("[field]", "age")
220
+ @collection = mock
221
+ Person.expects(:collection).returns(@collection)
222
+ @context = Mongoid::Contexts::Mongo.new({}, {}, Person)
223
+ end
224
+
225
+ it "calls group on the collection with the aggregate js" do
226
+ @collection.expects(:group).with(
227
+ nil,
228
+ {},
229
+ {:max => "start"},
230
+ @reduce,
231
+ true
232
+ ).returns([{"max" => 200.0}])
233
+ @context.max(:age).should == 200.0
234
+ end
235
+
236
+ end
237
+
238
+ describe "#min" do
239
+
240
+ before do
241
+ @reduce = Mongoid::Contexts::Mongo::MIN_REDUCE.gsub("[field]", "age")
242
+ @collection = mock
243
+ Person.expects(:collection).returns(@collection)
244
+ @context = Mongoid::Contexts::Mongo.new({}, {}, Person)
245
+ end
246
+
247
+ it "calls group on the collection with the aggregate js" do
248
+ @collection.expects(:group).with(
249
+ nil,
250
+ {},
251
+ {:min => "start"},
252
+ @reduce,
253
+ true
254
+ ).returns([{"min" => 4.0}])
255
+ @context.min(:age).should == 4.0
256
+ end
257
+
258
+ end
259
+
260
+ describe "#one" do
261
+
262
+ context "when documents exist" do
263
+
264
+ before do
265
+ @collection = mock
266
+ Person.expects(:collection).returns(@collection)
267
+ @context = Mongoid::Contexts::Mongo.new({}, {}, Person)
268
+ @collection.expects(:find_one).with({}, {}).returns(
269
+ { "title"=> "Sir", "_type" => "Person" }
270
+ )
271
+ end
272
+
273
+ it "calls find on the collection with the selector and options" do
274
+ @context.one.should be_a_kind_of(Person)
275
+ end
276
+
277
+ end
278
+
279
+ context "when no documents exist" do
280
+
281
+ before do
282
+ @collection = mock
283
+ Person.expects(:collection).returns(@collection)
284
+ @context = Mongoid::Contexts::Mongo.new({}, {}, Person)
285
+ @collection.expects(:find_one).with({}, {}).returns(nil)
286
+ end
287
+
288
+ it "returns nil" do
289
+ @context.one.should be_nil
290
+ end
291
+
292
+ end
293
+
294
+ end
295
+
296
+ describe "#page" do
297
+
298
+ context "when the page option exists" do
299
+
300
+ before do
301
+ @criteria = Mongoid::Criteria.new(Person).extras({ :page => 5 })
302
+ @context = Mongoid::Contexts::Mongo.new({}, @criteria.options, Person)
303
+ end
304
+
305
+ it "returns the page option" do
306
+ @context.page.should == 5
307
+ end
308
+
309
+ end
310
+
311
+ context "when the page option does not exist" do
312
+
313
+ before do
314
+ @criteria = Mongoid::Criteria.new(Person)
315
+ @context = Mongoid::Contexts::Mongo.new({}, @criteria.options, Person)
316
+ end
317
+
318
+ it "returns 1" do
319
+ @context.page.should == 1
320
+ end
321
+
322
+ end
323
+
324
+ end
325
+
326
+ describe "#paginate" do
327
+
328
+ before do
329
+ @collection = mock
330
+ Person.expects(:collection).returns(@collection)
331
+ @criteria = Person.where(:_id => "1").skip(60).limit(20)
332
+ @context = Mongoid::Contexts::Mongo.new(@criteria.selector, @criteria.options, Person)
333
+ @collection.expects(:find).with({:_type => { "$in" => ["Doctor", "Person"] }, :_id => "1"}, :skip => 60, :limit => 20).returns([])
334
+ @results = @context.paginate
335
+ end
336
+
337
+ it "executes and paginates the results" do
338
+ @results.current_page.should == 4
339
+ @results.per_page.should == 20
340
+ end
341
+
342
+ end
343
+
344
+ describe "#sum" do
345
+
346
+ context "when klass not provided" do
347
+
348
+ before do
349
+ @reduce = Mongoid::Contexts::Mongo::SUM_REDUCE.gsub("[field]", "age")
350
+ @collection = mock
351
+ @context = Mongoid::Contexts::Mongo.new({}, {}, Person)
352
+ Person.expects(:collection).returns(@collection)
353
+ end
354
+
355
+ it "calls group on the collection with the aggregate js" do
356
+ @collection.expects(:group).with(
357
+ nil,
358
+ {},
359
+ {:sum => "start"},
360
+ @reduce,
361
+ true
362
+ ).returns([{"sum" => 50.0}])
363
+ @context.sum(:age).should == 50.0
364
+ end
365
+
366
+ end
367
+
368
+ end
369
+
370
+ end