ign-mongo_mapper 0.8.6.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +7 -0
  4. data/bin/mmconsole +60 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +8 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +41 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +83 -0
  19. data/lib/mongo_mapper/connection.rb +83 -0
  20. data/lib/mongo_mapper/document.rb +41 -0
  21. data/lib/mongo_mapper/embedded_document.rb +31 -0
  22. data/lib/mongo_mapper/exceptions.rb +27 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +27 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +29 -0
  37. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  38. data/lib/mongo_mapper/plugins.rb +15 -0
  39. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  40. data/lib/mongo_mapper/plugins/associations.rb +134 -0
  41. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  42. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  43. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  44. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  45. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  46. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +151 -0
  47. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  48. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +109 -0
  49. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  50. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  51. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  52. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
  53. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  54. data/lib/mongo_mapper/plugins/associations/proxy.rb +139 -0
  55. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  56. data/lib/mongo_mapper/plugins/callbacks.rb +243 -0
  57. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  58. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  59. data/lib/mongo_mapper/plugins/dirty.rb +124 -0
  60. data/lib/mongo_mapper/plugins/document.rb +41 -0
  61. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  62. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  63. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  64. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  65. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  66. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  67. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  68. data/lib/mongo_mapper/plugins/keys.rb +311 -0
  69. data/lib/mongo_mapper/plugins/keys/key.rb +65 -0
  70. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  71. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  72. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  73. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  74. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  75. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  76. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  77. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  78. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  79. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  80. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  81. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  82. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  83. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  84. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  85. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  86. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  87. data/lib/mongo_mapper/version.rb +4 -0
  88. data/rails/init.rb +15 -0
  89. data/test/_NOTE_ON_TESTING +1 -0
  90. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  91. data/test/functional/associations/test_belongs_to_proxy.rb +117 -0
  92. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  93. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  94. data/test/functional/associations/test_many_documents_proxy.rb +615 -0
  95. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  96. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  97. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  98. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  99. data/test/functional/associations/test_one_proxy.rb +206 -0
  100. data/test/functional/test_accessible.rb +168 -0
  101. data/test/functional/test_associations.rb +46 -0
  102. data/test/functional/test_binary.rb +27 -0
  103. data/test/functional/test_caching.rb +76 -0
  104. data/test/functional/test_callbacks.rb +151 -0
  105. data/test/functional/test_dirty.rb +163 -0
  106. data/test/functional/test_document.rb +272 -0
  107. data/test/functional/test_dynamic_querying.rb +75 -0
  108. data/test/functional/test_embedded_document.rb +210 -0
  109. data/test/functional/test_identity_map.rb +513 -0
  110. data/test/functional/test_indexes.rb +42 -0
  111. data/test/functional/test_logger.rb +20 -0
  112. data/test/functional/test_modifiers.rb +416 -0
  113. data/test/functional/test_pagination.rb +91 -0
  114. data/test/functional/test_protected.rb +175 -0
  115. data/test/functional/test_querying.rb +873 -0
  116. data/test/functional/test_safe.rb +76 -0
  117. data/test/functional/test_sci.rb +230 -0
  118. data/test/functional/test_scopes.rb +171 -0
  119. data/test/functional/test_string_id_compatibility.rb +67 -0
  120. data/test/functional/test_timestamps.rb +62 -0
  121. data/test/functional/test_userstamps.rb +27 -0
  122. data/test/functional/test_validations.rb +342 -0
  123. data/test/models.rb +233 -0
  124. data/test/test_active_model_lint.rb +13 -0
  125. data/test/test_helper.rb +102 -0
  126. data/test/unit/associations/test_base.rb +212 -0
  127. data/test/unit/associations/test_proxy.rb +105 -0
  128. data/test/unit/serializers/test_json_serializer.rb +217 -0
  129. data/test/unit/test_clone.rb +69 -0
  130. data/test/unit/test_descendant_appends.rb +71 -0
  131. data/test/unit/test_document.rb +208 -0
  132. data/test/unit/test_dynamic_finder.rb +125 -0
  133. data/test/unit/test_embedded_document.rb +639 -0
  134. data/test/unit/test_extensions.rb +376 -0
  135. data/test/unit/test_identity_map_middleware.rb +34 -0
  136. data/test/unit/test_inspect.rb +22 -0
  137. data/test/unit/test_key.rb +205 -0
  138. data/test/unit/test_keys.rb +89 -0
  139. data/test/unit/test_mongo_mapper.rb +110 -0
  140. data/test/unit/test_pagination.rb +11 -0
  141. data/test/unit/test_plugins.rb +50 -0
  142. data/test/unit/test_rails.rb +181 -0
  143. data/test/unit/test_rails_compatibility.rb +52 -0
  144. data/test/unit/test_serialization.rb +51 -0
  145. data/test/unit/test_time_zones.rb +39 -0
  146. data/test/unit/test_validations.rb +564 -0
  147. metadata +385 -0
