humanoid 1.2.7

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 (210) hide show
  1. data/.gitignore +6 -0
  2. data/.watchr +29 -0
  3. data/HISTORY +342 -0
  4. data/MIT_LICENSE +20 -0
  5. data/README.rdoc +56 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/caliper.yml +4 -0
  9. data/humanoid.gemspec +374 -0
  10. data/lib/humanoid.rb +111 -0
  11. data/lib/humanoid/associations.rb +258 -0
  12. data/lib/humanoid/associations/belongs_to.rb +64 -0
  13. data/lib/humanoid/associations/belongs_to_related.rb +62 -0
  14. data/lib/humanoid/associations/has_many.rb +180 -0
  15. data/lib/humanoid/associations/has_many_related.rb +109 -0
  16. data/lib/humanoid/associations/has_one.rb +95 -0
  17. data/lib/humanoid/associations/has_one_related.rb +81 -0
  18. data/lib/humanoid/associations/options.rb +57 -0
  19. data/lib/humanoid/associations/proxy.rb +31 -0
  20. data/lib/humanoid/attributes.rb +184 -0
  21. data/lib/humanoid/callbacks.rb +23 -0
  22. data/lib/humanoid/collection.rb +118 -0
  23. data/lib/humanoid/collections/cyclic_iterator.rb +34 -0
  24. data/lib/humanoid/collections/master.rb +28 -0
  25. data/lib/humanoid/collections/mimic.rb +46 -0
  26. data/lib/humanoid/collections/operations.rb +41 -0
  27. data/lib/humanoid/collections/slaves.rb +44 -0
  28. data/lib/humanoid/commands.rb +182 -0
  29. data/lib/humanoid/commands/create.rb +21 -0
  30. data/lib/humanoid/commands/delete.rb +16 -0
  31. data/lib/humanoid/commands/delete_all.rb +23 -0
  32. data/lib/humanoid/commands/deletion.rb +18 -0
  33. data/lib/humanoid/commands/destroy.rb +19 -0
  34. data/lib/humanoid/commands/destroy_all.rb +23 -0
  35. data/lib/humanoid/commands/save.rb +27 -0
  36. data/lib/humanoid/components.rb +24 -0
  37. data/lib/humanoid/config.rb +84 -0
  38. data/lib/humanoid/contexts.rb +25 -0
  39. data/lib/humanoid/contexts/enumerable.rb +117 -0
  40. data/lib/humanoid/contexts/ids.rb +25 -0
  41. data/lib/humanoid/contexts/mongo.rb +224 -0
  42. data/lib/humanoid/contexts/paging.rb +42 -0
  43. data/lib/humanoid/criteria.rb +259 -0
  44. data/lib/humanoid/criterion/complex.rb +21 -0
  45. data/lib/humanoid/criterion/exclusion.rb +65 -0
  46. data/lib/humanoid/criterion/inclusion.rb +91 -0
  47. data/lib/humanoid/criterion/optional.rb +128 -0
  48. data/lib/humanoid/cursor.rb +82 -0
  49. data/lib/humanoid/document.rb +300 -0
  50. data/lib/humanoid/enslavement.rb +38 -0
  51. data/lib/humanoid/errors.rb +77 -0
  52. data/lib/humanoid/extensions.rb +84 -0
  53. data/lib/humanoid/extensions/array/accessors.rb +17 -0
  54. data/lib/humanoid/extensions/array/aliasing.rb +4 -0
  55. data/lib/humanoid/extensions/array/assimilation.rb +26 -0
  56. data/lib/humanoid/extensions/array/conversions.rb +29 -0
  57. data/lib/humanoid/extensions/array/parentization.rb +13 -0
  58. data/lib/humanoid/extensions/boolean/conversions.rb +16 -0
  59. data/lib/humanoid/extensions/date/conversions.rb +15 -0
  60. data/lib/humanoid/extensions/datetime/conversions.rb +17 -0
  61. data/lib/humanoid/extensions/float/conversions.rb +16 -0
  62. data/lib/humanoid/extensions/hash/accessors.rb +38 -0
  63. data/lib/humanoid/extensions/hash/assimilation.rb +30 -0
  64. data/lib/humanoid/extensions/hash/conversions.rb +15 -0
  65. data/lib/humanoid/extensions/hash/criteria_helpers.rb +20 -0
  66. data/lib/humanoid/extensions/hash/scoping.rb +12 -0
  67. data/lib/humanoid/extensions/integer/conversions.rb +16 -0
  68. data/lib/humanoid/extensions/nil/assimilation.rb +13 -0
  69. data/lib/humanoid/extensions/object/conversions.rb +33 -0
  70. data/lib/humanoid/extensions/proc/scoping.rb +12 -0
  71. data/lib/humanoid/extensions/string/conversions.rb +15 -0
  72. data/lib/humanoid/extensions/string/inflections.rb +97 -0
  73. data/lib/humanoid/extensions/symbol/inflections.rb +36 -0
  74. data/lib/humanoid/extensions/time/conversions.rb +18 -0
  75. data/lib/humanoid/factory.rb +19 -0
  76. data/lib/humanoid/field.rb +39 -0
  77. data/lib/humanoid/fields.rb +62 -0
  78. data/lib/humanoid/finders.rb +224 -0
  79. data/lib/humanoid/identity.rb +39 -0
  80. data/lib/humanoid/indexes.rb +30 -0
  81. data/lib/humanoid/matchers.rb +36 -0
  82. data/lib/humanoid/matchers/all.rb +11 -0
  83. data/lib/humanoid/matchers/default.rb +26 -0
  84. data/lib/humanoid/matchers/exists.rb +13 -0
  85. data/lib/humanoid/matchers/gt.rb +11 -0
  86. data/lib/humanoid/matchers/gte.rb +11 -0
  87. data/lib/humanoid/matchers/in.rb +11 -0
  88. data/lib/humanoid/matchers/lt.rb +11 -0
  89. data/lib/humanoid/matchers/lte.rb +11 -0
  90. data/lib/humanoid/matchers/ne.rb +11 -0
  91. data/lib/humanoid/matchers/nin.rb +11 -0
  92. data/lib/humanoid/matchers/size.rb +11 -0
  93. data/lib/humanoid/memoization.rb +27 -0
  94. data/lib/humanoid/named_scope.rb +40 -0
  95. data/lib/humanoid/scope.rb +75 -0
  96. data/lib/humanoid/timestamps.rb +30 -0
  97. data/lib/humanoid/versioning.rb +28 -0
  98. data/perf/benchmark.rb +77 -0
  99. data/spec/integration/humanoid/associations_spec.rb +301 -0
  100. data/spec/integration/humanoid/attributes_spec.rb +22 -0
  101. data/spec/integration/humanoid/commands_spec.rb +216 -0
  102. data/spec/integration/humanoid/contexts/enumerable_spec.rb +33 -0
  103. data/spec/integration/humanoid/criteria_spec.rb +224 -0
  104. data/spec/integration/humanoid/document_spec.rb +587 -0
  105. data/spec/integration/humanoid/extensions_spec.rb +26 -0
  106. data/spec/integration/humanoid/finders_spec.rb +119 -0
  107. data/spec/integration/humanoid/inheritance_spec.rb +137 -0
  108. data/spec/integration/humanoid/named_scope_spec.rb +46 -0
  109. data/spec/models/address.rb +39 -0
  110. data/spec/models/animal.rb +6 -0
  111. data/spec/models/comment.rb +8 -0
  112. data/spec/models/country_code.rb +6 -0
  113. data/spec/models/employer.rb +5 -0
  114. data/spec/models/game.rb +6 -0
  115. data/spec/models/inheritance.rb +56 -0
  116. data/spec/models/location.rb +5 -0
  117. data/spec/models/mixed_drink.rb +4 -0
  118. data/spec/models/name.rb +13 -0
  119. data/spec/models/namespacing.rb +11 -0
  120. data/spec/models/patient.rb +4 -0
  121. data/spec/models/person.rb +98 -0
  122. data/spec/models/pet.rb +7 -0
  123. data/spec/models/pet_owner.rb +6 -0
  124. data/spec/models/phone.rb +7 -0
  125. data/spec/models/post.rb +15 -0
  126. data/spec/models/translation.rb +5 -0
  127. data/spec/models/vet_visit.rb +5 -0
  128. data/spec/spec.opts +3 -0
  129. data/spec/spec_helper.rb +31 -0
  130. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +141 -0
  131. data/spec/unit/mongoid/associations/belongs_to_spec.rb +193 -0
  132. data/spec/unit/mongoid/associations/has_many_related_spec.rb +387 -0
  133. data/spec/unit/mongoid/associations/has_many_spec.rb +471 -0
  134. data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
  135. data/spec/unit/mongoid/associations/has_one_spec.rb +282 -0
  136. data/spec/unit/mongoid/associations/options_spec.rb +191 -0
  137. data/spec/unit/mongoid/associations_spec.rb +545 -0
  138. data/spec/unit/mongoid/attributes_spec.rb +484 -0
  139. data/spec/unit/mongoid/callbacks_spec.rb +55 -0
  140. data/spec/unit/mongoid/collection_spec.rb +171 -0
  141. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  142. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  143. data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
  144. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  145. data/spec/unit/mongoid/commands/create_spec.rb +30 -0
  146. data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
  147. data/spec/unit/mongoid/commands/delete_spec.rb +35 -0
  148. data/spec/unit/mongoid/commands/destroy_all_spec.rb +23 -0
  149. data/spec/unit/mongoid/commands/destroy_spec.rb +44 -0
  150. data/spec/unit/mongoid/commands/save_spec.rb +105 -0
  151. data/spec/unit/mongoid/commands_spec.rb +282 -0
  152. data/spec/unit/mongoid/config_spec.rb +165 -0
  153. data/spec/unit/mongoid/contexts/enumerable_spec.rb +374 -0
  154. data/spec/unit/mongoid/contexts/mongo_spec.rb +505 -0
  155. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  156. data/spec/unit/mongoid/criteria_spec.rb +769 -0
  157. data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
  158. data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
  159. data/spec/unit/mongoid/criterion/inclusion_spec.rb +211 -0
  160. data/spec/unit/mongoid/criterion/optional_spec.rb +329 -0
  161. data/spec/unit/mongoid/cursor_spec.rb +74 -0
  162. data/spec/unit/mongoid/document_spec.rb +986 -0
  163. data/spec/unit/mongoid/enslavement_spec.rb +63 -0
  164. data/spec/unit/mongoid/errors_spec.rb +103 -0
  165. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  166. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  167. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
  168. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  169. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  170. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
  171. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +70 -0
  172. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  173. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  174. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
  175. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
  176. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  177. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  178. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  179. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
  180. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +43 -0
  181. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  182. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
  183. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  184. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
  185. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
  186. data/spec/unit/mongoid/factory_spec.rb +31 -0
  187. data/spec/unit/mongoid/field_spec.rb +81 -0
  188. data/spec/unit/mongoid/fields_spec.rb +158 -0
  189. data/spec/unit/mongoid/finders_spec.rb +368 -0
  190. data/spec/unit/mongoid/identity_spec.rb +88 -0
  191. data/spec/unit/mongoid/indexes_spec.rb +93 -0
  192. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  193. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  194. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  195. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  196. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  197. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  198. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  199. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  200. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  201. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  202. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  203. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  204. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  205. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  206. data/spec/unit/mongoid/scope_spec.rb +240 -0
  207. data/spec/unit/mongoid/timestamps_spec.rb +25 -0
  208. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  209. data/spec/unit/mongoid_spec.rb +37 -0
  210. metadata +431 -0
