lookout-mongo_mapper 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +26 -0
  4. data/bin/mmconsole +59 -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 +2 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +38 -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 +94 -0
  19. data/lib/mongo_mapper/connection.rb +96 -0
  20. data/lib/mongo_mapper/document.rb +42 -0
  21. data/lib/mongo_mapper/embedded_document.rb +32 -0
  22. data/lib/mongo_mapper/exceptions.rb +30 -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 +26 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +32 -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 +28 -0
  37. data/lib/mongo_mapper/locale/en.yml +5 -0
  38. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  39. data/lib/mongo_mapper/plugins.rb +22 -0
  40. data/lib/mongo_mapper/plugins/accessible.rb +52 -0
  41. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  42. data/lib/mongo_mapper/plugins/associations.rb +90 -0
  43. data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
  44. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
  45. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
  46. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  47. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  48. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
  49. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
  50. data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
  51. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  52. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
  53. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  54. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  55. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  56. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  57. data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
  58. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  59. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  60. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
  61. data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
  62. data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
  63. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  64. data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
  65. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  66. data/lib/mongo_mapper/plugins/dirty.rb +60 -0
  67. data/lib/mongo_mapper/plugins/document.rb +41 -0
  68. data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
  69. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  70. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
  71. data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
  72. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  73. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  74. data/lib/mongo_mapper/plugins/indexes.rb +13 -0
  75. data/lib/mongo_mapper/plugins/inspect.rb +16 -0
  76. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  77. data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
  78. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  79. data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
  80. data/lib/mongo_mapper/plugins/pagination.rb +16 -0
  81. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  82. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  83. data/lib/mongo_mapper/plugins/querying.rb +165 -0
  84. data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
  85. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  86. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  87. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  88. data/lib/mongo_mapper/plugins/sci.rb +36 -0
  89. data/lib/mongo_mapper/plugins/scopes.rb +27 -0
  90. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  91. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  92. data/lib/mongo_mapper/plugins/touch.rb +18 -0
  93. data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
  94. data/lib/mongo_mapper/plugins/validations.rb +86 -0
  95. data/lib/mongo_mapper/railtie.rb +48 -0
  96. data/lib/mongo_mapper/railtie/database.rake +65 -0
  97. data/lib/mongo_mapper/translation.rb +10 -0
  98. data/lib/mongo_mapper/version.rb +4 -0
  99. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  100. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  101. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  102. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
  103. data/test/_NOTE_ON_TESTING +1 -0
  104. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  105. data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
  106. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  107. data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
  108. data/test/functional/associations/test_many_documents_proxy.rb +866 -0
  109. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
  110. data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
  111. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  112. data/test/functional/associations/test_one_as_proxy.rb +491 -0
  113. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  114. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  115. data/test/functional/associations/test_one_proxy.rb +383 -0
  116. data/test/functional/test_accessible.rb +198 -0
  117. data/test/functional/test_associations.rb +46 -0
  118. data/test/functional/test_binary.rb +27 -0
  119. data/test/functional/test_caching.rb +77 -0
  120. data/test/functional/test_callbacks.rb +232 -0
  121. data/test/functional/test_dirty.rb +301 -0
  122. data/test/functional/test_document.rb +282 -0
  123. data/test/functional/test_dynamic_querying.rb +75 -0
  124. data/test/functional/test_embedded_document.rb +288 -0
  125. data/test/functional/test_equality.rb +20 -0
  126. data/test/functional/test_identity_map.rb +513 -0
  127. data/test/functional/test_indexes.rb +50 -0
  128. data/test/functional/test_logger.rb +20 -0
  129. data/test/functional/test_modifiers.rb +537 -0
  130. data/test/functional/test_pagination.rb +91 -0
  131. data/test/functional/test_protected.rb +201 -0
  132. data/test/functional/test_querying.rb +935 -0
  133. data/test/functional/test_safe.rb +76 -0
  134. data/test/functional/test_sci.rb +240 -0
  135. data/test/functional/test_scopes.rb +171 -0
  136. data/test/functional/test_timestamps.rb +62 -0
  137. data/test/functional/test_touch.rb +125 -0
  138. data/test/functional/test_userstamps.rb +44 -0
  139. data/test/functional/test_validations.rb +414 -0
  140. data/test/models.rb +261 -0
  141. data/test/support/railtie.rb +4 -0
  142. data/test/support/railtie/autoloaded.rb +2 -0
  143. data/test/support/railtie/not_autoloaded.rb +3 -0
  144. data/test/support/railtie/parent.rb +3 -0
  145. data/test/test_active_model_lint.rb +18 -0
  146. data/test/test_helper.rb +93 -0
  147. data/test/unit/associations/test_base.rb +146 -0
  148. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  149. data/test/unit/associations/test_many_association.rb +63 -0
  150. data/test/unit/associations/test_one_association.rb +47 -0
  151. data/test/unit/associations/test_proxy.rb +100 -0
  152. data/test/unit/serializers/test_json_serializer.rb +216 -0
  153. data/test/unit/serializers/test_xml_serializer.rb +196 -0
  154. data/test/unit/test_clone.rb +69 -0
  155. data/test/unit/test_document.rb +249 -0
  156. data/test/unit/test_dynamic_finder.rb +125 -0
  157. data/test/unit/test_embedded_document.rb +682 -0
  158. data/test/unit/test_equality.rb +38 -0
  159. data/test/unit/test_exceptions.rb +12 -0
  160. data/test/unit/test_extensions.rb +380 -0
  161. data/test/unit/test_identity_map_middleware.rb +34 -0
  162. data/test/unit/test_inspect.rb +47 -0
  163. data/test/unit/test_key.rb +205 -0
  164. data/test/unit/test_keys.rb +65 -0
  165. data/test/unit/test_mongo_mapper.rb +143 -0
  166. data/test/unit/test_pagination.rb +11 -0
  167. data/test/unit/test_plugins.rb +89 -0
  168. data/test/unit/test_rails.rb +183 -0
  169. data/test/unit/test_rails_compatibility.rb +38 -0
  170. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  171. data/test/unit/test_railtie.rb +66 -0
  172. data/test/unit/test_serialization.rb +166 -0
  173. data/test/unit/test_time_zones.rb +44 -0
  174. data/test/unit/test_translation.rb +27 -0
  175. data/test/unit/test_validations.rb +562 -0
  176. metadata +285 -0
