mongoid 1.9.5 → 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. data/.gitignore +6 -0
  2. data/.watchr +29 -0
  3. data/Rakefile +52 -0
  4. data/VERSION +1 -0
  5. data/caliper.yml +4 -0
  6. data/lib/mongoid.rb +20 -9
  7. data/lib/mongoid/associations.rb +100 -123
  8. data/lib/mongoid/associations/belongs_to_related.rb +3 -2
  9. data/lib/mongoid/associations/{embeds_many.rb → embed_many.rb} +29 -90
  10. data/lib/mongoid/associations/{embeds_one.rb → embed_one.rb} +7 -8
  11. data/lib/mongoid/associations/embedded_in.rb +4 -12
  12. data/lib/mongoid/associations/has_many_related.rb +4 -52
  13. data/lib/mongoid/associations/has_one_related.rb +4 -8
  14. data/lib/mongoid/associations/meta_data.rb +1 -2
  15. data/lib/mongoid/associations/options.rb +1 -6
  16. data/lib/mongoid/associations/proxy.rb +21 -14
  17. data/lib/mongoid/attributes.rb +13 -33
  18. data/lib/mongoid/callbacks.rb +11 -16
  19. data/lib/mongoid/collection.rb +3 -4
  20. data/lib/mongoid/collections/master.rb +2 -3
  21. data/lib/mongoid/collections/mimic.rb +46 -0
  22. data/lib/mongoid/collections/slaves.rb +2 -3
  23. data/lib/mongoid/commands.rb +161 -0
  24. data/lib/mongoid/commands/create.rb +19 -0
  25. data/lib/mongoid/commands/delete.rb +16 -0
  26. data/lib/mongoid/commands/delete_all.rb +23 -0
  27. data/lib/mongoid/commands/deletion.rb +18 -0
  28. data/lib/mongoid/commands/destroy.rb +17 -0
  29. data/lib/mongoid/commands/destroy_all.rb +23 -0
  30. data/lib/mongoid/commands/save.rb +29 -0
  31. data/lib/mongoid/components.rb +6 -4
  32. data/lib/mongoid/config.rb +15 -134
  33. data/lib/mongoid/contexts.rb +1 -1
  34. data/lib/mongoid/contexts/enumerable.rb +1 -1
  35. data/lib/mongoid/contexts/mongo.rb +1 -1
  36. data/lib/mongoid/contexts/paging.rb +2 -10
  37. data/lib/mongoid/criterion/inclusion.rb +0 -17
  38. data/lib/mongoid/criterion/optional.rb +1 -1
  39. data/lib/mongoid/cursor.rb +1 -0
  40. data/lib/mongoid/document.rb +45 -49
  41. data/lib/mongoid/errors.rb +1 -32
  42. data/lib/mongoid/extensions.rb +10 -12
  43. data/lib/mongoid/extensions/array/conversions.rb +6 -8
  44. data/lib/mongoid/extensions/big_decimal/conversions.rb +2 -2
  45. data/lib/mongoid/extensions/boolean/conversions.rb +2 -8
  46. data/lib/mongoid/extensions/date/conversions.rb +4 -13
  47. data/lib/mongoid/extensions/datetime/conversions.rb +6 -1
  48. data/lib/mongoid/extensions/float/conversions.rb +1 -5
  49. data/lib/mongoid/extensions/hash/assimilation.rb +3 -12
  50. data/lib/mongoid/extensions/hash/conversions.rb +4 -34
  51. data/lib/mongoid/extensions/integer/conversions.rb +1 -5
  52. data/lib/mongoid/extensions/nil/assimilation.rb +0 -4
  53. data/lib/mongoid/extensions/object/conversions.rb +2 -8
  54. data/lib/mongoid/extensions/objectid/conversions.rb +1 -1
  55. data/lib/mongoid/extensions/string/conversions.rb +1 -1
  56. data/lib/mongoid/extensions/symbol/inflections.rb +1 -1
  57. data/lib/mongoid/extensions/time/conversions.rb +18 -0
  58. data/lib/mongoid/factory.rb +1 -2
  59. data/lib/mongoid/field.rb +2 -9
  60. data/lib/mongoid/fields.rb +7 -11
  61. data/lib/mongoid/finders.rb +2 -2
  62. data/lib/mongoid/identity.rb +4 -4
  63. data/lib/mongoid/indexes.rb +7 -10
  64. data/lib/mongoid/memoization.rb +2 -8
  65. data/lib/mongoid/named_scope.rb +5 -0
  66. data/lib/mongoid/observable.rb +1 -1
  67. data/lib/mongoid/paths.rb +22 -30
  68. data/lib/mongoid/state.rb +21 -28
  69. data/lib/mongoid/timestamps.rb +1 -1
  70. data/lib/mongoid/validations.rb +51 -0
  71. data/lib/mongoid/validations/associated.rb +32 -0
  72. data/lib/mongoid/validations/locale/en.yml +4 -0
  73. data/lib/mongoid/validations/uniqueness.rb +22 -0
  74. data/lib/mongoid/versioning.rb +1 -2
  75. data/mongoid.gemspec +408 -0
  76. data/perf/benchmark.rb +77 -0
  77. data/spec/integration/mongoid/associations_spec.rb +340 -0
  78. data/spec/integration/mongoid/attributes_spec.rb +22 -0
  79. data/spec/integration/mongoid/commands_spec.rb +227 -0
  80. data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
  81. data/spec/integration/mongoid/criteria_spec.rb +272 -0
  82. data/spec/integration/mongoid/document_spec.rb +650 -0
  83. data/spec/integration/mongoid/extensions_spec.rb +22 -0
  84. data/spec/integration/mongoid/finders_spec.rb +119 -0
  85. data/spec/integration/mongoid/inheritance_spec.rb +137 -0
  86. data/spec/integration/mongoid/named_scope_spec.rb +46 -0
  87. data/spec/models/address.rb +39 -0
  88. data/spec/models/animal.rb +6 -0
  89. data/spec/models/callbacks.rb +18 -0
  90. data/spec/models/comment.rb +8 -0
  91. data/spec/models/country_code.rb +6 -0
  92. data/spec/models/employer.rb +5 -0
  93. data/spec/models/game.rb +7 -0
  94. data/spec/models/inheritance.rb +56 -0
  95. data/spec/models/location.rb +5 -0
  96. data/spec/models/mixed_drink.rb +4 -0
  97. data/spec/models/name.rb +13 -0
  98. data/spec/models/namespacing.rb +11 -0
  99. data/spec/models/patient.rb +4 -0
  100. data/spec/models/person.rb +99 -0
  101. data/spec/models/pet.rb +7 -0
  102. data/spec/models/pet_owner.rb +6 -0
  103. data/spec/models/phone.rb +7 -0
  104. data/spec/models/post.rb +15 -0
  105. data/spec/models/translation.rb +5 -0
  106. data/spec/models/vet_visit.rb +5 -0
  107. data/spec/spec.opts +3 -0
  108. data/spec/spec_helper.rb +31 -0
  109. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +145 -0
  110. data/spec/unit/mongoid/associations/embed_many_spec.rb +516 -0
  111. data/spec/unit/mongoid/associations/embed_one_spec.rb +282 -0
  112. data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
  113. data/spec/unit/mongoid/associations/has_many_related_spec.rb +418 -0
  114. data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
  115. data/spec/unit/mongoid/associations/meta_data_spec.rb +88 -0
  116. data/spec/unit/mongoid/associations/options_spec.rb +192 -0
  117. data/spec/unit/mongoid/associations_spec.rb +595 -0
  118. data/spec/unit/mongoid/attributes_spec.rb +507 -0
  119. data/spec/unit/mongoid/callbacks_spec.rb +55 -0
  120. data/spec/unit/mongoid/collection_spec.rb +187 -0
  121. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  122. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  123. data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
  124. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  125. data/spec/unit/mongoid/commands/create_spec.rb +31 -0
  126. data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
  127. data/spec/unit/mongoid/commands/delete_spec.rb +38 -0
  128. data/spec/unit/mongoid/commands/destroy_all_spec.rb +21 -0
  129. data/spec/unit/mongoid/commands/destroy_spec.rb +51 -0
  130. data/spec/unit/mongoid/commands/save_spec.rb +107 -0
  131. data/spec/unit/mongoid/commands_spec.rb +270 -0
  132. data/spec/unit/mongoid/config_spec.rb +172 -0
  133. data/spec/unit/mongoid/contexts/enumerable_spec.rb +421 -0
  134. data/spec/unit/mongoid/contexts/mongo_spec.rb +682 -0
  135. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  136. data/spec/unit/mongoid/criteria_spec.rb +824 -0
  137. data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
  138. data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
  139. data/spec/unit/mongoid/criterion/inclusion_spec.rb +219 -0
  140. data/spec/unit/mongoid/criterion/optional_spec.rb +319 -0
  141. data/spec/unit/mongoid/cursor_spec.rb +74 -0
  142. data/spec/unit/mongoid/deprecation_spec.rb +24 -0
  143. data/spec/unit/mongoid/document_spec.rb +818 -0
  144. data/spec/unit/mongoid/errors_spec.rb +103 -0
  145. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  146. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  147. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
  148. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  149. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +22 -0
  150. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  151. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  152. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
  153. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +67 -0
  154. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  155. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  156. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
  157. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
  158. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  159. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  160. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  161. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
  162. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +57 -0
  163. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  164. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
  165. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  166. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
  167. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
  168. data/spec/unit/mongoid/extras_spec.rb +102 -0
  169. data/spec/unit/mongoid/factory_spec.rb +31 -0
  170. data/spec/unit/mongoid/field_spec.rb +143 -0
  171. data/spec/unit/mongoid/fields_spec.rb +181 -0
  172. data/spec/unit/mongoid/finders_spec.rb +404 -0
  173. data/spec/unit/mongoid/identity_spec.rb +109 -0
  174. data/spec/unit/mongoid/indexes_spec.rb +93 -0
  175. data/spec/unit/mongoid/javascript_spec.rb +48 -0
  176. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  177. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  178. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  179. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  180. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  181. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  182. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  183. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  184. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  185. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  186. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  187. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  188. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  189. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  190. data/spec/unit/mongoid/observable_spec.rb +46 -0
  191. data/spec/unit/mongoid/paths_spec.rb +124 -0
  192. data/spec/unit/mongoid/scope_spec.rb +240 -0
  193. data/spec/unit/mongoid/state_spec.rb +83 -0
  194. data/spec/unit/mongoid/timestamps_spec.rb +25 -0
  195. data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
  196. data/spec/unit/mongoid/validations/uniqueness_spec.rb +47 -0
  197. data/spec/unit/mongoid/validations_spec.rb +190 -0
  198. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  199. data/spec/unit/mongoid_spec.rb +46 -0
  200. metadata +316 -110
  201. data/lib/mongoid/collections.rb +0 -41
  202. data/lib/mongoid/concern.rb +0 -31
  203. data/lib/mongoid/dirty.rb +0 -253
  204. data/lib/mongoid/extensions/time_conversions.rb +0 -35
  205. data/lib/mongoid/persistence.rb +0 -222
  206. data/lib/mongoid/persistence/command.rb +0 -39
  207. data/lib/mongoid/persistence/insert.rb +0 -50
  208. data/lib/mongoid/persistence/insert_embedded.rb +0 -38
  209. data/lib/mongoid/persistence/remove.rb +0 -39
  210. data/lib/mongoid/persistence/remove_all.rb +0 -37
  211. data/lib/mongoid/persistence/remove_embedded.rb +0 -50
  212. data/lib/mongoid/persistence/update.rb +0 -63
  213. data/lib/mongoid/version.rb +0 -4
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts do
4
+
5
+ context ".context_for" do
6
+ let(:klass) { stub('klass', :embedded => false) }
7
+ let(:criteria) { stub('criteria', :klass => klass) }
8
+
9
+ context "when criteria is for a top-level Mongoid::Document" do
10
+ it "creates a Mongo context" do
11
+ Mongoid::Contexts::Mongo.expects(:new).with(criteria)
12
+ Mongoid::Contexts.context_for(criteria)
13
+ end
14
+ end
15
+
16
+ context "when criteria is for an embedded Mongoid::Document" do
17
+ it "creates a Mongo context" do
18
+ klass.stubs(:embedded).returns(true)
19
+ Mongoid::Contexts::Enumerable.expects(:new).with(criteria)
20
+ Mongoid::Contexts.context_for(criteria)
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,824 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Criteria do
4
+
5
+ before do
6
+ @criteria = Mongoid::Criteria.new(Person)
7
+ @canvas_criteria = Mongoid::Criteria.new(Canvas)
8
+ end
9
+
10
+ describe "#+" do
11
+
12
+ before do
13
+ @sir = Person.new(:title => "Sir")
14
+ @canvas = Canvas.new
15
+ end
16
+
17
+ context "when the criteria has not been executed" do
18
+
19
+ before do
20
+ @collection = mock
21
+ @cursor = stub(:count => 1)
22
+ @cursor.expects(:each).at_least_once.yields(@sir)
23
+ Person.expects(:collection).at_least_once.returns(@collection)
24
+ @collection.expects(:find).at_least_once.returns(@cursor)
25
+ end
26
+
27
+ it "executes the criteria and concats the results" do
28
+ results = @criteria + [ @canvas ]
29
+ results.should == [ @sir, @canvas ]
30
+ end
31
+
32
+ end
33
+
34
+ context "when the other is a criteria" do
35
+
36
+ before do
37
+ @collection = mock
38
+ @canvas_collection = mock
39
+ @cursor = stub(:count => 1)
40
+ @canvas_cursor = stub(:count => 1)
41
+ @cursor.expects(:each).at_least_once.yields(@sir)
42
+ @canvas_cursor.expects(:each).at_least_once.yields(@canvas)
43
+ Person.expects(:collection).at_least_once.returns(@collection)
44
+ @collection.expects(:find).at_least_once.returns(@cursor)
45
+ Canvas.expects(:collection).at_least_once.returns(@canvas_collection)
46
+ @canvas_collection.expects(:find).at_least_once.returns(@canvas_cursor)
47
+ end
48
+
49
+ it "concats the results" do
50
+ results = @criteria + @canvas_criteria
51
+ results.should == [ @sir, @canvas ]
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ describe "#-" do
59
+
60
+ before do
61
+ @sir = Person.new(:title => "Sir")
62
+ @madam = Person.new(:title => "Madam")
63
+ end
64
+
65
+ context "when the criteria has not been executed" do
66
+
67
+ before do
68
+ @collection = mock
69
+ @cursor = stub(:count => 1)
70
+ @cursor.expects(:each).yields(@madam)
71
+ Person.expects(:collection).returns(@collection)
72
+ @collection.expects(:find).returns(@cursor)
73
+ end
74
+
75
+ it "executes the criteria and returns the difference" do
76
+ results = @criteria - [ @sir ]
77
+ results.should == [ @madam ]
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+ describe "#[]" do
85
+
86
+ before do
87
+ @criteria.where(:title => "Sir")
88
+ @collection = stub
89
+ @person = Person.new(:title => "Sir")
90
+ @cursor = stub(:count => 10)
91
+ @cursor.expects(:each).yields(@person)
92
+ end
93
+
94
+ context "when the criteria has not been executed" do
95
+
96
+ before do
97
+ Person.expects(:collection).returns(@collection)
98
+ @collection.expects(:find).with({ :title => "Sir", :_type => { "$in" => ["Doctor", "Person"] } }, {}).returns(@cursor)
99
+ end
100
+
101
+ it "executes the criteria and returns the element at the index" do
102
+ @criteria[0].should == @person
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ describe "#aggregate" do
110
+
111
+ before do
112
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
113
+ @criteria.instance_variable_set(:@context, @context)
114
+ end
115
+
116
+ it "delegates to the context" do
117
+ @context.expects(:aggregate)
118
+ @criteria.aggregate
119
+ end
120
+
121
+ end
122
+
123
+ describe "#avg" do
124
+
125
+ before do
126
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
127
+ @criteria.instance_variable_set(:@context, @context)
128
+ end
129
+
130
+ it "delegates to the context" do
131
+ @context.expects(:avg).with(:age)
132
+ @criteria.avg(:age)
133
+ end
134
+ end
135
+
136
+ describe "#blank?" do
137
+
138
+ before do
139
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
140
+ @criteria.instance_variable_set(:@context, @context)
141
+ end
142
+
143
+ context "when the context is blank" do
144
+
145
+ before do
146
+ @context.expects(:blank?).returns(true)
147
+ end
148
+
149
+ it "returns true" do
150
+ @criteria.blank?.should be_true
151
+ end
152
+ end
153
+
154
+ context "when the context is not blank" do
155
+
156
+ before do
157
+ @context.expects(:blank?).returns(false)
158
+ end
159
+
160
+ it "returns false" do
161
+ @criteria.blank?.should be_false
162
+ end
163
+ end
164
+ end
165
+
166
+ describe "#context" do
167
+
168
+ context "when the context has been set" do
169
+
170
+ before do
171
+ @context = stub
172
+ @criteria.instance_variable_set(:@context, @context)
173
+ end
174
+
175
+ it "returns the memoized context" do
176
+ @criteria.context.should == @context
177
+ end
178
+
179
+ end
180
+
181
+ context "when the context has not been set" do
182
+
183
+ before do
184
+ @context = stub
185
+ end
186
+
187
+ it "creates a new context" do
188
+ Mongoid::Contexts::Mongo.expects(:new).with(@criteria).returns(@context)
189
+ @criteria.context.should == @context
190
+ end
191
+
192
+ end
193
+
194
+ context "when the class is embedded" do
195
+
196
+ before do
197
+ @criteria = Mongoid::Criteria.new(Address)
198
+ end
199
+
200
+ it "returns an enumerable context" do
201
+ @criteria.context.should be_a_kind_of(Mongoid::Contexts::Enumerable)
202
+ end
203
+
204
+ end
205
+
206
+ context "when the class is not embedded" do
207
+
208
+ it "returns a mongo context" do
209
+ @criteria.context.should be_a_kind_of(Mongoid::Contexts::Mongo)
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ describe "#distinct" do
217
+
218
+ before do
219
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
220
+ @criteria.instance_variable_set(:@context, @context)
221
+ end
222
+
223
+ it "delegates to the context" do
224
+ @context.expects(:distinct).with(:title)
225
+ @criteria.distinct(:title)
226
+ end
227
+ end
228
+
229
+ describe "#entries" do
230
+
231
+ context "filtering" do
232
+
233
+ before do
234
+ @collection = mock
235
+ Person.expects(:collection).returns(@collection)
236
+ @criteria = Mongoid::Criteria.new(Person).extras(:page => 1, :per_page => 20)
237
+ @collection.expects(:find).with(@criteria.selector, @criteria.options).returns([])
238
+ end
239
+
240
+ it "filters out unused params" do
241
+ @criteria.entries
242
+ @criteria.options[:page].should be_nil
243
+ @criteria.options[:per_page].should be_nil
244
+ end
245
+
246
+ end
247
+
248
+ context "when type is :all" do
249
+
250
+ before do
251
+ @collection = mock
252
+ Person.expects(:collection).returns(@collection)
253
+ @criteria = Mongoid::Criteria.new(Person).extras(:page => 1, :per_page => 20)
254
+ @cursor = stub(:count => 44)
255
+ @cursor.expects(:each)
256
+ @collection.expects(:find).with(@criteria.selector, @criteria.options).returns(@cursor)
257
+ end
258
+
259
+ it "does not add the count instance variable" do
260
+ @criteria.entries.should == []
261
+ @criteria.instance_variable_get(:@count).should be_nil
262
+ end
263
+
264
+ end
265
+
266
+ context "when type is not :first" do
267
+
268
+ it "calls find on the collection with the selector and options" do
269
+ criteria = Mongoid::Criteria.new(Person)
270
+ collection = mock
271
+ Person.expects(:collection).returns(collection)
272
+ collection.expects(:find).with(criteria.selector, criteria.options).returns([])
273
+ criteria.entries.should == []
274
+ end
275
+
276
+ end
277
+
278
+ end
279
+
280
+ describe "#count" do
281
+
282
+ before do
283
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
284
+ @criteria.instance_variable_set(:@context, @context)
285
+ end
286
+
287
+ it "delegates to the context" do
288
+ @context.expects(:count).returns(10)
289
+ @criteria.count.should == 10
290
+ end
291
+
292
+ end
293
+
294
+ describe "#each" do
295
+
296
+ before do
297
+ @criteria.where(:title => "Sir")
298
+ @collection = stub
299
+ @person = Person.new(:title => "Sir")
300
+ @cursor = stub(:count => 10)
301
+ end
302
+
303
+ it "delegates to the context#iterate" do
304
+ @context = stub('context')
305
+ @criteria.stubs(:context).returns(@context)
306
+ @context.expects(:iterate)
307
+ @criteria.each
308
+ end
309
+
310
+ context "when the criteria has not been executed" do
311
+
312
+ before do
313
+ Person.expects(:collection).returns(@collection)
314
+ @collection.expects(:find).with({ :_type => { "$in" => ["Doctor", "Person"] }, :title => "Sir" }, {}).returns(@cursor)
315
+ @cursor.expects(:each).yields(@person)
316
+ end
317
+
318
+ it "executes the criteria" do
319
+ @criteria.each do |doc|
320
+ doc.should == @person
321
+ end
322
+ end
323
+
324
+ end
325
+
326
+ context "when the criteria has been executed" do
327
+
328
+ before do
329
+ Person.expects(:collection).returns(@collection)
330
+ @collection.expects(:find).with({ :_type => { "$in" => ["Doctor", "Person"] }, :title => "Sir" }, {}).returns(@cursor)
331
+ @cursor.expects(:each).yields(@person)
332
+ end
333
+
334
+ it "calls each on the existing results" do
335
+ @criteria.each do |person|
336
+ person.should == @person
337
+ end
338
+ end
339
+
340
+ end
341
+
342
+ context "when no block is passed" do
343
+
344
+ it "returns self" do
345
+ @criteria.each.should == @criteria
346
+ end
347
+
348
+ end
349
+
350
+ context "when caching" do
351
+
352
+ before do
353
+ Person.expects(:collection).returns(@collection)
354
+ @collection.expects(:find).with(
355
+ { :_type => { "$in" => ["Doctor", "Person"] },
356
+ :title => "Sir"
357
+ },
358
+ { :cache => true }
359
+ ).returns(@cursor)
360
+ @cursor.expects(:each).yields(@person)
361
+ @criteria.cache
362
+ @criteria.each do |doc|
363
+ doc.should == @person
364
+ end
365
+ end
366
+
367
+ it "caches the results of the cursor iteration" do
368
+ @criteria.each do |doc|
369
+ doc.should == @person
370
+ end
371
+ # Do it again for sanity's sake.
372
+ @criteria.each do |doc|
373
+ doc.should == @person
374
+ end
375
+ end
376
+
377
+ end
378
+
379
+ end
380
+
381
+ describe "#first" do
382
+
383
+ before do
384
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
385
+ @criteria.instance_variable_set(:@context, @context)
386
+ end
387
+
388
+ it "delegates to the context" do
389
+ @context.expects(:first).returns([])
390
+ @criteria.first.should == []
391
+ end
392
+
393
+ end
394
+
395
+ describe "#group" do
396
+
397
+ before do
398
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
399
+ @criteria.instance_variable_set(:@context, @context)
400
+ end
401
+
402
+ it "delegates to the context" do
403
+ @context.expects(:group).returns({})
404
+ @criteria.group.should == {}
405
+ end
406
+
407
+ end
408
+
409
+ describe "#initialize" do
410
+
411
+ let(:criteria) { Mongoid::Criteria.new(Person) }
412
+
413
+ it "sets the selector to an empty hash" do
414
+ criteria.selector.should == {}
415
+ end
416
+
417
+ it "sets the options to an empty hash" do
418
+ criteria.options.should == {}
419
+ end
420
+
421
+ it "sets the documents to an empty array" do
422
+ criteria.documents.should == []
423
+ end
424
+
425
+ it "sets the klass to the given class" do
426
+ criteria.klass.should == Person
427
+ end
428
+
429
+ end
430
+
431
+ describe "#last" do
432
+
433
+ before do
434
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
435
+ @criteria.instance_variable_set(:@context, @context)
436
+ end
437
+
438
+ it "delegates to the context" do
439
+ @context.expects(:last).returns([])
440
+ @criteria.last.should == []
441
+ end
442
+
443
+ end
444
+
445
+ describe "#max" do
446
+
447
+ before do
448
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
449
+ @criteria.instance_variable_set(:@context, @context)
450
+ end
451
+
452
+ it "delegates to the context" do
453
+ @context.expects(:max).with(:field).returns(100)
454
+ @criteria.max(:field).should == 100
455
+ end
456
+
457
+ end
458
+
459
+ describe "#merge" do
460
+
461
+ before do
462
+ @criteria.where(:title => "Sir", :age => 30).skip(40).limit(20)
463
+ end
464
+
465
+ context "with another criteria" do
466
+
467
+ context "when the other has a selector and options" do
468
+
469
+ before do
470
+ @other = Mongoid::Criteria.new(Person)
471
+ @other.where(:name => "Chloe").order_by([[:name, :asc]])
472
+ @selector = { :title => "Sir", :age => 30, :name => "Chloe" }
473
+ @options = { :skip => 40, :limit => 20, :sort => [[:name, :asc]] }
474
+ end
475
+
476
+ it "merges the selector and options hashes together" do
477
+ @criteria.merge(@other)
478
+ @criteria.selector.should == @selector
479
+ @criteria.options.should == @options
480
+ end
481
+
482
+ end
483
+
484
+ context "when the other has no selector or options" do
485
+
486
+ before do
487
+ @other = Mongoid::Criteria.new(Person)
488
+ @selector = { :title => "Sir", :age => 30 }
489
+ @options = { :skip => 40, :limit => 20 }
490
+ end
491
+
492
+ it "merges the selector and options hashes together" do
493
+ @criteria.merge(@other)
494
+ @criteria.selector.should == @selector
495
+ @criteria.options.should == @options
496
+ end
497
+
498
+ end
499
+
500
+ context "when the other has a document collection" do
501
+
502
+ before do
503
+ @documents = [ stub ]
504
+ @other = Mongoid::Criteria.new(Person)
505
+ @other.documents = @documents
506
+ end
507
+
508
+ it "merges the documents collection in" do
509
+ @criteria.merge(@other)
510
+ @criteria.documents.should == @documents
511
+ end
512
+
513
+ end
514
+
515
+ end
516
+
517
+ end
518
+
519
+ describe "#method_missing" do
520
+
521
+ before do
522
+ @criteria = Mongoid::Criteria.new(Person)
523
+ @criteria.where(:title => "Sir")
524
+ end
525
+
526
+ it "merges the criteria with the next one" do
527
+ @new_criteria = @criteria.accepted
528
+ @new_criteria.selector.should == { :title => "Sir", :terms => true }
529
+ end
530
+
531
+ context "chaining more than one scope" do
532
+
533
+ before do
534
+ @criteria = Person.accepted.old.knight
535
+ end
536
+
537
+ it "returns the final merged criteria" do
538
+ @criteria.selector.should == { :title => "Sir", :terms => true, :age => { "$gt" => 50 } }
539
+ end
540
+
541
+ end
542
+
543
+ context "when expecting behaviour of an array" do
544
+
545
+ before do
546
+ @array = mock
547
+ @document = mock
548
+ end
549
+
550
+ describe "#[]" do
551
+
552
+ it "collects the criteria and calls []" do
553
+ @criteria.expects(:entries).returns([@document])
554
+ @criteria[0].should == @document
555
+ end
556
+
557
+ end
558
+
559
+ describe "#rand" do
560
+
561
+ it "collects the criteria and call rand" do
562
+ @criteria.expects(:entries).returns(@array)
563
+ @array.expects(:send).with(:rand).returns(@document)
564
+ @criteria.rand
565
+ end
566
+
567
+ end
568
+
569
+ end
570
+
571
+ end
572
+
573
+ describe "#min" do
574
+
575
+ before do
576
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
577
+ @criteria.instance_variable_set(:@context, @context)
578
+ end
579
+
580
+ it "delegates to the context" do
581
+ @context.expects(:min).with(:field).returns(100)
582
+ @criteria.min(:field).should == 100
583
+ end
584
+
585
+ end
586
+
587
+ describe "#offset" do
588
+
589
+ end
590
+
591
+ describe "#one" do
592
+
593
+ before do
594
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
595
+ @criteria.instance_variable_set(:@context, @context)
596
+ end
597
+
598
+ it "delegates to the context" do
599
+ @context.expects(:one)
600
+ @criteria.one
601
+ end
602
+
603
+ end
604
+
605
+ describe "#page" do
606
+
607
+ before do
608
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
609
+ @criteria.instance_variable_set(:@context, @context)
610
+ end
611
+
612
+ it "delegates to the context" do
613
+ @context.expects(:page).returns(1)
614
+ @criteria.page.should == 1
615
+ end
616
+
617
+ end
618
+
619
+ describe "#paginate" do
620
+
621
+ before do
622
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
623
+ @criteria.instance_variable_set(:@context, @context)
624
+ end
625
+
626
+ it "delegates to the context" do
627
+ @context.expects(:paginate).returns([])
628
+ @criteria.paginate.should == []
629
+ end
630
+
631
+ end
632
+
633
+ describe "#per_page" do
634
+
635
+ before do
636
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
637
+ @criteria.instance_variable_set(:@context, @context)
638
+ end
639
+
640
+ it "delegates to the context" do
641
+ @context.expects(:per_page).returns(20)
642
+ @criteria.per_page.should == 20
643
+ end
644
+
645
+ end
646
+
647
+ describe "#scoped" do
648
+
649
+ before do
650
+ @criteria = Person.where(:title => "Sir").skip(20)
651
+ end
652
+
653
+ it "returns the selector plus the options" do
654
+ @criteria.scoped.should == { :where => { :title => "Sir" }, :skip => 20 }
655
+ end
656
+
657
+ end
658
+
659
+ describe "#sum" do
660
+
661
+ before do
662
+ @context = stub.quacks_like(Mongoid::Contexts::Mongo.allocate)
663
+ @criteria.instance_variable_set(:@context, @context)
664
+ end
665
+
666
+ it "delegates to the context" do
667
+ @context.expects(:sum).with(:field).returns(20)
668
+ @criteria.sum(:field).should == 20
669
+ end
670
+
671
+ end
672
+
673
+ describe ".translate" do
674
+
675
+ context "with a single argument" do
676
+
677
+ context "when the arg is a string" do
678
+
679
+ before do
680
+ @id = Mongo::ObjectID.new.to_s
681
+ @document = stub
682
+ @criteria = mock
683
+ Mongoid::Criteria.expects(:new).returns(@criteria)
684
+ end
685
+
686
+ it "delegates to #id_criteria" do
687
+ @criteria.expects(:id_criteria).with(@id).returns(@document)
688
+ Mongoid::Criteria.translate(Person, @id).should == @document
689
+ end
690
+ end
691
+
692
+ context "when the arg is an object id" do
693
+
694
+ before do
695
+ @id = Mongo::ObjectID.new
696
+ @document = stub
697
+ @criteria = mock
698
+ Mongoid::Criteria.expects(:new).returns(@criteria)
699
+ end
700
+
701
+ it "delegates to #id_criteria" do
702
+ @criteria.expects(:id_criteria).with(@id).returns(@document)
703
+ Mongoid::Criteria.translate(Person, @id).should == @document
704
+ end
705
+ end
706
+ end
707
+
708
+ context "multiple arguments" do
709
+
710
+ context "when an array of ids" do
711
+
712
+ before do
713
+ @ids = []
714
+ @documents = []
715
+ 3.times do
716
+ @ids << Mongo::ObjectID.new.to_s
717
+ @documents << stub
718
+ end
719
+ @criteria = mock
720
+ Mongoid::Criteria.expects(:new).returns(@criteria)
721
+ end
722
+
723
+ it "delegates to #id_criteria" do
724
+ @criteria.expects(:id_criteria).with(@ids).returns(@documents)
725
+ Mongoid::Criteria.translate(Person, @ids).should == @documents
726
+ end
727
+
728
+ end
729
+
730
+ context "when Person, :conditions => {}" do
731
+
732
+ before do
733
+ @criteria = Mongoid::Criteria.translate(Person, :conditions => { :title => "Test" })
734
+ end
735
+
736
+ it "returns a criteria with a selector from the conditions" do
737
+ @criteria.selector.should == { :title => "Test" }
738
+ end
739
+
740
+ it "returns a criteria with klass Person" do
741
+ @criteria.klass.should == Person
742
+ end
743
+
744
+ end
745
+
746
+ context "when Person, :conditions => {:id => id}" do
747
+
748
+ before do
749
+ @criteria = Mongoid::Criteria.translate(Person, :conditions => { :id => "1234e567" })
750
+ end
751
+
752
+ it "returns a criteria with a selector from the conditions" do
753
+ @criteria.selector.should == { :_id => "1234e567" }
754
+ end
755
+
756
+ it "returns a criteria with klass Person" do
757
+ @criteria.klass.should == Person
758
+ end
759
+
760
+ end
761
+
762
+ context "when :all, :conditions => {}" do
763
+
764
+ before do
765
+ @criteria = Mongoid::Criteria.translate(Person, :conditions => { :title => "Test" })
766
+ end
767
+
768
+ it "returns a criteria with a selector from the conditions" do
769
+ @criteria.selector.should == { :title => "Test" }
770
+ end
771
+
772
+ it "returns a criteria with klass Person" do
773
+ @criteria.klass.should == Person
774
+ end
775
+
776
+ end
777
+
778
+ context "when :last, :conditions => {}" do
779
+
780
+ before do
781
+ @criteria = Mongoid::Criteria.translate(Person, :conditions => { :title => "Test" })
782
+ end
783
+
784
+ it "returns a criteria with a selector from the conditions" do
785
+ @criteria.selector.should == { :title => "Test" }
786
+ end
787
+
788
+ it "returns a criteria with klass Person" do
789
+ @criteria.klass.should == Person
790
+ end
791
+ end
792
+
793
+ context "when options are provided" do
794
+
795
+ before do
796
+ @criteria = Mongoid::Criteria.translate(Person, :conditions => { :title => "Test" }, :skip => 10)
797
+ end
798
+
799
+ it "adds the criteria and the options" do
800
+ @criteria.selector.should == { :title => "Test" }
801
+ @criteria.options.should == { :skip => 10 }
802
+ end
803
+
804
+ end
805
+
806
+ end
807
+
808
+ end
809
+
810
+ context "#fuse" do
811
+
812
+ it ":where => {:title => 'Test'} returns a criteria with the correct selector" do
813
+ @result = @criteria.fuse(:where => { :title => 'Test' })
814
+ @result.selector[:title].should == 'Test'
815
+ end
816
+
817
+ it ":where => {:title => 'Test'}, :skip => 10 returns a criteria with the correct selector and options" do
818
+ @result = @criteria.fuse(:where => { :title => 'Test' }, :skip => 10)
819
+ @result.selector[:title].should == 'Test'
820
+ @result.options.should == { :skip => 10 }
821
+ end
822
+ end
823
+
824
+ end