@@ -0,0 +1,505 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Contexts::Mongo do
4
+
5
+ describe "#aggregate" do
6
+
7
+ before do
8
+ @criteria = Humanoid::Criteria.new(Person)
9
+ @criteria.only(:field1)
10
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
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], {:_type => {'$in' => ['Doctor', 'Person']}}, {: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
+ @criteria = Humanoid::Criteria.new(Person)
34
+ @criteria.where(:test => 'Testing')
35
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
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(@criteria.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 "#execute" do
69
+
70
+ let(:selector) { { :field => "value" } }
71
+ let(:options) { { :skip => 20 } }
72
+
73
+ before do
74
+ @cursor = stub(:count => 500)
75
+ @collection = mock
76
+ @klass = stub(:collection => @collection, :hereditary => false, :instantiate => @person)
77
+ @criteria = Humanoid::Criteria.new(@klass)
78
+ @criteria.where(selector).skip(20)
79
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
80
+ end
81
+
82
+ it "calls find on the collection" do
83
+ @collection.expects(:find).with(selector, options).returns(@cursor)
84
+ @context.execute.should == @cursor
85
+ end
86
+
87
+ context "when paginating" do
88
+
89
+ it "should find the count from the cursor" do
90
+ @collection.expects(:find).with(selector, options).returns(@cursor)
91
+ @context.execute(true).should == @cursor
92
+ @context.count.should == 500
93
+ end
94
+
95
+ end
96
+
97
+ context "when field options are supplied" do
98
+
99
+ context "when _type not in the field list" do
100
+
101
+ before do
102
+ @criteria.only(:title)
103
+ @expected_options = { :skip => 20, :fields => [ :title, :_type ] }
104
+ end
105
+
106
+ it "adds _type to the fields" do
107
+ @collection.expects(:find).with(selector, @expected_options).returns(@cursor)
108
+ @context.execute.should == @cursor
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ describe "#group" do
118
+
119
+ before do
120
+ @criteria = Humanoid::Criteria.new(Person)
121
+ @criteria.only(:field1)
122
+ @grouping = [{ "title" => "Sir", "group" => [{ "title" => "Sir", "age" => 30, "_type" => "Person" }] }]
123
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
124
+ end
125
+
126
+ context "when klass provided" do
127
+
128
+ before do
129
+ @reduce = "function(obj, prev) { prev.group.push(obj); }"
130
+ @collection = mock
131
+ Person.expects(:collection).returns(@collection)
132
+ end
133
+
134
+ it "calls group on the collection with the aggregate js" do
135
+ @collection.expects(:group).with(
136
+ [:field1],
137
+ {:_type => { "$in" => ["Doctor", "Person"] }},
138
+ {:group => []},
139
+ @reduce,
140
+ true
141
+ ).returns(@grouping)
142
+ @context.group
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+
149
+ describe ".initialize" do
150
+
151
+ let(:selector) { { :field => "value" } }
152
+ let(:options) { { :skip => 20 } }
153
+ let(:klass) { Person }
154
+
155
+ before do
156
+ @criteria = Humanoid::Criteria.new(klass)
157
+ @criteria.where(selector).skip(20)
158
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
159
+ end
160
+
161
+ it "sets the selector" do
162
+ @context.selector.should == @criteria.selector
163
+ end
164
+
165
+ it "sets the options" do
166
+ @context.options.should == options
167
+ end
168
+
169
+ it "sets the klass" do
170
+ @context.klass.should == klass
171
+ end
172
+
173
+ it "set the selector to query across the _type of the Criteria's klass when it is hereditary" do
174
+ @context.selector[:_type].should == {'$in' => Person._types}
175
+ end
176
+ end
177
+
178
+ describe "#last" do
179
+
180
+ before do
181
+ @collection = mock
182
+ Person.expects(:collection).returns(@collection)
183
+ end
184
+
185
+ context "when documents exist" do
186
+
187
+ before do
188
+ @criteria = Humanoid::Criteria.new(Person)
189
+ @criteria.order_by([[:title, :asc]])
190
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
191
+ @collection.expects(:find_one).with({:_type => {'$in' => ['Doctor', 'Person']}}, { :sort => [[:title, :desc]] }).returns(
192
+ { "title" => "Sir", "_type" => "Person" }
193
+ )
194
+ end
195
+
196
+ it "calls find on the collection with the selector and sort options reversed" do
197
+ @context.last.should be_a_kind_of(Person)
198
+ end
199
+
200
+ end
201
+
202
+ context "when no documents exist" do
203
+
204
+ before do
205
+ @criteria = Humanoid::Criteria.new(Person)
206
+ @criteria.order_by([[:_id, :asc]])
207
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
208
+ @collection.expects(:find_one).with({:_type => {'$in' => ['Doctor', 'Person']}}, { :sort => [[:_id, :desc]] }).returns(nil)
209
+ end
210
+
211
+ it "returns nil" do
212
+ @context.last.should be_nil
213
+ end
214
+
215
+ end
216
+
217
+ context "when no sorting options provided" do
218
+
219
+ before do
220
+ @criteria = Humanoid::Criteria.new(Person)
221
+ @criteria.order_by([[:_id, :asc]])
222
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
223
+ @collection.expects(:find_one).with({:_type => {'$in' => ['Doctor', 'Person']}}, { :sort => [[:_id, :desc]] }).returns(
224
+ { "title" => "Sir", "_type" => "Person" }
225
+ )
226
+ end
227
+
228
+ it "defaults to sort by id" do
229
+ @context.last
230
+ end
231
+
232
+ end
233
+
234
+ end
235
+
236
+ describe "#max" do
237
+
238
+ before do
239
+ @reduce = Humanoid::Contexts::Mongo::MAX_REDUCE.gsub("[field]", "age")
240
+ @collection = mock
241
+ Person.expects(:collection).returns(@collection)
242
+ @criteria = Humanoid::Criteria.new(Person)
243
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
244
+ end
245
+
246
+ it "calls group on the collection with the aggregate js" do
247
+ @collection.expects(:group).with(
248
+ nil,
249
+ {:_type => {'$in' => ['Doctor', 'Person']}},
250
+ {:max => "start"},
251
+ @reduce,
252
+ true
253
+ ).returns([{"max" => 200.0}])
254
+ @context.max(:age).should == 200.0
255
+ end
256
+
257
+ end
258
+
259
+ describe "#min" do
260
+
261
+ before do
262
+ @reduce = Humanoid::Contexts::Mongo::MIN_REDUCE.gsub("[field]", "age")
263
+ @collection = mock
264
+ Person.expects(:collection).returns(@collection)
265
+ @criteria = Humanoid::Criteria.new(Person)
266
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
267
+ end
268
+
269
+ it "calls group on the collection with the aggregate js" do
270
+ @collection.expects(:group).with(
271
+ nil,
272
+ {:_type => {'$in' => ['Doctor', 'Person']}},
273
+ {:min => "start"},
274
+ @reduce,
275
+ true
276
+ ).returns([{"min" => 4.0}])
277
+ @context.min(:age).should == 4.0
278
+ end
279
+
280
+ end
281
+
282
+ describe "#one" do
283
+
284
+ context "when documents exist" do
285
+
286
+ before do
287
+ Person.expects(:collection).returns(@collection)
288
+ @criteria = Humanoid::Criteria.new(Person)
289
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
290
+ @collection.expects(:find_one).with({:_type => {'$in' => ['Doctor', 'Person']}}, {}).returns(
291
+ { "title"=> "Sir", "_type" => "Person" }
292
+ )
293
+ end
294
+
295
+ it "calls find on the collection with the selector and options" do
296
+ @context.one.should be_a_kind_of(Person)
297
+ end
298
+
299
+ end
300
+
301
+ context "when no documents exist" do
302
+
303
+ before do
304
+ @collection = mock
305
+ Person.expects(:collection).returns(@collection)
306
+ @criteria = Humanoid::Criteria.new(Person)
307
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
308
+ @collection.expects(:find_one).with({:_type => {'$in' => ['Doctor', 'Person']}}, {}).returns(nil)
309
+ end
310
+
311
+ it "returns nil" do
312
+ @context.one.should be_nil
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+
319
+ describe "#page" do
320
+
321
+ context "when the page option exists" do
322
+
323
+ before do
324
+ @criteria = Humanoid::Criteria.new(Person).extras({ :page => 5 })
325
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
326
+ end
327
+
328
+ it "returns the page option" do
329
+ @context.page.should == 5
330
+ end
331
+
332
+ end
333
+
334
+ context "when the page option does not exist" do
335
+
336
+ before do
337
+ @criteria = Humanoid::Criteria.new(Person)
338
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
339
+ end
340
+
341
+ it "returns 1" do
342
+ @context.page.should == 1
343
+ end
344
+
345
+ end
346
+
347
+ end
348
+
349
+ describe "#paginate" do
350
+
351
+ before do
352
+ @collection = mock
353
+ Person.expects(:collection).returns(@collection)
354
+ @criteria = Person.where(:_id => "1").skip(60).limit(20)
355
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
356
+ @collection.expects(:find).with(
357
+ {:_type => { "$in" => ["Doctor", "Person"] }, :_id => "1"}, :skip => 60, :limit => 20
358
+ ).returns([])
359
+ @results = @context.paginate
360
+ end
361
+
362
+ it "executes and paginates the results" do
363
+ @results.current_page.should == 4
364
+ @results.per_page.should == 20
365
+ end
366
+
367
+ end
368
+
369
+ describe "#sum" do
370
+
371
+ context "when klass not provided" do
372
+
373
+ before do
374
+ @reduce = Humanoid::Contexts::Mongo::SUM_REDUCE.gsub("[field]", "age")
375
+ @collection = mock
376
+ @criteria = Humanoid::Criteria.new(Person)
377
+ @context = Humanoid::Contexts::Mongo.new(@criteria)
378
+ Person.expects(:collection).returns(@collection)
379
+ end
380
+
381
+ it "calls group on the collection with the aggregate js" do
382
+ @collection.expects(:group).with(
383
+ nil,
384
+ {:_type => {'$in' => ['Doctor', 'Person']}},
385
+ {:sum => "start"},
386
+ @reduce,
387
+ true
388
+ ).returns([{"sum" => 50.0}])
389
+ @context.sum(:age).should == 50.0
390
+ end
391
+
392
+ end
393
+
394
+ end
395
+
396
+ context "#id_criteria" do
397
+
398
+ let(:criteria) { Humanoid::Criteria.new(Person) }
399
+ let(:context) { criteria.context }
400
+
401
+ context "with a single argument" do
402
+
403
+ let(:id) { Mongo::ObjectID.new.to_s }
404
+
405
+ before do
406
+ criteria.expects(:id).with(id).returns(criteria)
407
+ end
408
+
409
+ context "when the document is found" do
410
+
411
+ let(:document) { stub }
412
+
413
+ it "returns a matching document" do
414
+ context.expects(:one).returns(document)
415
+ document.expects(:blank? => false)
416
+ context.id_criteria(id).should == document
417
+ end
418
+
419
+ end
420
+
421
+ context "when the document is not found" do
422
+
423
+ it "raises an error" do
424
+ context.expects(:one).returns(nil)
425
+ lambda { context.id_criteria(id) }.should raise_error
426
+ end
427
+
428
+ end
429
+
430
+ end
431
+
432
+ context "multiple arguments" do
433
+
434
+ context "when an array of ids" do
435
+
436
+ let(:ids) do
437
+ (0..2).inject([]) { |ary, i| ary << Mongo::ObjectID.new.to_s }
438
+ end
439
+
440
+ context "when documents are found" do
441
+
442
+ let(:docs) do
443
+ (0..2).inject([]) { |ary, i| ary << stub }
444
+ end
445
+
446
+ before do
447
+ criteria.expects(:id).with(ids).returns(criteria)
448
+ end
449
+
450
+ it "returns matching documents" do
451
+ context.expects(:execute).returns(docs)
452
+ context.id_criteria(ids).should == docs
453
+ end
454
+
455
+ end
456
+
457
+ context "when documents are not found" do
458
+
459
+ it "raises an error" do
460
+ context.expects(:execute).returns([])
461
+ lambda { context.id_criteria(ids) }.should raise_error
462
+ end
463
+
464
+ end
465
+
466
+ end
467
+
468
+ context "when an array of object ids" do
469
+
470
+ let(:ids) do
471
+ (0..2).inject([]) { |ary, i| ary << Mongo::ObjectID.new }
472
+ end
473
+
474
+ context "when documents are found" do
475
+
476
+ let(:docs) do
477
+ (0..2).inject([]) { |ary, i| ary << stub }
478
+ end
479
+
480
+ before do
481
+ criteria.expects(:id).with(ids).returns(criteria)
482
+ end
483
+
484
+ it "returns matching documents" do
485
+ context.expects(:execute).returns(docs)
486
+ context.id_criteria(ids).should == docs
487
+ end
488
+
489
+ end
490
+
491
+ context "when documents are not found" do
492
+
493
+ it "raises an error" do
494
+ context.expects(:execute).returns([])
495
+ lambda { context.id_criteria(ids) }.should raise_error
496
+ end
497
+
498
+ end
499
+
500
+ end
501
+ end
502
+
503
+ end
504
+
505
+ end