mongo_doc 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +174 -0
  5. data/Rakefile +135 -0
  6. data/TODO +31 -0
  7. data/VERSION +1 -0
  8. data/data/.gitignore +2 -0
  9. data/examples/simple_document.rb +35 -0
  10. data/examples/simple_object.rb +30 -0
  11. data/features/finders.feature +76 -0
  12. data/features/mongodb.yml +7 -0
  13. data/features/mongodoc_base.feature +128 -0
  14. data/features/new_record.feature +36 -0
  15. data/features/partial_updates.feature +105 -0
  16. data/features/removing_documents.feature +68 -0
  17. data/features/saving_an_object.feature +15 -0
  18. data/features/scopes.feature +66 -0
  19. data/features/step_definitions/collection_steps.rb +14 -0
  20. data/features/step_definitions/document_steps.rb +149 -0
  21. data/features/step_definitions/documents.rb +30 -0
  22. data/features/step_definitions/finder_steps.rb +15 -0
  23. data/features/step_definitions/json_steps.rb +9 -0
  24. data/features/step_definitions/object_steps.rb +50 -0
  25. data/features/step_definitions/objects.rb +24 -0
  26. data/features/step_definitions/partial_update_steps.rb +32 -0
  27. data/features/step_definitions/query_steps.rb +54 -0
  28. data/features/step_definitions/removing_documents_steps.rb +14 -0
  29. data/features/step_definitions/scope_steps.rb +18 -0
  30. data/features/step_definitions/util_steps.rb +7 -0
  31. data/features/support/support.rb +10 -0
  32. data/features/using_criteria.feature +128 -0
  33. data/lib/mongo_doc/associations/collection_proxy.rb +105 -0
  34. data/lib/mongo_doc/associations/document_proxy.rb +56 -0
  35. data/lib/mongo_doc/associations/hash_proxy.rb +98 -0
  36. data/lib/mongo_doc/associations/proxy_base.rb +53 -0
  37. data/lib/mongo_doc/attributes.rb +140 -0
  38. data/lib/mongo_doc/bson.rb +45 -0
  39. data/lib/mongo_doc/collection.rb +55 -0
  40. data/lib/mongo_doc/connection.rb +88 -0
  41. data/lib/mongo_doc/contexts/enumerable.rb +128 -0
  42. data/lib/mongo_doc/contexts/ids.rb +41 -0
  43. data/lib/mongo_doc/contexts/mongo.rb +232 -0
  44. data/lib/mongo_doc/contexts.rb +25 -0
  45. data/lib/mongo_doc/criteria.rb +38 -0
  46. data/lib/mongo_doc/cursor.rb +32 -0
  47. data/lib/mongo_doc/document.rb +216 -0
  48. data/lib/mongo_doc/ext/array.rb +5 -0
  49. data/lib/mongo_doc/ext/binary.rb +7 -0
  50. data/lib/mongo_doc/ext/boolean_class.rb +11 -0
  51. data/lib/mongo_doc/ext/date.rb +16 -0
  52. data/lib/mongo_doc/ext/date_time.rb +13 -0
  53. data/lib/mongo_doc/ext/dbref.rb +7 -0
  54. data/lib/mongo_doc/ext/hash.rb +7 -0
  55. data/lib/mongo_doc/ext/nil_class.rb +5 -0
  56. data/lib/mongo_doc/ext/numeric.rb +17 -0
  57. data/lib/mongo_doc/ext/object.rb +17 -0
  58. data/lib/mongo_doc/ext/object_id.rb +7 -0
  59. data/lib/mongo_doc/ext/regexp.rb +5 -0
  60. data/lib/mongo_doc/ext/string.rb +5 -0
  61. data/lib/mongo_doc/ext/symbol.rb +5 -0
  62. data/lib/mongo_doc/ext/time.rb +5 -0
  63. data/lib/mongo_doc/finders.rb +49 -0
  64. data/lib/mongo_doc/matchers.rb +35 -0
  65. data/lib/mongo_doc/query.rb +7 -0
  66. data/lib/mongo_doc/scope.rb +64 -0
  67. data/lib/mongo_doc/validations/macros.rb +11 -0
  68. data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
  69. data/lib/mongo_doc.rb +19 -0
  70. data/lib/mongoid/contexts/paging.rb +42 -0
  71. data/lib/mongoid/criteria.rb +247 -0
  72. data/lib/mongoid/criterion/complex.rb +21 -0
  73. data/lib/mongoid/criterion/exclusion.rb +65 -0
  74. data/lib/mongoid/criterion/inclusion.rb +92 -0
  75. data/lib/mongoid/criterion/optional.rb +136 -0
  76. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  77. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  78. data/lib/mongoid/matchers/all.rb +11 -0
  79. data/lib/mongoid/matchers/default.rb +26 -0
  80. data/lib/mongoid/matchers/exists.rb +13 -0
  81. data/lib/mongoid/matchers/gt.rb +11 -0
  82. data/lib/mongoid/matchers/gte.rb +11 -0
  83. data/lib/mongoid/matchers/in.rb +11 -0
  84. data/lib/mongoid/matchers/lt.rb +11 -0
  85. data/lib/mongoid/matchers/lte.rb +11 -0
  86. data/lib/mongoid/matchers/ne.rb +11 -0
  87. data/lib/mongoid/matchers/nin.rb +11 -0
  88. data/lib/mongoid/matchers/size.rb +11 -0
  89. data/mongo_doc.gemspec +205 -0
  90. data/mongod.example.yml +2 -0
  91. data/mongodb.example.yml +14 -0
  92. data/perf/mongo_doc_runner.rb +90 -0
  93. data/perf/ruby_driver_runner.rb +64 -0
  94. data/script/console +8 -0
  95. data/spec/associations/collection_proxy_spec.rb +200 -0
  96. data/spec/associations/document_proxy_spec.rb +42 -0
  97. data/spec/associations/hash_proxy_spec.rb +163 -0
  98. data/spec/attributes_spec.rb +273 -0
  99. data/spec/bson_matchers.rb +54 -0
  100. data/spec/bson_spec.rb +196 -0
  101. data/spec/collection_spec.rb +161 -0
  102. data/spec/connection_spec.rb +147 -0
  103. data/spec/contexts/enumerable_spec.rb +274 -0
  104. data/spec/contexts/ids_spec.rb +49 -0
  105. data/spec/contexts/mongo_spec.rb +198 -0
  106. data/spec/contexts_spec.rb +28 -0
  107. data/spec/criteria_spec.rb +33 -0
  108. data/spec/cursor_spec.rb +91 -0
  109. data/spec/document_ext.rb +9 -0
  110. data/spec/document_spec.rb +664 -0
  111. data/spec/embedded_save_spec.rb +109 -0
  112. data/spec/finders_spec.rb +73 -0
  113. data/spec/hash_matchers.rb +27 -0
  114. data/spec/matchers_spec.rb +342 -0
  115. data/spec/mongodb.yml +6 -0
  116. data/spec/mongodb_pairs.yml +8 -0
  117. data/spec/new_record_spec.rb +128 -0
  118. data/spec/query_spec.rb +12 -0
  119. data/spec/scope_spec.rb +79 -0
  120. data/spec/spec.opts +2 -0
  121. data/spec/spec_helper.rb +13 -0
  122. metadata +290 -0
