mark_mapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +39 -0
  4. data/examples/attr_accessible.rb +24 -0
  5. data/examples/attr_protected.rb +24 -0
  6. data/examples/cache_key.rb +26 -0
  7. data/examples/custom_types.rb +26 -0
  8. data/examples/identity_map.rb +30 -0
  9. data/examples/identity_map/automatic.rb +2 -0
  10. data/examples/keys.rb +42 -0
  11. data/examples/modifiers/set.rb +27 -0
  12. data/examples/plugins.rb +40 -0
  13. data/examples/querying.rb +39 -0
  14. data/examples/sample_app.rb +43 -0
  15. data/examples/scopes.rb +56 -0
  16. data/examples/validating/embedded_docs.rb +31 -0
  17. data/lib/mark_mapper.rb +125 -0
  18. data/lib/mark_mapper/config.rb +90 -0
  19. data/lib/mark_mapper/connection.rb +60 -0
  20. data/lib/mark_mapper/criteria_hash.rb +194 -0
  21. data/lib/mark_mapper/document.rb +46 -0
  22. data/lib/mark_mapper/embedded_document.rb +32 -0
  23. data/lib/mark_mapper/exceptions.rb +33 -0
  24. data/lib/mark_mapper/extensions/array.rb +27 -0
  25. data/lib/mark_mapper/extensions/boolean.rb +45 -0
  26. data/lib/mark_mapper/extensions/date.rb +29 -0
  27. data/lib/mark_mapper/extensions/duplicable.rb +86 -0
  28. data/lib/mark_mapper/extensions/float.rb +18 -0
  29. data/lib/mark_mapper/extensions/hash.rb +26 -0
  30. data/lib/mark_mapper/extensions/integer.rb +27 -0
  31. data/lib/mark_mapper/extensions/kernel.rb +11 -0
  32. data/lib/mark_mapper/extensions/nil_class.rb +18 -0
  33. data/lib/mark_mapper/extensions/object.rb +30 -0
  34. data/lib/mark_mapper/extensions/object_id.rb +18 -0
  35. data/lib/mark_mapper/extensions/set.rb +20 -0
  36. data/lib/mark_mapper/extensions/string.rb +31 -0
  37. data/lib/mark_mapper/extensions/symbol.rb +87 -0
  38. data/lib/mark_mapper/extensions/time.rb +29 -0
  39. data/lib/mark_mapper/locale/en.yml +5 -0
  40. data/lib/mark_mapper/middleware/identity_map.rb +41 -0
  41. data/lib/mark_mapper/normalizers/criteria_hash_key.rb +17 -0
  42. data/lib/mark_mapper/normalizers/criteria_hash_value.rb +66 -0
  43. data/lib/mark_mapper/normalizers/fields_value.rb +26 -0
  44. data/lib/mark_mapper/normalizers/hash_key.rb +19 -0
  45. data/lib/mark_mapper/normalizers/integer.rb +19 -0
  46. data/lib/mark_mapper/normalizers/options_hash_value.rb +83 -0
  47. data/lib/mark_mapper/normalizers/sort_value.rb +55 -0
  48. data/lib/mark_mapper/options_hash.rb +103 -0
  49. data/lib/mark_mapper/pagination.rb +6 -0
  50. data/lib/mark_mapper/pagination/collection.rb +32 -0
  51. data/lib/mark_mapper/pagination/paginator.rb +46 -0
  52. data/lib/mark_mapper/plugins.rb +22 -0
  53. data/lib/mark_mapper/plugins/accessible.rb +61 -0
  54. data/lib/mark_mapper/plugins/active_model.rb +18 -0
  55. data/lib/mark_mapper/plugins/associations.rb +96 -0
  56. data/lib/mark_mapper/plugins/associations/base.rb +98 -0
  57. data/lib/mark_mapper/plugins/associations/belongs_to_association.rb +63 -0
  58. data/lib/mark_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +35 -0
  59. data/lib/mark_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  60. data/lib/mark_mapper/plugins/associations/collection.rb +29 -0
  61. data/lib/mark_mapper/plugins/associations/embedded_collection.rb +44 -0
  62. data/lib/mark_mapper/plugins/associations/in_array_proxy.rb +133 -0
  63. data/lib/mark_mapper/plugins/associations/many_association.rb +63 -0
  64. data/lib/mark_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  65. data/lib/mark_mapper/plugins/associations/many_documents_proxy.rb +142 -0
  66. data/lib/mark_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  67. data/lib/mark_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  68. data/lib/mark_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  69. data/lib/mark_mapper/plugins/associations/one_as_proxy.rb +22 -0
  70. data/lib/mark_mapper/plugins/associations/one_association.rb +48 -0
  71. data/lib/mark_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  72. data/lib/mark_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  73. data/lib/mark_mapper/plugins/associations/one_proxy.rb +95 -0
  74. data/lib/mark_mapper/plugins/associations/proxy.rb +138 -0
  75. data/lib/mark_mapper/plugins/associations/single_association.rb +46 -0
  76. data/lib/mark_mapper/plugins/caching.rb +21 -0
  77. data/lib/mark_mapper/plugins/callbacks.rb +42 -0
  78. data/lib/mark_mapper/plugins/clone.rb +24 -0
  79. data/lib/mark_mapper/plugins/counter_cache.rb +97 -0
  80. data/lib/mark_mapper/plugins/dirty.rb +61 -0
  81. data/lib/mark_mapper/plugins/document.rb +41 -0
  82. data/lib/mark_mapper/plugins/dumpable.rb +22 -0
  83. data/lib/mark_mapper/plugins/dynamic_querying.rb +45 -0
  84. data/lib/mark_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  85. data/lib/mark_mapper/plugins/embedded_callbacks.rb +81 -0
  86. data/lib/mark_mapper/plugins/embedded_document.rb +53 -0
  87. data/lib/mark_mapper/plugins/equality.rb +23 -0
  88. data/lib/mark_mapper/plugins/identity_map.rb +144 -0
  89. data/lib/mark_mapper/plugins/indexable.rb +86 -0
  90. data/lib/mark_mapper/plugins/inspect.rb +16 -0
  91. data/lib/mark_mapper/plugins/keys.rb +470 -0
  92. data/lib/mark_mapper/plugins/keys/key.rb +134 -0
  93. data/lib/mark_mapper/plugins/keys/static.rb +45 -0
  94. data/lib/mark_mapper/plugins/logger.rb +18 -0
  95. data/lib/mark_mapper/plugins/modifiers.rb +140 -0
  96. data/lib/mark_mapper/plugins/pagination.rb +16 -0
  97. data/lib/mark_mapper/plugins/partial_updates.rb +77 -0
  98. data/lib/mark_mapper/plugins/persistence.rb +79 -0
  99. data/lib/mark_mapper/plugins/protected.rb +45 -0
  100. data/lib/mark_mapper/plugins/querying.rb +173 -0
  101. data/lib/mark_mapper/plugins/querying/decorated_markmapper_query.rb +75 -0
  102. data/lib/mark_mapper/plugins/rails.rb +79 -0
  103. data/lib/mark_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  104. data/lib/mark_mapper/plugins/sci.rb +82 -0
  105. data/lib/mark_mapper/plugins/scopes.rb +28 -0
  106. data/lib/mark_mapper/plugins/serialization.rb +109 -0
  107. data/lib/mark_mapper/plugins/timestamps.rb +29 -0
  108. data/lib/mark_mapper/plugins/touch.rb +18 -0
  109. data/lib/mark_mapper/plugins/userstamps.rb +18 -0
  110. data/lib/mark_mapper/plugins/validations.rb +96 -0
  111. data/lib/mark_mapper/query.rb +278 -0
  112. data/lib/mark_mapper/railtie.rb +52 -0
  113. data/lib/mark_mapper/railtie/database.rake +65 -0
  114. data/lib/mark_mapper/translation.rb +10 -0
  115. data/lib/mark_mapper/version.rb +4 -0
  116. data/lib/rails/generators/mark_mapper/config/config_generator.rb +37 -0
  117. data/lib/rails/generators/mark_mapper/config/templates/marklogic.yml +19 -0
  118. data/lib/rails/generators/mark_mapper/model/model_generator.rb +40 -0
  119. data/lib/rails/generators/mark_mapper/model/templates/model.rb +17 -0
  120. data/spec/config/mark_mapper.yml +6 -0
  121. data/spec/examples_spec.rb +25 -0
  122. data/spec/functional/accessible_spec.rb +198 -0
  123. data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +64 -0
  124. data/spec/functional/associations/belongs_to_proxy_spec.rb +255 -0
  125. data/spec/functional/associations/in_array_proxy_spec.rb +349 -0
  126. data/spec/functional/associations/many_documents_as_proxy_spec.rb +230 -0
  127. data/spec/functional/associations/many_documents_proxy_spec.rb +968 -0
  128. data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +238 -0
  129. data/spec/functional/associations/many_embedded_proxy_spec.rb +288 -0
  130. data/spec/functional/associations/many_polymorphic_proxy_spec.rb +302 -0
  131. data/spec/functional/associations/one_as_proxy_spec.rb +489 -0
  132. data/spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb +207 -0
  133. data/spec/functional/associations/one_embedded_proxy_spec.rb +100 -0
  134. data/spec/functional/associations/one_proxy_spec.rb +406 -0
  135. data/spec/functional/associations_spec.rb +48 -0
  136. data/spec/functional/caching_spec.rb +75 -0
  137. data/spec/functional/callbacks_spec.rb +330 -0
  138. data/spec/functional/counter_cache_spec.rb +235 -0
  139. data/spec/functional/dirty_spec.rb +316 -0
  140. data/spec/functional/document_spec.rb +310 -0
  141. data/spec/functional/dumpable_spec.rb +24 -0
  142. data/spec/functional/dynamic_querying_spec.rb +75 -0
  143. data/spec/functional/embedded_document_spec.rb +316 -0
  144. data/spec/functional/equality_spec.rb +20 -0
  145. data/spec/functional/extensions_spec.rb +16 -0
  146. data/spec/functional/identity_map_spec.rb +483 -0
  147. data/spec/functional/keys_spec.rb +339 -0
  148. data/spec/functional/logger_spec.rb +20 -0
  149. data/spec/functional/modifiers_spec.rb +446 -0
  150. data/spec/functional/options_hash_spec.rb +41 -0
  151. data/spec/functional/pagination_spec.rb +89 -0
  152. data/spec/functional/partial_updates_spec.rb +530 -0
  153. data/spec/functional/protected_spec.rb +199 -0
  154. data/spec/functional/querying_spec.rb +984 -0
  155. data/spec/functional/rails_spec.rb +55 -0
  156. data/spec/functional/sci_spec.rb +374 -0
  157. data/spec/functional/scopes_spec.rb +204 -0
  158. data/spec/functional/static_keys_spec.rb +153 -0
  159. data/spec/functional/timestamps_spec.rb +97 -0
  160. data/spec/functional/touch_spec.rb +125 -0
  161. data/spec/functional/userstamps_spec.rb +46 -0
  162. data/spec/functional/validations_spec.rb +416 -0
  163. data/spec/quality_spec.rb +51 -0
  164. data/spec/spec_helper.rb +150 -0
  165. data/spec/support/matchers.rb +15 -0
  166. data/spec/support/models.rb +256 -0
  167. data/spec/symbol_operator_spec.rb +70 -0
  168. data/spec/symbol_spec.rb +9 -0
  169. data/spec/unit/associations/base_spec.rb +146 -0
  170. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  171. data/spec/unit/associations/many_association_spec.rb +64 -0
  172. data/spec/unit/associations/one_association_spec.rb +48 -0
  173. data/spec/unit/associations/proxy_spec.rb +103 -0
  174. data/spec/unit/clone_spec.rb +79 -0
  175. data/spec/unit/config_generator_spec.rb +24 -0
  176. data/spec/unit/criteria_hash_spec.rb +218 -0
  177. data/spec/unit/document_spec.rb +251 -0
  178. data/spec/unit/dynamic_finder_spec.rb +125 -0
  179. data/spec/unit/embedded_document_spec.rb +676 -0
  180. data/spec/unit/equality_spec.rb +38 -0
  181. data/spec/unit/exceptions_spec.rb +12 -0
  182. data/spec/unit/extensions_spec.rb +368 -0
  183. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  184. data/spec/unit/inspect_spec.rb +47 -0
  185. data/spec/unit/key_spec.rb +276 -0
  186. data/spec/unit/keys_spec.rb +155 -0
  187. data/spec/unit/mark_mapper_spec.rb +37 -0
  188. data/spec/unit/model_generator_spec.rb +45 -0
  189. data/spec/unit/normalizers/criteria_hash_key_spec.rb +37 -0
  190. data/spec/unit/normalizers/criteria_hash_value_spec.rb +200 -0
  191. data/spec/unit/normalizers/fields_value_spec.rb +45 -0
  192. data/spec/unit/normalizers/hash_key_spec.rb +15 -0
  193. data/spec/unit/normalizers/integer_spec.rb +24 -0
  194. data/spec/unit/normalizers/options_hash_value_spec.rb +99 -0
  195. data/spec/unit/normalizers/sort_value_spec.rb +98 -0
  196. data/spec/unit/options_hash_spec.rb +64 -0
  197. data/spec/unit/pagination/collection_spec.rb +30 -0
  198. data/spec/unit/pagination/paginator_spec.rb +118 -0
  199. data/spec/unit/pagination_spec.rb +11 -0
  200. data/spec/unit/plugins_spec.rb +89 -0
  201. data/spec/unit/query_spec.rb +837 -0
  202. data/spec/unit/rails_compatibility_spec.rb +40 -0
  203. data/spec/unit/rails_reflect_on_association_spec.rb +118 -0
  204. data/spec/unit/rails_spec.rb +188 -0
  205. data/spec/unit/serialization_spec.rb +169 -0
  206. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  207. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  208. data/spec/unit/time_zones_spec.rb +44 -0
  209. data/spec/unit/translation_spec.rb +27 -0
  210. data/spec/unit/validations_spec.rb +588 -0
  211. metadata +307 -0