@@ -0,0 +1,272 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DocumentTest < Test::Unit::TestCase
5
+ def setup
6
+ @document = Doc do
7
+ key :first_name, String
8
+ key :last_name, String
9
+ key :age, Integer
10
+ key :date, Date
11
+ end
12
+ end
13
+
14
+ context "array key" do
15
+ setup do
16
+ @document.key :tags, Array
17
+ end
18
+
19
+ should "give correct default" do
20
+ doc = @document.new
21
+ doc.tags.should == []
22
+ end
23
+
24
+ should "work with assignment" do
25
+ doc = @document.new
26
+ doc.tags = %w(foo bar)
27
+ doc.tags.should == %w(foo bar)
28
+ end
29
+
30
+ should "work with assignment after saving" do
31
+ doc = @document.new
32
+ doc.tags = %w(foo bar)
33
+ doc.save
34
+ doc.tags.should == %w(foo bar)
35
+ doc.reload.tags.should == %w(foo bar)
36
+ end
37
+
38
+ should "work with assignment then <<" do
39
+ doc = @document.new
40
+ doc.tags = []
41
+ doc.tags << "foo"
42
+ doc.tags.should == ["foo"]
43
+ end
44
+
45
+ should "work with <<" do
46
+ doc = @document.new
47
+ doc.tags << "foo"
48
+ doc.tags.should == ["foo"]
49
+ end
50
+
51
+ should "work with << then save" do
52
+ doc = @document.new
53
+ doc.tags << "foo"
54
+ doc.tags << "bar"
55
+ doc.save
56
+ doc.tags.should == %w(foo bar)
57
+ doc.reload.tags.should == %w(foo bar)
58
+ end
59
+ end
60
+
61
+ context "hash key" do
62
+ setup do
63
+ @document.key :foo, Hash
64
+ end
65
+
66
+ should "give correct default" do
67
+ doc = @document.new
68
+ doc.foo.should == {}
69
+ end
70
+
71
+ should "work with []=" do
72
+ doc = @document.new
73
+ doc.foo["quux"] = "bar"
74
+ doc.foo["quux"].should == "bar"
75
+ doc.foo.should == { "quux" => "bar" }
76
+ end
77
+
78
+ should "work with indifferent access" do
79
+ doc = @document.new
80
+ doc.foo = {:baz => 'bar'}
81
+ doc.foo[:baz].should == 'bar'
82
+ doc.foo['baz'].should == 'bar'
83
+ end
84
+
85
+ should "work with indifferent access after save" do
86
+ doc = @document.new
87
+ doc.foo = {:baz => 'bar'}
88
+ doc.save
89
+
90
+ doc = doc.reload
91
+ doc.foo[:baz].should == 'bar'
92
+ doc.foo['baz'].should == 'bar'
93
+ end
94
+ end
95
+
96
+ context "custom type key with default" do
97
+ setup do
98
+ @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
99
+ end
100
+
101
+ should "default to default" do
102
+ doc = @document.new
103
+ doc.window.should == WindowSize.new(600, 480)
104
+
105
+ end
106
+
107
+ should "save and load from mongo" do
108
+ doc = @document.new
109
+ doc.save
110
+
111
+ doc = doc.reload
112
+ doc.window.should == WindowSize.new(600, 480)
113
+ end
114
+ end
115
+
116
+ context "key with proc default value" do
117
+ setup do
118
+ @document.key :proc_default, String, :default => lambda { return 'string' }
119
+ end
120
+
121
+ should "detect and run proc default" do
122
+ doc = @document.new
123
+ doc.proc_default.should == 'string'
124
+ end
125
+
126
+ should "save and load from mongo" do
127
+ doc = @document.create
128
+ doc = doc.reload
129
+ doc.proc_default.should == 'string'
130
+ end
131
+ end
132
+
133
+ should "have instance method for collection" do
134
+ @document.new.collection.name.should == @document.collection.name
135
+ end
136
+
137
+ should "have instance method for database" do
138
+ @document.new.database.should == @document.database
139
+ end
140
+
141
+ context "#destroyed?" do
142
+ setup do
143
+ @doc1 = @document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
144
+ end
145
+
146
+ should "be true if deleted" do
147
+ @doc1.delete
148
+ assert @doc1.destroyed?
149
+ end
150
+
151
+ should "be true if destroyed" do
152
+ @doc1.destroy
153
+ assert @doc1.destroyed?
154
+ end
155
+
156
+ should "be false if not deleted or destroyed" do
157
+ assert ! @doc1.destroyed?
158
+ end
159
+ end
160
+
161
+ context "#persisted?" do
162
+ setup do
163
+ @doc = @document.new(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
164
+ end
165
+
166
+ should "be false if new" do
167
+ @doc.should_not be_persisted
168
+ end
169
+
170
+ should "be false if destroyed" do
171
+ @doc.save
172
+ @doc.destroy
173
+ @doc.should be_destroyed
174
+ @doc.should_not be_persisted
175
+ end
176
+
177
+ should "be true if not new or destroyed" do
178
+ @doc.save
179
+ @doc.should be_persisted
180
+ end
181
+ end
182
+
183
+ context "#reload" do
184
+ setup do
185
+ @foo_class = Doc do
186
+ key :name
187
+ end
188
+
189
+ @bar_class = EDoc do
190
+ key :name
191
+ end
192
+
193
+ @document.many :foos, :class => @foo_class
194
+ @document.many :bars, :class => @bar_class
195
+ @document.belongs_to :foo, :class => @foo_class
196
+ @document.one :bar, :class => @bar_class
197
+
198
+ @instance = @document.create({
199
+ :age => 39,
200
+ :foos => [@foo_class.new(:name => '1')],
201
+ :bars => [@bar_class.new(:name => '1')],
202
+ :foo => @foo_class.new(:name => '2'),
203
+ :bar => @bar_class.new(:name => '2')
204
+ })
205
+ end
206
+
207
+ should "reload keys from the database" do
208
+ @instance.age = 37
209
+ @instance.age.should == 37
210
+ @instance.reload
211
+ @instance.age.should == 39
212
+ end
213
+
214
+ should "reset many associations" do
215
+ @instance.foos.expects(:reset).at_least_once
216
+ @instance.bars.expects(:reset).at_least_once
217
+ @instance.reload
218
+ end
219
+
220
+ should "reset belongs_to association" do
221
+ @instance.foo = nil
222
+ @instance.reload
223
+ @instance.foo.should_not be_nil
224
+ end
225
+
226
+ should "reset one association" do
227
+ @instance.bar = nil
228
+ @instance.reload
229
+ @instance.bar.should_not be_nil
230
+ end
231
+
232
+ should "reset nil one association" do
233
+ end
234
+
235
+ should "reinstantiate embedded associations" do
236
+ @instance.reload
237
+ @instance.bars.first.name.should == '1'
238
+ end
239
+
240
+ should "return self" do
241
+ @instance.reload.object_id.should == @instance.object_id
242
+ end
243
+
244
+ should "raise DocumentNotFound if not found" do
245
+ @instance.destroy
246
+ assert_raises(MongoMapper::DocumentNotFound) { @instance.reload }
247
+ end
248
+ end
249
+
250
+ context "database has keys not defined in model" do
251
+ setup do
252
+ @id = BSON::ObjectId.new
253
+ @document.collection.insert({
254
+ :_id => @id,
255
+ :first_name => 'John',
256
+ :last_name => 'Nunemaker',
257
+ :age => 27,
258
+ :favorite_color => 'red',
259
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
260
+ })
261
+ end
262
+
263
+ should "assign all keys from database" do
264
+ doc = @document.find(@id)
265
+ doc.first_name.should == 'John'
266
+ doc.last_name.should == 'Nunemaker'
267
+ doc.age.should == 27
268
+ doc.favorite_color.should == 'red'
269
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+
3
+ class DynamicQueryingTest < Test::Unit::TestCase
4
+ def setup
5
+ @document = Doc do
6
+ scope :nunes, where(:last_name => 'Nunemaker')
7
+
8
+ key :first_name, String
9
+ key :last_name, String
10
+ key :age, Integer
11
+ key :date, Date
12
+ end
13
+
14
+ @doc1 = @document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => 27)
15
+ @doc2 = @document.create(:first_name => 'Steve', :last_name => 'Smith', :age => 28)
16
+ @doc3 = @document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => 26)
17
+ end
18
+
19
+ should "find document based on argument" do
20
+ @document.find_by_first_name('John').should == @doc1
21
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
22
+ @document.find_by_age(27).should == @doc1
23
+ end
24
+
25
+ should "not raise error" do
26
+ @document.find_by_first_name('Mongo').should be_nil
27
+ end
28
+
29
+ should "define a method for each key" do
30
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
31
+ end
32
+
33
+ should "find document based on all arguments" do
34
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
35
+ end
36
+
37
+ should "not find the document if an argument is wrong" do
38
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
39
+ end
40
+
41
+ should "find all documents based on arguments" do
42
+ docs = @document.find_all_by_last_name('Nunemaker')
43
+ docs.should be_kind_of(Array)
44
+ docs.should include(@doc1)
45
+ docs.should include(@doc3)
46
+ end
47
+
48
+ should "initialize document with given arguments" do
49
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
50
+ doc.should be_new
51
+ doc.first_name.should == 'David'
52
+ end
53
+
54
+ should "not initialize document if document is found" do
55
+ doc = @document.find_or_initialize_by_first_name('John')
56
+ doc.should_not be_new
57
+ end
58
+
59
+ should "create document with given arguments" do
60
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
61
+ doc.should_not be_new
62
+ doc.first_name.should == 'David'
63
+ end
64
+
65
+ should "raise error if document is not found when using !" do
66
+ lambda {
67
+ @document.find_by_first_name_and_last_name!(1,2)
68
+ }.should raise_error(MongoMapper::DocumentNotFound)
69
+ end
70
+
71
+ should "work on scopes" do
72
+ @document.nunes.find_by_first_name('Steph').should == @doc3
73
+ @document.nunes.find_all_by_first_name('Steph').should == [@doc3]
74
+ end
75
+ end
@@ -0,0 +1,210 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class EmbeddedDocumentTest < Test::Unit::TestCase
5
+ def setup
6
+ @klass = Doc('Person') do
7
+ key :name, String
8
+ end
9
+
10
+ @pet_klass = EDoc('Pet') do
11
+ key :name, String
12
+ end
13
+
14
+ @klass.many :pets, :class => @pet_klass
15
+
16
+ @address_class = EDoc('Address') do
17
+ key :city, String
18
+ key :state, String
19
+ end
20
+ end
21
+
22
+ context "Saving a document with a key that is an embedded document" do
23
+ setup do
24
+ @klass.key :foo, @address_class
25
+ end
26
+
27
+ should "embed embedded document" do
28
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
29
+ doc = @klass.create(:foo => address)
30
+ doc.foo.city.should == 'South Bend'
31
+ doc.foo.state.should == 'IN'
32
+
33
+ doc = doc.reload
34
+ doc.foo.city.should == 'South Bend'
35
+ doc.foo.state.should == 'IN'
36
+ end
37
+
38
+ should "assign _parent_document and _root_document" do
39
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
40
+ address._parent_document.should be_nil
41
+ doc = @klass.create(:foo => address)
42
+ address._parent_document.should be(doc)
43
+ address._root_document.should be(doc)
44
+ end
45
+
46
+ should "assign _parent_document and _root_document when loading" do
47
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
48
+ doc = @klass.create(:foo => address)
49
+ doc.reload
50
+ doc.foo._parent_document.should be(doc)
51
+ doc.foo._root_document.should be(doc)
52
+ end
53
+ end
54
+
55
+ should "correctly instantiate single collection inherited embedded documents" do
56
+ document = Doc('Foo') do
57
+ key :message, Message
58
+ end
59
+
60
+ doc1 = document.create(:message => Enter.new)
61
+ doc1.reload.message.class.should be(Enter)
62
+ end
63
+
64
+ context "new? (embedded key)" do
65
+ setup do
66
+ @klass.key :foo, @address_class
67
+ end
68
+
69
+ should "be true until document is saved" do
70
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
71
+ doc = @klass.new(:foo => address)
72
+ address.new?.should be_true
73
+ end
74
+
75
+ should "be false after document is saved" do
76
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
77
+ doc = @klass.new(:foo => address)
78
+ doc.save
79
+ doc.foo.new?.should be_false
80
+ end
81
+
82
+ should "be false when loaded from database" do
83
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
84
+ doc = @klass.new(:foo => address)
85
+ doc.save
86
+
87
+ doc.reload
88
+ doc.foo.new?.should be_false
89
+ end
90
+ end
91
+
92
+ context "new? (embedded association)" do
93
+ setup do
94
+ @doc = @klass.new(:pets => [{:name => 'poo bear'}])
95
+ end
96
+
97
+ should "be true until document is saved" do
98
+ @doc.should be_new
99
+ @doc.pets.first.should be_new
100
+ end
101
+
102
+ should "be false after document is saved" do
103
+ @doc.save
104
+ @doc.pets.first.should_not be_new
105
+ end
106
+
107
+ should "be false when loaded from database" do
108
+ @doc.save
109
+ @doc.pets.first.should_not be_new
110
+ @doc.reload
111
+ @doc.pets.first.should_not be_new
112
+ end
113
+ end
114
+
115
+ context "#destroyed?" do
116
+ setup do
117
+ @doc = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
118
+ end
119
+
120
+ should "be false if root document is not destroyed" do
121
+ @doc.should_not be_destroyed
122
+ @doc.pets.first.should_not be_destroyed
123
+ end
124
+
125
+ should "be true if root document is destroyed" do
126
+ @doc.destroy
127
+ @doc.should be_destroyed
128
+ @doc.pets.first.should be_destroyed
129
+ end
130
+ end
131
+
132
+ context "#persisted?" do
133
+ setup do
134
+ @doc = @klass.new(:name => 'persisted doc', :pets => [@pet_klass.new(:name => 'persisted pet')])
135
+ end
136
+
137
+ should "be false if new" do
138
+ @doc.pets.first.should_not be_persisted
139
+ end
140
+
141
+ should "be false if destroyed" do
142
+ @doc.save
143
+ @doc.destroy
144
+ @doc.pets.first.should be_destroyed
145
+ @doc.pets.first.should_not be_persisted
146
+ end
147
+
148
+ should "be true if not new or destroyed" do
149
+ @doc.save
150
+ @doc.pets.first.should be_persisted
151
+ end
152
+ end
153
+
154
+ should "be able to save" do
155
+ person = @klass.create
156
+
157
+ pet = @pet_klass.new(:name => 'sparky')
158
+ person.pets << pet
159
+ pet.should be_new
160
+ pet.save
161
+ pet.should_not be_new
162
+
163
+ person.reload
164
+ person.pets.first.should == pet
165
+ end
166
+
167
+ should "be able to dynamically add new keys and save" do
168
+ person = @klass.create
169
+
170
+ pet = @pet_klass.new(:name => 'sparky', :crazy_key => 'crazy')
171
+ person.pets << pet
172
+ pet.save
173
+
174
+ person.reload
175
+ person.pets.first.crazy_key.should == 'crazy'
176
+ end
177
+
178
+ should "be able to update_attributes" do
179
+ pet = @pet_klass.new(:name => 'sparky')
180
+ person = @klass.create(:pets => [pet])
181
+ person.reload
182
+ pet = person.pets.first
183
+
184
+ pet.update_attributes(:name => 'koda').should be_true
185
+ person.reload
186
+ person.pets.first._id.should == pet._id
187
+ person.pets.first.name.should == 'koda'
188
+ end
189
+
190
+ should "be able to update_attributes!" do
191
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
192
+ person.reload
193
+ pet = person.pets.first
194
+
195
+ attributes = {:name => 'koda'}
196
+ pet.expects(:attributes=).with(attributes)
197
+ pet.expects(:save!)
198
+ pet.update_attributes!(attributes)
199
+ end
200
+
201
+ should "have database instance method that is equal to root document" do
202
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
203
+ person.pets.first.database.should == person.database
204
+ end
205
+
206
+ should "have collection instance method that is equal to root document" do
207
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
208
+ person.pets.first.collection.name.should == person.collection.name
209
+ end
210
+ end