@@ -0,0 +1,208 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class OneEmbeddedPolymorhpicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc('Post') do
7
+ key :title, String
8
+ end
9
+ end
10
+
11
+ should "default to nil" do
12
+ @post_class.one :author, :polymorphic => true, :class => Robot
13
+ @post_class.new.author.should be_nil
14
+ end
15
+
16
+ should "return nil instead of a proxy" do
17
+ @post_class.one :author, :polymorphic => true, :class => Robot
18
+ nil.should === @post_class.new.author
19
+ end
20
+
21
+ should "be able to build" do
22
+ @post_class.one :author, :polymorphic => true, :class => Robot
23
+ post = @post_class.create
24
+ author = post.build_author(:serial_number => "1B")
25
+ post.author.should be_instance_of(Robot)
26
+ post.author.should be_new
27
+ post.author.serial_number.should == '1B'
28
+ post.author.should == author
29
+ post.author.post.should == post
30
+ end
31
+
32
+ should "allow assignment of associated document using a hash" do
33
+ @post_class.one :author, :polymorphic => :true, :class => Robot
34
+
35
+ post = @post_class.new('author' => { 'name' => 'Frank', '_type' => 'Human' })
36
+ post.author.name.should == 'Frank'
37
+ post.author.class.should == Human
38
+
39
+ post.save.should be_true
40
+ post.reload
41
+
42
+ post.author.name.should == 'Frank'
43
+ post.author.class.should == Human
44
+ end
45
+
46
+ context "replacing the association" do
47
+ context "with an object" do
48
+ setup do
49
+ @post_class.one :author, :polymorphic => true, :class => Robot
50
+ @post = @post_class.create
51
+ @human = Human.new(:name => 'Frank')
52
+ end
53
+
54
+ should "work" do
55
+ @post.author = @human
56
+ @post.save
57
+ @post.reload
58
+
59
+ @post.author.should == @human
60
+ @post.author.nil?.should be_false
61
+ @post.author.class.should == Human
62
+
63
+ new_human = Human.new(:name => 'Emily')
64
+ @post.author = new_human
65
+ @post.author.should == new_human
66
+ end
67
+
68
+ should "generate a new proxy instead of modifying the existing one" do
69
+ @post.author = @human
70
+ @post.save
71
+ @post.reload
72
+
73
+ @post.author.should == @human
74
+ @post.author.nil?.should be_false
75
+
76
+ original_author = @post.author
77
+ original_author.name.should == 'Frank'
78
+ new_human = Human.new(:name => 'Emily')
79
+ @post.author = new_human
80
+ @post.author.should == new_human
81
+
82
+ original_author.name.should == 'Frank'
83
+ end
84
+
85
+ should "assign _type" do
86
+ @post.author = @human
87
+ @post.author._type.should == "Human"
88
+ end
89
+ end
90
+
91
+ context "with a Hash" do
92
+ setup do
93
+ @post_class.one :author, :polymorphic => true, :class => Robot
94
+ @post = @post_class.create
95
+ end
96
+
97
+ should "convert to an object of the class and work" do
98
+ @post.author = {'serial_number' => '1B'}
99
+ @post.save
100
+ @post.reload
101
+
102
+ @post.author.serial_number.should == '1B'
103
+ @post.author.nil?.should be_false
104
+
105
+ @post.author = {'serial_number' => '2C'}
106
+ @post.author.serial_number.should == '2C'
107
+ end
108
+
109
+ should "convert to an object of _type if given" do
110
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
111
+ @post.author.name.should == 'Frank'
112
+ @post.author.class.should == Human
113
+ @post.save
114
+ @post.reload
115
+
116
+ @post.author.name.should == 'Frank'
117
+ @post.author.class.should == Human
118
+ end
119
+
120
+ should "assign _type" do
121
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
122
+ @post.save
123
+ @post.reload
124
+ @post.author._type.should == "Human"
125
+ end
126
+ end
127
+ end
128
+
129
+ should "unset the association" do
130
+ @post_class.one :author, :polymorphic => true, :class => Robot
131
+ post = @post_class.create
132
+ human = Human.new
133
+ post.update_attributes!(:author => human)
134
+ post.reload
135
+ post.author = nil
136
+ post.author.should == nil
137
+ end
138
+
139
+ should "set modularized associated models correctly" do
140
+ @post_class.one :author, :polymorphic => true, :class => Robot
141
+
142
+ post = @post_class.new('author' => {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true})
143
+
144
+ post.author.class.should == TrModels::Ambulance
145
+ post.author.license_plate.should == 'GGG123'
146
+ post.author.icu.should be_true
147
+ post.save.should be_true
148
+
149
+ post = post.reload
150
+ post.author.class.should == TrModels::Ambulance
151
+ post.author.license_plate.should == 'GGG123'
152
+ post.author.icu.should be_true
153
+ end
154
+
155
+ should "not have problem loading root document if embedded one is nil" do
156
+ @post_class.one :author, :polymorphic => true, :class => Robot
157
+ post = @post_class.create
158
+
159
+ lambda {
160
+ @post_class.find(post.id)
161
+ }.should_not raise_error
162
+ end
163
+
164
+ should "load the parent and root documents for nested embedded documents" do
165
+ @address_class = EDoc('Address') do
166
+ key :city, String
167
+ key :state, String
168
+ end
169
+ @author_class = EDoc('EmbeddedAuthor')
170
+ @author_class.one :address, :polymorphic => true, :class => @address_class
171
+ @post_class.one :author, :polymorphic => true, :class => @author_class
172
+
173
+ post = @post_class.create(:title => 'Post Title', :author => { :name => 'Frank', :address => { :city => 'Boston', :state => 'MA' } })
174
+
175
+ post.author.address._parent_document.should == post.author
176
+ post.author.address._root_document.should == post
177
+ end
178
+
179
+ should "have boolean method for testing presence" do
180
+ @post_class.one :author, :polymorphic => true, :class => Robot
181
+
182
+ post = @post_class.new
183
+ post.author?.should be_false
184
+
185
+ post.author = Human.new(:name => 'Frank')
186
+ post.author?.should be_true
187
+ end
188
+
189
+ should "initialize id for nested embedded document created from hash" do
190
+ @address_class = EDoc('Address') do
191
+ key :city, String
192
+ key :state, String
193
+ end
194
+ @author_class = EDoc('EmbeddedAuthor')
195
+ @author_class.one :address, :polymorphic => true, :class => @address_class
196
+ @post_class.one :author, :polymorphic => true, :class => @author_class
197
+
198
+ post = @post_class.create(:title => 'Post Title', :author => {
199
+ :name => 'Frank',
200
+ :address => {
201
+ :city => 'Boston',
202
+ :state => 'MA'
203
+ }
204
+ })
205
+
206
+ post.author.address.id.should_not be_nil
207
+ end
208
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class OneEmbeddedProxyTest < Test::Unit::TestCase
4
+ def setup
5
+ @post_class = Doc('Post') do
6
+ key :title, String
7
+ end
8
+ @author_class = EDoc('Author') do
9
+ key :name, String
10
+ embedded_in :post
11
+ end
12
+ end
13
+
14
+ should "default to nil" do
15
+ @post_class.one :author, :class => @author_class
16
+ @post_class.new.author.should be_nil
17
+ end
18
+
19
+ should "be able to build" do
20
+ @post_class.one :author, :class => @author_class
21
+
22
+ post = @post_class.create
23
+ author = post.build_author(:name => "John")
24
+ post.author.should be_instance_of(@author_class)
25
+ post.author.should be_new
26
+ post.author.name.should == 'John'
27
+ post.author.should == author
28
+ post.author.post.should == post
29
+ end
30
+
31
+ should "be able to replace the association" do
32
+ @post_class.one :author, :class => @author_class
33
+
34
+ post = @post_class.new
35
+ author = @author_class.new(:name => 'Frank')
36
+ post.author = author
37
+ post.save
38
+ post.reload
39
+
40
+ post.author.should == author
41
+ post.author.nil?.should be_false
42
+
43
+ new_author = @author_class.new(:name => 'Emily')
44
+ post.author = new_author
45
+ post.author.should == new_author
46
+ end
47
+
48
+ should "not have problem loading root document if embedded one is nil" do
49
+ @post_class.one :author, :class => @author_class
50
+ post = @post_class.create
51
+
52
+ lambda {
53
+ @post_class.find(post.id)
54
+ }.should_not raise_error
55
+ end
56
+
57
+ should "load the parent and root documents for nested embedded documents" do
58
+ @address_class = EDoc('Address') do
59
+ key :city, String
60
+ key :state, String
61
+ end
62
+ @author_class.one :address, :class => @address_class
63
+ @post_class.one :author, :class => @author_class
64
+
65
+ post = @post_class.create(:title => 'Post Title', :author => { :name => 'Frank', :address => { :city => 'Boston', :state => 'MA' } })
66
+
67
+ post.author.address._parent_document.should == post.author
68
+ post.author.address._root_document.should == post
69
+ end
70
+
71
+ should "have boolean method for testing presence" do
72
+ @post_class.one :author, :class => @author_class
73
+
74
+ post = @post_class.new
75
+ post.author?.should be_false
76
+
77
+ post.author = @author_class.new(:name => 'Frank')
78
+ post.author?.should be_true
79
+ end
80
+
81
+ should "initialize id for nested embedded document created from hash" do
82
+ @address_class = EDoc('Address') do
83
+ key :city, String
84
+ key :state, String
85
+ end
86
+ @author_class.one(:address, :class => @address_class)
87
+ @post_class.one(:author, :class => @author_class)
88
+
89
+ post = @post_class.create(:title => 'Post Title', :author => {
90
+ :name => 'Frank',
91
+ :address => {
92
+ :city => 'Boston',
93
+ :state => 'MA'
94
+ }
95
+ })
96
+
97
+ post.author.address.id.should_not be_nil
98
+ end
99
+
100
+ end
@@ -0,0 +1,383 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class OneProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc('Post')
7
+ @author_class = Doc do
8
+ key :post_id, ObjectId
9
+ end
10
+ end
11
+
12
+ should "default to nil" do
13
+ @post_class.one :author, :class => @author_class
14
+ @post_class.new.author.nil?.should be_true
15
+ end
16
+
17
+ should "return nil instead of a proxy" do
18
+ @post_class.one :author, :class => @author_class
19
+ nil.should === @post_class.new.author
20
+ end
21
+
22
+ should "allow assignment of associated document using a hash" do
23
+ @post_class.one :author, :class => @author_class
24
+
25
+ post = @post_class.new('author' => { 'name' => 'Frank' })
26
+ post.author.name.should == 'Frank'
27
+
28
+ post.save.should be_true
29
+ post.reload
30
+
31
+ post.author.name.should == 'Frank'
32
+ end
33
+
34
+ context "replacing the association" do
35
+ context "with an object of the class" do
36
+ should "work" do
37
+ @post_class.one :author, :class => @author_class
38
+
39
+ post = @post_class.new
40
+ author = @author_class.new(:name => 'Frank')
41
+ post.author = author
42
+ post.reload
43
+
44
+ post.author.should == author
45
+ post.author.nil?.should be_false
46
+
47
+ new_author = @author_class.new(:name => 'Emily')
48
+ post.author = new_author
49
+ post.author.should == new_author
50
+ end
51
+
52
+ should "generate a new proxy instead of modifying the existing one" do
53
+ @post_class.one :author, :class => @author_class
54
+
55
+ post = @post_class.new
56
+ author = @author_class.new(:name => 'Frank')
57
+ post.author = author
58
+ post.reload
59
+
60
+ post.author.should == author
61
+ post.author.nil?.should be_false
62
+
63
+ original_author = post.author
64
+ original_author.name.should == 'Frank'
65
+ new_author = @author_class.new(:name => 'Emily')
66
+ post.author = new_author
67
+ post.author.should == new_author
68
+
69
+ original_author.name.should == 'Frank'
70
+ end
71
+ end
72
+
73
+ context "with a Hash" do
74
+ should "convert to an object of the class and work" do
75
+ @post_class.one :author, :class => @author_class
76
+
77
+ post = @post_class.new
78
+ post.author = {'name' => 'Frank'}
79
+ post.reload
80
+
81
+ post.author.name.should == 'Frank'
82
+ post.author.nil?.should be_false
83
+
84
+ post.author = {'name' => 'Emily'}
85
+ post.author.name.should == 'Emily'
86
+ end
87
+ end
88
+
89
+ context "with :dependent" do
90
+ context "=> delete" do
91
+ setup do
92
+ @post_class.one :author, :class => @author_class, :dependent => :delete
93
+
94
+ @post = @post_class.create
95
+ @author = @author_class.new
96
+ @post.author = @author
97
+ end
98
+
99
+ should "call delete on the existing document" do
100
+ @author_class.any_instance.expects(:delete).once
101
+ @post.author = @author_class.new
102
+ end
103
+
104
+ should "remove the existing document from the database" do
105
+ @post.author = @author_class.new
106
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
107
+ end
108
+
109
+ should "do nothing if it's the same document" do
110
+ @author_class.any_instance.expects(:delete).never
111
+ @post.author = @author
112
+ end
113
+ end
114
+
115
+ context "=> destory" do
116
+ setup do
117
+ @post_class.one :author, :class => @author_class, :dependent => :destroy
118
+
119
+ @post = @post_class.create
120
+ @author = @author_class.new
121
+ @post.author = @author
122
+ end
123
+
124
+ should "call destroy the existing document" do
125
+ @author_class.any_instance.expects(:destroy).once
126
+ @post.author = @author_class.new
127
+ end
128
+
129
+ should "remove the existing document from the database" do
130
+ @post.author = @author_class.new
131
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
132
+ end
133
+
134
+ should "do nothing if it's the same document" do
135
+ @author_class.any_instance.expects(:destroy).never
136
+ @post.author = @author
137
+ end
138
+ end
139
+
140
+ context "=> nullify" do
141
+ setup do
142
+ @post_class.one :author, :class => @author_class, :dependent => :nullify
143
+
144
+ @post = @post_class.create
145
+ @author = @author_class.new
146
+ @post.author = @author
147
+ end
148
+
149
+ should "nullify the existing document" do
150
+ @author.reload
151
+ @author.post_id.should == @post.id
152
+
153
+ @post.author = @author_class.new
154
+
155
+ @author.reload
156
+ @author.post_id.should be_nil
157
+ end
158
+
159
+ should "work when it's the same document" do
160
+ old_author = @post.author
161
+ @post.author = @author
162
+ old_author.should == @post.author
163
+ end
164
+ end
165
+
166
+ context "unspecified" do
167
+ should "nullify the existing document" do
168
+ @post_class.one :author, :class => @author_class
169
+
170
+ post = @post_class.create
171
+ author = @author_class.new
172
+ post.author = author
173
+ author.reload
174
+ author.post_id.should == post.id
175
+
176
+ post.author = @author_class.new
177
+
178
+ author.reload
179
+ author.post_id.should be_nil
180
+ end
181
+ end
182
+ end
183
+
184
+ context "with nil" do
185
+ setup do
186
+ @post_class.one :author, :class => @author_class
187
+
188
+ @post = @post_class.new
189
+ @author = @author_class.new(:name => 'Frank')
190
+ @post.author = @author
191
+ end
192
+
193
+ should "nullify the existing document" do
194
+ @post.author = nil
195
+ @author.reload
196
+ @author.post_id.should be_nil
197
+ end
198
+
199
+ should "set the target to nil" do
200
+ @post.author = nil
201
+ @post.author.should == nil
202
+ end
203
+ end
204
+ end
205
+
206
+ should "have boolean method for testing presence" do
207
+ @post_class.one :author, :class => @author_class
208
+
209
+ post = @post_class.new
210
+ post.author?.should be_false
211
+
212
+ post.author = @author_class.new(:name => 'Frank')
213
+ post.author?.should be_true
214
+ end
215
+
216
+ should "work with criteria" do
217
+ @post_class.one :primary_author, :class => @author_class, :primary => true
218
+ @post_class.one :author, :class => @author_class, :primary => false
219
+
220
+ post = @post_class.create
221
+ author = @author_class.create(:name => 'Frank', :primary => false, :post_id => post.id)
222
+ primary = @author_class.create(:name => 'Bill', :primary => true, :post_id => post.id)
223
+ post.reload
224
+ post.author.should == author
225
+ post.primary_author.should == primary
226
+ end
227
+
228
+ should "unset the association" do
229
+ @post_class.one :author, :class => @author_class
230
+ post = @post_class.create
231
+ author = @author_class.create
232
+ post.update_attributes!(:author => author)
233
+ post.reload
234
+ post.author = nil
235
+ post.author.nil?.should be_true
236
+ end
237
+
238
+ context "destroying parent with :dependent" do
239
+ context "=> destroy" do
240
+ setup do
241
+ @post_class.one :author, :class => @author_class, :dependent => :destroy
242
+
243
+ @post = @post_class.create
244
+ @author = @author_class.new
245
+ @post.author = @author
246
+ end
247
+
248
+ should "should call destroy on the associated documents" do
249
+ @author_class.any_instance.expects(:destroy).once
250
+ @post.destroy
251
+ end
252
+
253
+ should "should remove the associated documents" do
254
+ @author_class.count.should == 1
255
+ @post.destroy
256
+ @post.author.should == nil
257
+ @author_class.count.should == 0
258
+ end
259
+ end
260
+
261
+ context "=> delete" do
262
+ setup do
263
+ @post_class.one :author, :class => @author_class, :dependent => :delete
264
+
265
+ @post = @post_class.create
266
+ @author = @author_class.new
267
+ @post.author = @author
268
+ end
269
+
270
+ should "should call delete the associated documents" do
271
+ @author_class.any_instance.expects(:delete).once
272
+ @post.destroy
273
+ end
274
+
275
+ should "remove the associated documents" do
276
+ @author_class.count.should == 1
277
+ @post.destroy
278
+ @post.author.should == nil
279
+ @author_class.count.should == 0
280
+ end
281
+ end
282
+
283
+ context "=> nullify" do
284
+ should "should nullify the relationship but not destroy the associated document" do
285
+ @post_class.one :author, :class => @author_class, :dependent => :nullify
286
+
287
+ post = @post_class.create
288
+ author = @author_class.new
289
+ post.author = author
290
+
291
+ @author_class.count.should == 1
292
+ post.destroy
293
+ post.author.should == nil
294
+ @author_class.count.should == 1
295
+
296
+ @author_class.first.should == author
297
+ author.post_id.should == nil
298
+ end
299
+ end
300
+
301
+ context "unspecified" do
302
+ should "should nullify the relationship but not destroy the associated document" do
303
+ @post_class.one :author, :class => @author_class
304
+
305
+ post = @post_class.create
306
+ author = @author_class.new
307
+ post.author = author
308
+
309
+ @author_class.count.should == 1
310
+ post.destroy
311
+ post.author.should == nil
312
+ @author_class.count.should == 1
313
+
314
+ @author_class.first.should == author
315
+ author.post_id.should == nil
316
+ end
317
+ end
318
+ end
319
+
320
+
321
+ should "be able to build" do
322
+ @post_class.one :author, :class => @author_class
323
+
324
+ post = @post_class.create
325
+ author = post.build_author(:name => 'John')
326
+ post.author.should be_instance_of(@author_class)
327
+ post.author.should be_new
328
+ post.author.name.should == 'John'
329
+ post.author.should == author
330
+ post.author.post_id.should == post.id
331
+ end
332
+
333
+ should "be able to create" do
334
+ @post_class.one :author, :class => @author_class
335
+
336
+ post = @post_class.create
337
+ author = post.create_author(:name => 'John')
338
+ post.author.should be_instance_of(@author_class)
339
+ post.author.should_not be_new
340
+ post.author.name.should == 'John'
341
+ post.author.should == author
342
+ post.author.post_id.should == post.id
343
+ end
344
+
345
+ context "#create!" do
346
+ setup do
347
+ @author_class.key :name, String, :required => true
348
+ @post_class.one :author, :class => @author_class
349
+ end
350
+
351
+ should "raise exception if invalid" do
352
+ post = @post_class.create
353
+ assert_raises(MongoMapper::DocumentNotValid) do
354
+ post.create_author!
355
+ end
356
+ end
357
+
358
+ should "work if valid" do
359
+ post = @post_class.create
360
+ author = post.create_author!(:name => 'John')
361
+ post.author.should be_instance_of(@author_class)
362
+ post.author.should_not be_new
363
+ post.author.name.should == 'John'
364
+ post.author.should == author
365
+ post.author.post_id.should == post.id
366
+ end
367
+ end
368
+
369
+ context "namespaced foreign keys" do
370
+ setup do
371
+ News::Paper.one :article, :class_name => 'News::Article'
372
+ News::Article.belongs_to :paper, :class_name => 'News::Paper'
373
+
374
+ @paper = News::Paper.create
375
+ end
376
+
377
+ should "properly infer the foreign key" do
378
+ article = @paper.create_article
379
+ article.should respond_to(:paper_id)
380
+ article.paper_id.should == @paper.id
381
+ end
382
+ end
383
+ end