@@ -0,0 +1,207 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OneEmbeddedPolymorhpicProxy" do
4
+ before do
5
+ @post_class = Doc('Post') do
6
+ key :title, String
7
+ end
8
+ end
9
+
10
+ it "should default to nil" do
11
+ @post_class.one :author, :polymorphic => true, :class => Robot
12
+ @post_class.new.author.should be_nil
13
+ end
14
+
15
+ it "should return nil instead of a proxy" do
16
+ @post_class.one :author, :polymorphic => true, :class => Robot
17
+ nil.should === @post_class.new.author
18
+ end
19
+
20
+ it "should be able to build" do
21
+ @post_class.one :author, :polymorphic => true, :class => Robot
22
+ post = @post_class.create
23
+ author = post.build_author(:serial_number => "1B")
24
+ post.author.should be_instance_of(Robot)
25
+ post.author.should be_new
26
+ post.author.serial_number.should == '1B'
27
+ post.author.should == author
28
+ post.author.post.should == post
29
+ end
30
+
31
+ it "should allow assignment of associated document using a hash" do
32
+ @post_class.one :author, :polymorphic => :true, :class => Robot
33
+
34
+ post = @post_class.new('author' => { 'name' => 'Frank', '_type' => 'Human' })
35
+ post.author.name.should == 'Frank'
36
+ post.author.class.should == Human
37
+
38
+ post.save.should be_truthy
39
+ post.reload
40
+
41
+ post.author.name.should == 'Frank'
42
+ post.author.class.should == Human
43
+ end
44
+
45
+ context "replacing the association" do
46
+ context "with an object" do
47
+ before do
48
+ @post_class.one :author, :polymorphic => true, :class => Robot
49
+ @post = @post_class.create
50
+ @human = Human.new(:name => 'Frank')
51
+ end
52
+
53
+ it "should work" do
54
+ @post.author = @human
55
+ @post.save
56
+ @post.reload
57
+
58
+ @post.author.should == @human
59
+ @post.author.nil?.should be_falsey
60
+ @post.author.class.should == Human
61
+
62
+ new_human = Human.new(:name => 'Emily')
63
+ @post.author = new_human
64
+ @post.author.should == new_human
65
+ end
66
+
67
+ it "should generate a new proxy instead of modifying the existing one" do
68
+ @post.author = @human
69
+ @post.save
70
+ @post.reload
71
+
72
+ @post.author.should == @human
73
+ @post.author.nil?.should be_falsey
74
+
75
+ original_author = @post.author
76
+ original_author.name.should == 'Frank'
77
+ new_human = Human.new(:name => 'Emily')
78
+ @post.author = new_human
79
+ @post.author.should == new_human
80
+
81
+ original_author.name.should == 'Frank'
82
+ end
83
+
84
+ it "should assign _type" do
85
+ @post.author = @human
86
+ @post.author._type.should == "Human"
87
+ end
88
+ end
89
+
90
+ context "with a Hash" do
91
+ before do
92
+ @post_class.one :author, :polymorphic => true, :class => Robot
93
+ @post = @post_class.create
94
+ end
95
+
96
+ it "should convert to an object of the class and work" do
97
+ @post.author = {'serial_number' => '1B'}
98
+ @post.save
99
+ @post.reload
100
+
101
+ @post.author.serial_number.should == '1B'
102
+ @post.author.nil?.should be_falsey
103
+
104
+ @post.author = {'serial_number' => '2C'}
105
+ @post.author.serial_number.should == '2C'
106
+ end
107
+
108
+ it "should convert to an object of _type if given" do
109
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
110
+ @post.author.name.should == 'Frank'
111
+ @post.author.class.should == Human
112
+ @post.save
113
+ @post.reload
114
+
115
+ @post.author.name.should == 'Frank'
116
+ @post.author.class.should == Human
117
+ end
118
+
119
+ it "should assign _type" do
120
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
121
+ @post.save
122
+ @post.reload
123
+ @post.author._type.should == "Human"
124
+ end
125
+ end
126
+ end
127
+
128
+ it "should unset the association" do
129
+ @post_class.one :author, :polymorphic => true, :class => Robot
130
+ post = @post_class.create
131
+ human = Human.new
132
+ post.update_attributes!(:author => human)
133
+ post.reload
134
+ post.author = nil
135
+ post.author.should == nil
136
+ end
137
+
138
+ it "should set modularized associated models correctly" do
139
+ @post_class.one :author, :polymorphic => true, :class => Robot
140
+
141
+ post = @post_class.new('author' => {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true})
142
+
143
+ post.author.class.should == TrModels::Ambulance
144
+ post.author.license_plate.should == 'GGG123'
145
+ post.author.icu.should be_truthy
146
+ post.save.should be_truthy
147
+
148
+ post = post.reload
149
+ post.author.class.should == TrModels::Ambulance
150
+ post.author.license_plate.should == 'GGG123'
151
+ post.author.icu.should be_truthy
152
+ end
153
+
154
+ it "should not have problem loading root document if embedded one is nil" do
155
+ @post_class.one :author, :polymorphic => true, :class => Robot
156
+ post = @post_class.create
157
+
158
+ lambda {
159
+ @post_class.find(post.id)
160
+ }.should_not raise_error
161
+ end
162
+
163
+ it "should load the parent and root documents for nested embedded documents" do
164
+ @address_class = EDoc('Address') do
165
+ key :city, String
166
+ key :state, String
167
+ end
168
+ @author_class = EDoc('EmbeddedAuthor')
169
+ @author_class.one :address, :polymorphic => true, :class => @address_class
170
+ @post_class.one :author, :polymorphic => true, :class => @author_class
171
+
172
+ post = @post_class.create(:title => 'Post Title', :author => { :name => 'Frank', :address => { :city => 'Boston', :state => 'MA' } })
173
+
174
+ post.author.address._parent_document.should == post.author
175
+ post.author.address._root_document.should == post
176
+ end
177
+
178
+ it "should have boolean method for testing presence" do
179
+ @post_class.one :author, :polymorphic => true, :class => Robot
180
+
181
+ post = @post_class.new
182
+ post.author?.should be_falsey
183
+
184
+ post.author = Human.new(:name => 'Frank')
185
+ post.author?.should be_truthy
186
+ end
187
+
188
+ it "should initialize id for nested embedded document created from hash" do
189
+ @address_class = EDoc('Address') do
190
+ key :city, String
191
+ key :state, String
192
+ end
193
+ @author_class = EDoc('EmbeddedAuthor')
194
+ @author_class.one :address, :polymorphic => true, :class => @address_class
195
+ @post_class.one :author, :polymorphic => true, :class => @author_class
196
+
197
+ post = @post_class.create(:title => 'Post Title', :author => {
198
+ :name => 'Frank',
199
+ :address => {
200
+ :city => 'Boston',
201
+ :state => 'MA'
202
+ }
203
+ })
204
+
205
+ post.author.address.id.should_not be_nil
206
+ end
207
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OneEmbeddedProxy" do
4
+ before do
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
+ it "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
+ it "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
+ it "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_falsey
42
+
43
+ new_author = @author_class.new(:name => 'Emily')
44
+ post.author = new_author
45
+ post.author.should == new_author
46
+ end
47
+
48
+ it "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
+ it "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
+ it "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_falsey
76
+
77
+ post.author = @author_class.new(:name => 'Frank')
78
+ post.author?.should be_truthy
79
+ end
80
+
81
+ it "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,406 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OneProxy" do
4
+ before do
5
+ @post_class = Doc('Post')
6
+ @author_class = Doc do
7
+ key :name, String
8
+ key :post_id, ObjectId
9
+ end
10
+ end
11
+
12
+ it "should default to nil" do
13
+ @post_class.one :author, :class => @author_class
14
+ @post_class.new.author.nil?.should be_truthy
15
+ end
16
+
17
+ it "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
+ it "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_truthy
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
+ it "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_falsey
46
+
47
+ new_author = @author_class.new(:name => 'Emily')
48
+ post.author = new_author
49
+ post.author.should == new_author
50
+ end
51
+
52
+ it "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_falsey
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
+ it "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_falsey
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
+ before 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
+ it "should call delete on the existing document" do
100
+ expect_any_instance_of(@author_class).to receive(:delete).once
101
+ @post.author = @author_class.new
102
+ end
103
+
104
+ it "should remove the existing document from the database" do
105
+ @post.author = @author_class.new
106
+ lambda { @author.reload }.should raise_error(MarkMapper::DocumentNotFound)
107
+ end
108
+
109
+ it "should do nothing if it's the same document" do
110
+ expect_any_instance_of(@author_class).to receive(:delete).never
111
+ @post.author = @author
112
+ end
113
+ end
114
+
115
+ context "=> destory" do
116
+ before 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
+ it "should call destroy the existing document" do
125
+ expect_any_instance_of(@author_class).to receive(:destroy).once
126
+ @post.author = @author_class.new
127
+ end
128
+
129
+ it "should remove the existing document from the database" do
130
+ @post.author = @author_class.new
131
+ lambda { @author.reload }.should raise_error(MarkMapper::DocumentNotFound)
132
+ end
133
+
134
+ it "should do nothing if it's the same document" do
135
+ expect_any_instance_of(@author_class).to receive(:destroy).never
136
+ @post.author = @author
137
+ end
138
+ end
139
+
140
+ context "=> nullify" do
141
+ before 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
+ it "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
+ it "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
+ it "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
+ before 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
+ it "should nullify the existing document" do
194
+ @post.author = nil
195
+ @author.reload
196
+ @author.post_id.should be_nil
197
+ end
198
+
199
+ it "should set the target to nil" do
200
+ @post.author = nil
201
+ @post.author.should == nil
202
+ end
203
+ end
204
+ end
205
+
206
+ it "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_falsey
211
+
212
+ post.author = @author_class.new(:name => 'Frank')
213
+ post.author?.should be_truthy
214
+ end
215
+
216
+ it "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
+ it "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_truthy
236
+ end
237
+
238
+ context "destroying parent with :dependent" do
239
+ context "=> destroy" do
240
+ before 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
+ it "should should call destroy on the associated documents" do
249
+ expect_any_instance_of(@author_class).to receive(:destroy).once
250
+ @post.destroy
251
+ end
252
+
253
+ it "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
+ before 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
+ it "should should call delete the associated documents" do
271
+ expect_any_instance_of(@author_class).to receive(:delete).once
272
+ @post.destroy
273
+ end
274
+
275
+ it "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
+ it "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
+ it "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
+ context "when building associations" do
321
+ before do
322
+ @post_class.one :author, :class => @author_class
323
+ end
324
+ let(:post) { @post_class.create }
325
+
326
+ context "#build" do
327
+ it "should work" do
328
+ author = post.build_author(:name => 'John')
329
+ post.author.should be_instance_of(@author_class)
330
+ post.author.should be_new
331
+ post.author.name.should == 'John'
332
+ post.author.should == author
333
+ post.author.post_id.should == post.id
334
+ end
335
+
336
+ it "should allow a block" do
337
+ author = post.build_author do |doc|
338
+ doc.name = "John"
339
+ end
340
+ author.name.should == "John"
341
+ end
342
+ end
343
+
344
+ context "#create" do
345
+ it "should work" do
346
+ author = post.create_author(:name => 'John')
347
+ post.author.should be_instance_of(@author_class)
348
+ post.author.should_not be_new
349
+ post.author.name.should == 'John'
350
+ post.author.should == author
351
+ post.author.post_id.should == post.id
352
+ end
353
+
354
+ it "should allow a block" do
355
+ author = post.create_author do |doc|
356
+ doc.name = "John"
357
+ end
358
+ author.name.should == "John"
359
+ end
360
+ end
361
+
362
+
363
+ context "#create!" do
364
+ before do
365
+ @author_class.key :name, String, :required => true
366
+ end
367
+
368
+ it "should raise exception if invalid" do
369
+ expect {
370
+ post.create_author!
371
+ }.to raise_error(MarkMapper::DocumentNotValid)
372
+ end
373
+
374
+ it "should work if valid" do
375
+ author = post.create_author!(:name => 'John')
376
+ post.author.should be_instance_of(@author_class)
377
+ post.author.should_not be_new
378
+ post.author.name.should == 'John'
379
+ post.author.should == author
380
+ post.author.post_id.should == post.id
381
+ end
382
+
383
+ it "should accept a block" do
384
+ author = post.create_author! do |doc|
385
+ doc.name = "John"
386
+ end
387
+ author.name.should == "John"
388
+ end
389
+ end
390
+ end
391
+
392
+ context "namespaced foreign keys" do
393
+ before do
394
+ News::Paper.one :article, :class_name => 'News::Article'
395
+ News::Article.belongs_to :paper, :class_name => 'News::Paper'
396
+
397
+ @paper = News::Paper.create
398
+ end
399
+
400
+ it "should properly infer the foreign key" do
401
+ article = @paper.create_article
402
+ article.should respond_to(:paper_id)
403
+ article.paper_id.should == @paper.id
404
+ end
405
+ end
406
+ end