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,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts::Enumerable do
4
+
5
+ before do
6
+ @person = Person.new(:title => "Sir")
7
+ 10.times do |n|
8
+ @person.addresses << Address.new(:number => n, :street => "Upper Street")
9
+ end
10
+ end
11
+
12
+ describe "#paginate" do
13
+
14
+ it "paginates the embedded documents" do
15
+ addresses = @person.addresses.paginate(:page => nil, :per_page => 5)
16
+ addresses.current_page.should == 1
17
+ addresses.size.should == 5
18
+ end
19
+ end
20
+
21
+ describe "limit and skip" do
22
+
23
+ it "limits" do
24
+ @person.addresses.criteria.limit(5).size.should == 5
25
+ end
26
+
27
+ it "skips" do
28
+ @person.addresses.criteria.skip(5).limit(10).
29
+ map(&:number).should == [5, 6, 7, 8, 9]
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,272 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Criteria do
4
+
5
+ before do
6
+ Person.delete_all
7
+ end
8
+
9
+ after do
10
+ Person.delete_all
11
+ end
12
+
13
+ describe "#avg" do
14
+
15
+ context "without results" do
16
+ it "should return nil" do
17
+ Person.avg(:age).should == nil
18
+ end
19
+ end
20
+
21
+ context "with results" do
22
+ before do
23
+ 10.times do |n|
24
+ Person.create(:title => "Sir", :age => ((n + 1) * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
25
+ end
26
+ end
27
+
28
+ it "provides min for the field provided" do
29
+ Person.avg(:age).should == 55
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#excludes" do
35
+
36
+ before do
37
+ @person = Person.create(:title => "Sir", :age => 100, :aliases => ["D", "Durran"], :ssn => "666666666")
38
+ end
39
+
40
+ context "when passed id" do
41
+
42
+ it "it properly excludes ids" do
43
+ Person.criteria.excludes(:id => @person.id).entries.should be_empty
44
+ end
45
+
46
+ end
47
+
48
+ context "when passed _id" do
49
+
50
+ it "it properly excludes ids" do
51
+ Person.criteria.excludes(:_id => @person.id).entries.should be_empty
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ describe "#execute" do
59
+
60
+ context "when reiterating" do
61
+
62
+ before do
63
+ @person = Person.create(:title => "Sir", :age => 100, :aliases => ["D", "Durran"], :ssn => "666666666")
64
+ end
65
+
66
+ it "executes the query again" do
67
+ criteria = Person.all
68
+ criteria.size.should == 1
69
+ criteria.should_not be_empty
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#in" do
75
+
76
+ context "when searching nil values" do
77
+
78
+ before do
79
+ @person = Person.create(:title => nil)
80
+ end
81
+
82
+ it "returns the correct document" do
83
+ from_db = Person.any_in(:title => [ true, false, nil ]).first
84
+ from_db.should == @person
85
+ end
86
+ end
87
+
88
+ context "when searching false values" do
89
+
90
+ before do
91
+ @person = Person.create(:terms => false)
92
+ end
93
+
94
+ it "returns the correct document" do
95
+ from_db = Person.criteria.in(:terms => [ true, false, nil ]).first
96
+ from_db.should == @person
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#max" do
102
+
103
+ context "without results" do
104
+ it "should return nil" do
105
+ Person.max(:age).should == nil
106
+ end
107
+ end
108
+
109
+ context "with results" do
110
+ before do
111
+ 10.times do |n|
112
+ Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
113
+ end
114
+ end
115
+
116
+ it "provides max for the field provided" do
117
+ Person.max(:age).should == 90.0
118
+ end
119
+ end
120
+ end
121
+
122
+ describe "#min" do
123
+
124
+ context "without results" do
125
+ it "should return nil" do
126
+ Person.min(:age).should == nil
127
+ end
128
+ end
129
+
130
+ context "with results" do
131
+ before do
132
+ 10.times do |n|
133
+ Person.create(:title => "Sir", :age => ((n + 1) * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
134
+ end
135
+ end
136
+
137
+ it "provides min for the field provided" do
138
+ Person.min(:age).should == 10.0
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "#sum" do
144
+
145
+ context "without results" do
146
+ it "should return nil" do
147
+ Person.sum(:age).should == nil
148
+ end
149
+ end
150
+
151
+ context "with results" do
152
+ before do
153
+ 10.times do |n|
154
+ Person.create(:title => "Sir", :age => 5, :aliases => ["D", "Durran"], :ssn => "#{n}")
155
+ end
156
+ end
157
+
158
+ it "provides sum for the field provided" do
159
+ Person.where(:age.gt => 3).sum(:age).should == 50.0
160
+ end
161
+ end
162
+ end
163
+
164
+ describe "#where" do
165
+
166
+ before do
167
+ @person = Person.create(:title => "Sir", :age => 33, :aliases => ["D", "Durran"])
168
+ end
169
+
170
+ context "with complex criterion" do
171
+
172
+ context "#all" do
173
+
174
+ it "returns those matching an all clause" do
175
+ Person.criteria.where(:title.all => ["Sir"]).should == [@person]
176
+ end
177
+
178
+ end
179
+
180
+ context "#exists" do
181
+
182
+ it "returns those matching an exists clause" do
183
+ Person.criteria.where(:title.exists => true).should == [@person]
184
+ end
185
+
186
+ end
187
+
188
+ context "#gt" do
189
+
190
+ it "returns those matching a gt clause" do
191
+ Person.criteria.where(:age.gt => 30).should == [@person]
192
+ end
193
+
194
+ end
195
+
196
+ context "#gte" do
197
+
198
+ it "returns those matching a gte clause" do
199
+ Person.criteria.where(:age.gte => 33).should == [@person]
200
+ end
201
+
202
+ end
203
+
204
+ context "#in" do
205
+
206
+ it "returns those matching an in clause" do
207
+ Person.criteria.where(:title.in => ["Sir", "Madam"]).should == [@person]
208
+ end
209
+
210
+ end
211
+
212
+ context "#lt" do
213
+
214
+ it "returns those matching a lt clause" do
215
+ Person.criteria.where(:age.lt => 34).should == [@person]
216
+ end
217
+
218
+ end
219
+
220
+ context "#lte" do
221
+
222
+ it "returns those matching a lte clause" do
223
+ Person.criteria.where(:age.lte => 33).should == [@person]
224
+ end
225
+
226
+ end
227
+
228
+ context "#ne" do
229
+
230
+ it "returns those matching a ne clause" do
231
+ Person.criteria.where(:age.ne => 50).should == [@person]
232
+ end
233
+
234
+ end
235
+
236
+ context "#nin" do
237
+
238
+ it "returns those matching a nin clause" do
239
+ Person.criteria.where(:title.nin => ["Esquire", "Congressman"]).should == [@person]
240
+ end
241
+
242
+ end
243
+
244
+ context "#size" do
245
+
246
+ it "returns those matching a size clause" do
247
+ Person.criteria.where(:aliases.size => 2).should == [@person]
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ end
255
+
256
+ context "when caching" do
257
+
258
+ before do
259
+ 10.times do |n|
260
+ Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
261
+ end
262
+ end
263
+
264
+ it "iterates over the cursor only once" do
265
+ criteria = Person.where(:title => "Sir").cache
266
+ criteria.collect.to_a.size.should == 10
267
+ # Do it again!
268
+ criteria.collect.to_a.size.should == 10
269
+ end
270
+ end
271
+
272
+ end
@@ -0,0 +1,650 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Document do
4
+
5
+ before do
6
+ Person.delete_all
7
+ end
8
+
9
+ describe "#db" do
10
+
11
+ it "returns the mongo database" do
12
+ Person.db.should == Mongoid.master
13
+ end
14
+ end
15
+
16
+ context "when document contains a hash field" do
17
+
18
+ before do
19
+ @map = { "first" => 10, "second" => "Blah" }
20
+ @person = Person.create(:map => @map)
21
+ end
22
+
23
+ it "properly gets and sets the has attributes" do
24
+ @person.map.should == @map
25
+ @from_db = Person.find(@person.id)
26
+ @from_db.map.should == @map
27
+ end
28
+
29
+ end
30
+
31
+ describe ".collection" do
32
+
33
+ context "on a subclass of a root document" do
34
+
35
+ it "returns the root document collection" do
36
+ Browser.collection.should == Canvas.collection
37
+ end
38
+
39
+ end
40
+
41
+ context "on a namespaced document" do
42
+ Medical::Patient.collection.name.should == "medical_patients"
43
+ end
44
+
45
+ end
46
+
47
+ describe "#new" do
48
+
49
+ it "gets a new or current database connection" do
50
+ person = Person.new
51
+ person.collection.should be_a_kind_of(Mongoid::Collection)
52
+ end
53
+
54
+ end
55
+
56
+ describe "#count" do
57
+
58
+ before do
59
+ 5.times do |n|
60
+ Person.create(:title => "Sir", :ssn => "#{n}")
61
+ end
62
+ end
63
+
64
+ it "returns the count" do
65
+ Person.count.should == 5
66
+ end
67
+
68
+ end
69
+
70
+ describe "#create" do
71
+
72
+ it "persists a new record to the database" do
73
+ person = Person.create(:title => "Test")
74
+ person.id.should be_a_kind_of(String)
75
+ person.attributes[:title].should == "Test"
76
+ end
77
+
78
+ context "when creating a has many" do
79
+
80
+ before do
81
+ @person = Person.new(:title => "Esquire")
82
+ @person.addresses.create(:street => "Nan Jing Dong Lu", :city => "Shanghai")
83
+ end
84
+
85
+ it "should create and save the entire graph" do
86
+ person = Person.find(@person.id)
87
+ person.addresses.first.street.should == "Nan Jing Dong Lu"
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ context "chaining criteria scopes" do
95
+
96
+ before do
97
+ @one = Person.create(:title => "Mr", :age => 55, :terms => true, :ssn => "q")
98
+ @two = Person.create(:title => "Sir", :age => 55, :terms => true, :ssn => "w")
99
+ @three = Person.create(:title => "Sir", :age => 35, :terms => true, :ssn => "e")
100
+ @four = Person.create(:title => "Sir", :age => 55, :terms => false, :ssn => "r")
101
+ end
102
+
103
+ it "finds by the merged criteria" do
104
+ people = Person.old.accepted.knight
105
+ people.count.should == 1
106
+ people.first.should == @two
107
+ end
108
+
109
+ end
110
+
111
+ context "#destroy" do
112
+
113
+ context "on a root document" do
114
+
115
+ before do
116
+ @person = Person.create(:title => "Sir")
117
+ end
118
+
119
+ it "deletes the document" do
120
+ @person.destroy
121
+ lambda { Person.find(@person.id) }.should raise_error
122
+ end
123
+
124
+ it "marks the document as destroyed" do
125
+ @person.should_not be_destroyed
126
+ @person.destroy
127
+ @person.should be_destroyed
128
+ end
129
+
130
+ end
131
+
132
+ context "on an embedded document" do
133
+
134
+ before do
135
+ @person = Person.create(:title => "Lead")
136
+ address = @person.addresses.create(:street => "1st Street")
137
+ @person.create_name(:first_name => "Emmanuel")
138
+ @person.save
139
+ end
140
+
141
+ it "deletes the document" do
142
+ @person.addresses.first.destroy
143
+ @person.name.should_not be_nil
144
+ @person.name.destroy
145
+ @person.addresses.first.should be_nil
146
+ @person.name.should be_nil
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+
153
+ context ".find_or_create_by" do
154
+
155
+ before do
156
+ @person = Person.create(:title => "Senior")
157
+ end
158
+
159
+ context "when the document is found" do
160
+
161
+ it "returns the document" do
162
+ Person.find_or_create_by(:title => "Senior").should == @person
163
+ end
164
+
165
+ end
166
+
167
+ context "when the document is not found" do
168
+
169
+ it "creates a new document" do
170
+ person = Person.find_or_create_by(:title => "Senorita", :ssn => "1234567")
171
+ person.title.should == "Senorita"
172
+ person.should_not be_a_new_record
173
+ end
174
+
175
+ end
176
+
177
+ end
178
+
179
+ context ".find_or_initialize_by" do
180
+
181
+ before do
182
+ @person = Person.create(:title => "Senior")
183
+ end
184
+
185
+ context "when the document is found" do
186
+
187
+ it "returns the document" do
188
+ Person.find_or_initialize_by(:title => "Senior").should == @person
189
+ end
190
+
191
+ end
192
+
193
+ context "when the document is not found" do
194
+
195
+ it "returns a new document" do
196
+ person = Person.find_or_initialize_by(:title => "Senorita")
197
+ person.title.should == "Senorita"
198
+ person.should be_a_new_record
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+
205
+ describe "#find" do
206
+
207
+ before do
208
+ @person = Person.create(:title => "Test")
209
+ end
210
+
211
+ context "finding all documents" do
212
+
213
+ it "returns an array of documents based on the selector provided" do
214
+ documents = Person.find(:all, :conditions => { :title => "Test"})
215
+ documents.first.title.should == "Test"
216
+ end
217
+
218
+ end
219
+
220
+ context "finding first document" do
221
+
222
+ it "returns the first document based on the selector provided" do
223
+ person = Person.find(:first, :conditions => { :title => "Test" })
224
+ person.title.should == "Test"
225
+ end
226
+
227
+ end
228
+
229
+ context "finding by id" do
230
+
231
+ it "finds the document by the supplied id" do
232
+ person = Person.find(@person.id)
233
+ person.id.should == @person.id
234
+ end
235
+
236
+ end
237
+
238
+ context "limiting result fields" do
239
+
240
+ it "adds the type field to the options" do
241
+ people = Person.all(:fields => [ :title ])
242
+ people.first.title.should == "Test"
243
+ end
244
+
245
+ end
246
+
247
+ end
248
+
249
+ describe "#group" do
250
+
251
+ before do
252
+ 5.times do |num|
253
+ Person.create(:title => "Sir", :age => num, :ssn => num)
254
+ end
255
+ end
256
+
257
+ it "returns grouped documents" do
258
+ grouped = Person.only(:title).group
259
+ people = grouped.first["group"]
260
+ person = people.first
261
+ person.should be_a_kind_of(Person)
262
+ person.title.should == "Sir"
263
+ end
264
+
265
+ end
266
+
267
+ context "when address is a has one" do
268
+
269
+ before do
270
+ @owner = PetOwner.create(:title => "AKC")
271
+ @address = Address.new(:street => "Fido Street")
272
+ @owner.address = @address
273
+ @owner.save
274
+ end
275
+
276
+ after do
277
+ PetOwner.delete_all
278
+ end
279
+
280
+ it "is a single object and not an array" do
281
+ @from_db = PetOwner.find(@owner.id)
282
+ @from_db.address.should == @address
283
+ end
284
+
285
+ end
286
+
287
+ describe "#inspect" do
288
+
289
+ before do
290
+ @person = Person.new
291
+ end
292
+
293
+ it "returns a pretty string of class name and attributes" do
294
+ attrs = Person.fields.map { |name, field| "#{name}: #{@person.attributes[name].nil? ? 'nil' : @person.attributes[name]}" } * ", "
295
+ @person.inspect.should == "#<Person _id: #{@person.id}, #{attrs}>"
296
+ end
297
+
298
+ end
299
+
300
+ describe "#paginate" do
301
+
302
+ before do
303
+ 10.times do |num|
304
+ Person.create(:title => "Test-#{num}", :ssn => "55#{num}")
305
+ end
306
+ end
307
+
308
+ it "returns paginated documents" do
309
+ Person.paginate(:per_page => 5, :page => 2).length.should == 5
310
+ end
311
+
312
+ it "returns a proper count" do
313
+ @criteria = Mongoid::Criteria.translate(Person, { :per_page => 5, :page => 1 })
314
+ @criteria.count.should == 10
315
+ end
316
+
317
+ end
318
+
319
+ describe "#reload" do
320
+
321
+ before do
322
+ @person = Person.new(:title => "Sir")
323
+ @person.save
324
+ @from_db = Person.find(@person.id)
325
+ @from_db.age = 35
326
+ @from_db.save
327
+ end
328
+
329
+ it "reloads the obejct attributes from the db" do
330
+ @person.reload
331
+ @person.age.should == 35
332
+ end
333
+
334
+ it "reload should return self" do
335
+ @person.reload.should == @from_db
336
+ end
337
+
338
+ end
339
+
340
+ describe "#save" do
341
+
342
+ context "on a has_one association" do
343
+
344
+ before do
345
+ @person = Person.new(:title => "Sir")
346
+ @name = Name.new(:first_name => "Test")
347
+ @person.name = @name
348
+ end
349
+
350
+ it "saves the parent document" do
351
+ @name.save
352
+ person = Person.find(@person.id)
353
+ person.name.first_name.should == @name.first_name
354
+ end
355
+
356
+ end
357
+
358
+ context "without validation" do
359
+
360
+ before do
361
+ @comment = Comment.new
362
+ end
363
+
364
+ it "always persists" do
365
+ @comment.save(false).should be_true
366
+ @from_db = Comment.find(@comment.id)
367
+ @from_db.should == @comment
368
+ end
369
+
370
+ end
371
+
372
+ context "with failing validation" do
373
+
374
+ before do
375
+ @comment = Comment.new
376
+ end
377
+
378
+ it "returns false" do
379
+ @comment.should_not be_valid
380
+ end
381
+
382
+ end
383
+
384
+ end
385
+
386
+ context ".store_in" do
387
+
388
+ after do
389
+ Canvas.store_in(:canvases)
390
+ end
391
+
392
+ it "switches the database collection" do
393
+ Canvas.collection.name.should == "canvases"
394
+ Canvas.store_in(:browsers)
395
+ Canvas.collection.name.should == "browsers"
396
+ end
397
+
398
+ end
399
+
400
+ context "when has many exists through a has one" do
401
+
402
+ before do
403
+ @owner = PetOwner.new(:title => "Sir")
404
+ @pet = Pet.new(:name => "Fido")
405
+ @visit = VetVisit.new(:date => Date.today)
406
+ @pet.vet_visits << @visit
407
+ @owner.pet = @pet
408
+ end
409
+
410
+ it "can clear the association" do
411
+ @owner.pet.vet_visits.size.should == 1
412
+ @owner.pet.vet_visits.clear
413
+ @owner.pet.vet_visits.size.should == 0
414
+ end
415
+
416
+ end
417
+
418
+ context "the lot" do
419
+
420
+ before do
421
+ @person = Person.new(:title => "Sir")
422
+ @name = Name.new(:first_name => "Syd", :last_name => "Vicious")
423
+ @home = Address.new(:street => "Oxford Street")
424
+ @business = Address.new(:street => "Upper Street")
425
+ @person.name = @name
426
+ @person.addresses << @home
427
+ @person.addresses << @business
428
+ end
429
+
430
+ it "allows adding multiples on an embed_many in a row" do
431
+ @person.addresses.length.should == 2
432
+ end
433
+
434
+ context "when saving on a has_one" do
435
+
436
+ before do
437
+ @name.save
438
+ end
439
+
440
+ it "saves the entire graph up from the has_one" do
441
+ person = Person.first(:conditions => { :title => "Sir" })
442
+ person.should == @person
443
+ end
444
+
445
+ end
446
+
447
+ context "when saving on an embed_many" do
448
+
449
+ before do
450
+ @home.save
451
+ end
452
+
453
+ it "saves the entire graph up from the embed_many" do
454
+ person = Person.first(:conditions => { :title => "Sir" })
455
+ person.should == @person
456
+ end
457
+ end
458
+
459
+ end
460
+
461
+ context "setting belongs_to" do
462
+
463
+ before do
464
+ @person = Person.new(:title => "Mr")
465
+ @address = Address.new(:street => "Bloomsbury Ave")
466
+ @person.save!
467
+ end
468
+
469
+ it "allows the parent reference to change" do
470
+ @address.addressable = @person
471
+ @address.save!
472
+ @person.addresses.first.should == @address
473
+ end
474
+
475
+ end
476
+
477
+ describe "#to_json" do
478
+
479
+ before do
480
+ @person = Person.new(:title => "Sir", :age => 30)
481
+ @address = Address.new(:street => "Nan Jing Dong Lu")
482
+ @person.addresses << @address
483
+ end
484
+
485
+ context "on a new document" do
486
+
487
+ it "returns the json string" do
488
+ @person.to_json.should == @person.attributes.to_json
489
+ end
490
+
491
+ end
492
+
493
+ context "on a persisted document" do
494
+
495
+ it "returns the json string" do
496
+ @person.save
497
+ from_db = Person.find(@person.id)
498
+ from_db.to_json.should == from_db.attributes.to_json
499
+ end
500
+
501
+ end
502
+
503
+ end
504
+
505
+ describe "#as_json" do
506
+
507
+ before do
508
+ @person = Person.new(:title => "Sir", :age => 30)
509
+ @address = Address.new(:street => "Nan Jing Dong Lu")
510
+ @person.addresses << @address
511
+ end
512
+
513
+ context "on a new document" do
514
+
515
+ it "returns the attributes" do
516
+ @person.as_json.should == @person.attributes
517
+ end
518
+
519
+ end
520
+
521
+ context "on a persisted document" do
522
+
523
+ it "returns the attributes" do
524
+ @person.save
525
+ from_db = Person.find(@person.id)
526
+ from_db.as_json.should == from_db.attributes
527
+ end
528
+
529
+ end
530
+
531
+ end
532
+
533
+ describe "#encode_json" do
534
+
535
+ before do
536
+ @person = Person.new(:title => "Sir", :age => 30)
537
+ @address = Address.new(:street => "Nan Jing Dong Lu")
538
+ @person.addresses << @address
539
+ @encoder = Array.new
540
+ end
541
+
542
+ context "on a new document" do
543
+
544
+ it "returns the attributes" do
545
+ @person.encode_json(@encoder).should == @person.attributes
546
+ end
547
+
548
+ end
549
+
550
+ context "on a persisted document" do
551
+
552
+ it "returns the attributes" do
553
+ @person.save
554
+ from_db = Person.find(@person.id)
555
+ from_db.encode_json(@encoder).should == from_db.attributes
556
+ end
557
+
558
+ end
559
+
560
+ end
561
+
562
+ context "typecasting" do
563
+
564
+ before do
565
+ @date = Date.new(1976, 7, 4)
566
+ @person = Person.new(:dob => @date)
567
+ @person.save
568
+ end
569
+
570
+ it "properly casts dates and times" do
571
+ person = Person.first
572
+ person.dob.should == @date
573
+ end
574
+
575
+ end
576
+
577
+ context "versioning" do
578
+
579
+ before do
580
+ @comment = Comment.new(:text => "Testing")
581
+ @comment.save
582
+ end
583
+
584
+ after do
585
+ Comment.collection.drop
586
+ end
587
+
588
+ context "first save" do
589
+
590
+ it "creates a new version" do
591
+ @from_db = Comment.find(@comment.id)
592
+ @from_db.text = "New"
593
+ @from_db.save
594
+ @from_db.versions.size.should == 1
595
+ @from_db.version.should == 2
596
+ end
597
+
598
+ end
599
+
600
+ context "multiple saves" do
601
+
602
+ before do
603
+ 5.times do |n|
604
+ @comment.save
605
+ end
606
+ end
607
+
608
+ it "creates new versions" do
609
+ @from_db = Comment.find(@comment.id)
610
+ @from_db.version.should == 6
611
+ @from_db.versions.size.should == 5
612
+ end
613
+
614
+ end
615
+
616
+ end
617
+
618
+ context "executing criteria with date comparisons" do
619
+
620
+ context "handling specific dates" do
621
+
622
+ before do
623
+ @person = Person.create(:dob => Date.new(2000, 10, 31))
624
+ end
625
+
626
+ it "handles comparisons with todays date"do
627
+ people = Person.where("this.dob < new Date()")
628
+ people.first.should == @person
629
+ end
630
+
631
+ it "handles conparisons with a date range" do
632
+ people = Person.where("new Date(1976, 10, 31) < this.dob && this.dob < new Date()")
633
+ people.first.should == @person
634
+ end
635
+
636
+ it "handles false comparisons in a date range" do
637
+ people = Person.where("new Date(2005, 10, 31) < this.dob && this.dob < new Date()")
638
+ people.should be_empty
639
+ end
640
+
641
+ it "handles comparisons with date objects"do
642
+ people = Person.where(:dob => { "$lt" => Date.today.midnight })
643
+ people.first.should == @person
644
+ end
645
+
646
+ end
647
+
648
+ end
649
+
650
+ end