@@ -0,0 +1,109 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Saving embedded documents" do
4
+ class NestedDocsRoot
5
+ include MongoDoc::Document
6
+
7
+ has_many :nested_children
8
+ end
9
+
10
+ class NestedChild
11
+ include MongoDoc::Document
12
+
13
+ has_one :leaf
14
+ end
15
+
16
+ class LeafDoc
17
+ include MongoDoc::Document
18
+
19
+ key :data
20
+ end
21
+
22
+ let(:leaf) do
23
+ doc = LeafDoc.new
24
+ doc._id = 'id'
25
+ doc
26
+ end
27
+
28
+ let(:data) { 'data' }
29
+
30
+ context "#save" do
31
+ let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
32
+
33
+ it "calls the root document's save" do
34
+ root.should_receive(:save).with(true)
35
+ leaf.save
36
+ end
37
+
38
+ it "(with bang!) calls the root documents save!" do
39
+ root.should_receive(:save!)
40
+ leaf.save!
41
+ end
42
+ end
43
+
44
+ context "update_attributes naive" do
45
+ context "with no has_many, update_attributes" do
46
+ let(:root) { NestedChild.new(:leaf => leaf) }
47
+
48
+ it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
49
+ root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, false)
50
+ leaf.update_attributes(:data => data)
51
+ end
52
+
53
+ it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
54
+ root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, true)
55
+ leaf.update_attributes!(:data => data)
56
+ end
57
+ end
58
+
59
+ context "with has_many, update_attributes" do
60
+ let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
61
+
62
+ it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
63
+ root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, false)
64
+ leaf.update_attributes(:data => data)
65
+ end
66
+
67
+ it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
68
+ root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, true)
69
+ leaf.update_attributes!(:data => data)
70
+ end
71
+ end
72
+ end
73
+
74
+ context "update_attributes strict" do
75
+ let(:leaf_id) { 'leaf_id' }
76
+
77
+ before do
78
+ leaf.stub(:_id).and_return(leaf_id)
79
+ end
80
+
81
+ context "with no has_many, update_attributes" do
82
+ let(:root) { NestedChild.new(:leaf => leaf) }
83
+
84
+ it "calls the root document's _strict_update_attributes with a full attribute path and not safe" do
85
+ root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, false, 'leaf._id' => leaf_id)
86
+ leaf.update_attributes(:data => data, :__strict__ => true)
87
+ end
88
+
89
+ it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
90
+ root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, true, 'leaf._id' => leaf_id)
91
+ leaf.update_attributes!(:data => data, :__strict__ => true)
92
+ end
93
+ end
94
+
95
+ context "with has_many, update_attributes" do
96
+ let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
97
+
98
+ it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
99
+ root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, false, 'nested_children.0.leaf._id' => leaf_id)
100
+ leaf.update_attributes(:data => data, :__strict__ => true)
101
+ end
102
+
103
+ it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
104
+ root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, true, 'nested_children.0.leaf._id' => leaf_id)
105
+ leaf.update_attributes!(:data => data, :__strict__ => true)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,73 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper.rb"))
2
+
3
+ describe MongoDoc::Finders do
4
+ class FindersTest
5
+ include MongoDoc::Document
6
+
7
+ key :data
8
+ end
9
+
10
+ let(:criteria) { stub('criteria').as_null_object }
11
+
12
+ context ".find" do
13
+ before do
14
+ FindersTest.stub(:criteria).and_return(criteria)
15
+ end
16
+
17
+ it "delegates to id for the criteria" do
18
+ args = [1, 2, 3]
19
+ criteria.should_receive(:id).with(*args)
20
+ FindersTest.find(*args)
21
+ end
22
+ end
23
+
24
+ context ".find_all" do
25
+ it "delegates to an empty criteria" do
26
+ FindersTest.should_receive(:criteria)
27
+ FindersTest.find_all
28
+ end
29
+
30
+ it "returns the empty criteria" do
31
+ FindersTest.stub(:criteria).and_return(criteria)
32
+ FindersTest.find_all.should == criteria
33
+ end
34
+ end
35
+
36
+ context ".find_one" do
37
+ context "with an id" do
38
+ it "delegates to translate" do
39
+ id = 'an id'
40
+ Mongoid::Criteria.should_receive(:translate).with(FindersTest, id)
41
+ FindersTest.find_one(id)
42
+ end
43
+ end
44
+
45
+ context "with conditions" do
46
+ let(:conditions) { {:where => 'this.a > 3'} }
47
+
48
+ it "calls translate with the conditions" do
49
+ Mongoid::Criteria.should_receive(:translate).with(FindersTest, conditions).and_return(criteria)
50
+ FindersTest.find_one(conditions)
51
+ end
52
+
53
+ it "call one on the result" do
54
+ Mongoid::Criteria.stub(:translate).and_return(criteria)
55
+ criteria.should_receive(:one)
56
+ FindersTest.find_one(conditions)
57
+ end
58
+ end
59
+ end
60
+
61
+ context "all other finders" do
62
+ before do
63
+ FindersTest.stub(:criteria).and_return(criteria)
64
+ end
65
+
66
+ %w(count first last).each do |which|
67
+ it "calls #{which} on the new criteria" do
68
+ criteria.should_receive(which)
69
+ FindersTest.send(which)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,27 @@
1
+ class HasEntry
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(target)
7
+ @target = target
8
+ @expected.all? do |key, value|
9
+ @target[key] == value
10
+ end
11
+ end
12
+
13
+ def failure_message_for_should
14
+ "expected #{@target.inspect} to have entries #{@expected.inspect}"
15
+ end
16
+
17
+ def failure_message_for_should_not
18
+ "expected #{@target.inspect} not to have entries #{@expected.inspect}"
19
+ end
20
+ end
21
+
22
+ module HashMatchers
23
+ def has_entry(expected)
24
+ HasEntry.new(expected)
25
+ end
26
+ alias :has_entries :has_entry
27
+ end
@@ -0,0 +1,342 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoDoc::Matchers do
4
+
5
+ class Address
6
+ include MongoDoc::Matchers
7
+
8
+ attr_accessor :number
9
+ attr_accessor :services
10
+ attr_accessor :street
11
+
12
+ def initialize(attrs = {})
13
+ attrs.each {|key, value| send("#{key}=", value)}
14
+ end
15
+ end
16
+
17
+ describe "#matches?" do
18
+
19
+ context "when performing simple matching" do
20
+
21
+ before do
22
+ @document = Address.new(:street => "Clarkenwell Road")
23
+ end
24
+
25
+ context "when the attributes match" do
26
+
27
+ before do
28
+ @selector = { :street => "Clarkenwell Road" }
29
+ end
30
+
31
+ it "returns true" do
32
+ @document.matches?(@selector).should be_true
33
+ end
34
+
35
+ end
36
+
37
+ context "when the attributes dont match" do
38
+
39
+ before do
40
+ @selector = { :street => "Broadway Ave" }
41
+ end
42
+
43
+ it "returns false" do
44
+ @document.matches?(@selector).should be_false
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ context "when performing complex matching" do
52
+
53
+ before do
54
+ @document = Address.new(:services => ["first", "second"], :number => 100)
55
+ end
56
+
57
+ context "with an $all selector" do
58
+
59
+ context "when the attributes match" do
60
+
61
+ before do
62
+ @selector = { :services => { "$all" => [ "first", "second" ] } }
63
+ end
64
+
65
+ it "returns true" do
66
+ @document.matches?(@selector).should be_true
67
+ end
68
+
69
+ end
70
+
71
+ context "when the attributes do not match" do
72
+
73
+ before do
74
+ @selector = { :services => { "$all" => [ "first" ] } }
75
+ end
76
+
77
+ it "returns false" do
78
+ @document.matches?(@selector).should be_false
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ context "with an $exists selector" do
86
+
87
+ context "when the attributes match" do
88
+
89
+ before do
90
+ @selector = { :services => { "$exists" => true } }
91
+ end
92
+
93
+ it "returns true" do
94
+ @document.matches?(@selector).should be_true
95
+ end
96
+
97
+ end
98
+
99
+ context "when the attributes do not match" do
100
+
101
+ before do
102
+ @selector = { :services => { "$exists" => false } }
103
+ end
104
+
105
+ it "returns false" do
106
+ @document.matches?(@selector).should be_false
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ context "with a $gt selector" do
114
+
115
+ context "when the attributes match" do
116
+
117
+ before do
118
+ @selector = { :number => { "$gt" => 50 } }
119
+ end
120
+
121
+ it "returns true" do
122
+ @document.matches?(@selector).should be_true
123
+ end
124
+
125
+ end
126
+
127
+ context "when the attributes do not match" do
128
+
129
+ before do
130
+ @selector = { :number => { "$gt" => 200 } }
131
+ end
132
+
133
+ it "returns false" do
134
+ @document.matches?(@selector).should be_false
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ context "with a $gte selector" do
142
+
143
+ context "when the attributes match" do
144
+
145
+ before do
146
+ @selector = { :number => { "$gte" => 100 } }
147
+ end
148
+
149
+ it "returns true" do
150
+ @document.matches?(@selector).should be_true
151
+ end
152
+
153
+ end
154
+
155
+ context "when the attributes do not match" do
156
+
157
+ before do
158
+ @selector = { :number => { "$gte" => 200 } }
159
+ end
160
+
161
+ it "returns false" do
162
+ @document.matches?(@selector).should be_false
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ context "with an $in selector" do
170
+
171
+ context "when the attributes match" do
172
+
173
+ before do
174
+ @selector = { :number => { "$in" => [ 100, 200 ] } }
175
+ end
176
+
177
+ it "returns true" do
178
+ @document.matches?(@selector).should be_true
179
+ end
180
+
181
+ end
182
+
183
+ context "when the attributes do not match" do
184
+
185
+ before do
186
+ @selector = { :number => { "$in" => [ 200, 300 ] } }
187
+ end
188
+
189
+ it "returns false" do
190
+ @document.matches?(@selector).should be_false
191
+ end
192
+
193
+ end
194
+
195
+ end
196
+
197
+ context "with a $lt selector" do
198
+
199
+ context "when the attributes match" do
200
+
201
+ before do
202
+ @selector = { :number => { "$lt" => 200 } }
203
+ end
204
+
205
+ it "returns true" do
206
+ @document.matches?(@selector).should be_true
207
+ end
208
+
209
+ end
210
+
211
+ context "when the attributes do not match" do
212
+
213
+ before do
214
+ @selector = { :number => { "$lt" => 50 } }
215
+ end
216
+
217
+ it "returns false" do
218
+ @document.matches?(@selector).should be_false
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
225
+ context "with a $lte selector" do
226
+
227
+ context "when the attributes match" do
228
+
229
+ before do
230
+ @selector = { :number => { "$lte" => 200 } }
231
+ end
232
+
233
+ it "returns true" do
234
+ @document.matches?(@selector).should be_true
235
+ end
236
+
237
+ end
238
+
239
+ context "when the attributes do not match" do
240
+
241
+ before do
242
+ @selector = { :number => { "$lte" => 50 } }
243
+ end
244
+
245
+ it "returns false" do
246
+ @document.matches?(@selector).should be_false
247
+ end
248
+
249
+ end
250
+
251
+ end
252
+
253
+ context "with an $ne selector" do
254
+
255
+ context "when the attributes match" do
256
+
257
+ before do
258
+ @selector = { :number => { "$ne" => 200 } }
259
+ end
260
+
261
+ it "returns true" do
262
+ @document.matches?(@selector).should be_true
263
+ end
264
+
265
+ end
266
+
267
+ context "when the attributes do not match" do
268
+
269
+ before do
270
+ @selector = { :number => { "$ne" => 100 } }
271
+ end
272
+
273
+ it "returns false" do
274
+ @document.matches?(@selector).should be_false
275
+ end
276
+
277
+ end
278
+
279
+ end
280
+
281
+ context "with a $nin selector" do
282
+
283
+ context "when the attributes match" do
284
+
285
+ before do
286
+ @selector = { :number => { "$nin" => [ 1, 2, 3 ] } }
287
+ end
288
+
289
+ it "returns true" do
290
+ @document.matches?(@selector).should be_true
291
+ end
292
+
293
+ end
294
+
295
+ context "when the attributes do not match" do
296
+
297
+ before do
298
+ @selector = { :number => { "$nin" => [ 100 ] } }
299
+ end
300
+
301
+ it "returns false" do
302
+ @document.matches?(@selector).should be_false
303
+ end
304
+
305
+ end
306
+
307
+ end
308
+
309
+ context "with a $size selector" do
310
+
311
+ context "when the attributes match" do
312
+
313
+ before do
314
+ @selector = { :services => { "$size" => 2 } }
315
+ end
316
+
317
+ it "returns true" do
318
+ @document.matches?(@selector).should be_true
319
+ end
320
+
321
+ end
322
+
323
+ context "when the attributes do not match" do
324
+
325
+ before do
326
+ @selector = { :services => { "$size" => 5 } }
327
+ end
328
+
329
+ it "returns false" do
330
+ @document.matches?(@selector).should be_false
331
+ end
332
+
333
+ end
334
+
335
+ end
336
+
337
+ end
338
+
339
+ end
340
+
341
+ end
342
+
data/spec/mongodb.yml ADDED
@@ -0,0 +1,6 @@
1
+ name: database_name
2
+ host: localhost
3
+ port: 27017
4
+ options:
5
+ auto_reconnect: true
6
+
@@ -0,0 +1,8 @@
1
+ name: database_name
2
+ host_pairs:
3
+ first:
4
+ ['localhost', 27017]
5
+ port: 27017
6
+ options:
7
+ auto_reconnect: true
8
+
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "MongoDoc::Document _id and #new_record?" do
4
+ class Child
5
+ include MongoDoc::Document
6
+ end
7
+
8
+ class Parent
9
+ include MongoDoc::Document
10
+
11
+ has_one :child
12
+ has_many :children
13
+
14
+ key :data
15
+
16
+ validates_presence_of :data
17
+ end
18
+
19
+ let(:id) { 'id' }
20
+ let(:collection) { stub('collection', :save => id) }
21
+ let(:child) { Child.new }
22
+
23
+ context "as a has_one child" do
24
+ it "when added to the parent is a new record" do
25
+ Parent.new(:data => 'data', :child => child)
26
+ child.should be_new_record
27
+ end
28
+
29
+ context "saving" do
30
+ before do
31
+ Parent.stub(:collection).and_return(collection)
32
+ end
33
+
34
+ context "#save" do
35
+ it "when saved is not a new record" do
36
+ parent = Parent.new(:data => 'data', :child => child)
37
+ parent.save
38
+ child.should_not be_new_record
39
+ end
40
+
41
+ it "if parent is invalid, remains a new record" do
42
+ parent = Parent.new(:child => child)
43
+ parent.save
44
+ child.should be_new_record
45
+ end
46
+ end
47
+
48
+ context "#save!" do
49
+ it "when saved is not a new record" do
50
+ parent = Parent.new(:data => 'data', :child => child)
51
+ parent.save!
52
+ child.should_not be_new_record
53
+ end
54
+
55
+ it "if parent is invalid, remains a new record" do
56
+ parent = Parent.new(:child => child)
57
+ parent.save! rescue nil
58
+ child.should be_new_record
59
+ end
60
+
61
+ it "when db error is raised, remains a new record" do
62
+ collection.stub(:save).and_raise(Mongo::OperationFailure)
63
+ parent = Parent.new(:data => 'data', :child => child)
64
+ expect do
65
+ parent.save!
66
+ end.should raise_error(Mongo::OperationFailure)
67
+ child.should be_new_record
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ context "as a has_many child" do
74
+ it "when added to the parent is a new record" do
75
+ parent = Parent.new(:data => 'data')
76
+ parent.children << child
77
+ child.should be_new_record
78
+ end
79
+
80
+ context "saving" do
81
+ before do
82
+ Parent.stub(:collection).and_return(collection)
83
+ end
84
+
85
+ context "#save" do
86
+ it "when saved is not a new record" do
87
+ parent = Parent.new(:data => 'data')
88
+ parent.children << child
89
+ parent.save
90
+ child.should_not be_new_record
91
+ end
92
+
93
+ it "if parent is invalid, remains a new record" do
94
+ parent = Parent.new
95
+ parent.children << child
96
+ parent.save
97
+ child.should be_new_record
98
+ end
99
+ end
100
+
101
+ context "#save!" do
102
+ it "when saved is not a new record" do
103
+ parent = Parent.new(:data => 'data')
104
+ parent.children << child
105
+ parent.save!
106
+ child.should_not be_new_record
107
+ end
108
+
109
+ it "if parent is invalid, remains a new record" do
110
+ parent = Parent.new
111
+ parent.children << child
112
+ parent.save! rescue nil
113
+ child.should be_new_record
114
+ end
115
+
116
+ it "when db error is raised, remains a new record" do
117
+ collection.stub(:save).and_raise(Mongo::OperationFailure)
118
+ parent = Parent.new(:data => 'data')
119
+ parent.children << child
120
+ expect do
121
+ parent.save!
122
+ end.should raise_error(Mongo::OperationFailure)
123
+ child.should be_new_record
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Query support for MongoDoc" do
4
+ describe "#set_modifier" do
5
+ it "modifies all simple key/values of the hash to a set modifier" do
6
+ key = 'key'
7
+ value = 'value'
8
+ hash = {key => value}
9
+ MongoDoc::Query.set_modifier(hash).should == {'$set' => hash}
10
+ end
11
+ end
12
+ end