mark_mapper 0.0.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 (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,302 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ManyPolymorphicProxy" do
4
+ before do
5
+ Room.collection.remove
6
+ Message.collection.remove
7
+ end
8
+
9
+ it "should default reader to empty array" do
10
+ Room.new.messages.should == []
11
+ end
12
+
13
+ it "should add type key to polymorphic class base" do
14
+ Message.keys.keys.should include('_type')
15
+ end
16
+
17
+ it "should allow adding to assiciation like it was an array" do
18
+ room = Room.new
19
+ room.messages << Enter.new
20
+ room.messages.push Exit.new
21
+ room.messages.concat Exit.new
22
+ room.messages.size.should == 3
23
+ end
24
+
25
+ it "should be able to replace the association" do
26
+ room = Room.create(:name => 'Lounge')
27
+
28
+ lambda {
29
+ room.messages = [
30
+ Enter.new(:body => 'John entered room', :position => 1),
31
+ Chat.new(:body => 'Heyyyoooo!', :position => 2),
32
+ Exit.new(:body => 'John exited room', :position => 3)
33
+ ]
34
+ }.should change { Message.count }.by(3)
35
+
36
+ room = room.reload
37
+ messages = room.messages.all :order => "position"
38
+ messages.size.should == 3
39
+ messages[0].body.should == 'John entered room'
40
+ messages[1].body.should == 'Heyyyoooo!'
41
+ messages[2].body.should == 'John exited room'
42
+ end
43
+
44
+ it "should correctly store type when using <<, push and concat" do
45
+ room = Room.new
46
+ room.messages << Enter.new(:body => 'John entered the room', :position => 1)
47
+ room.messages.push Exit.new(:body => 'John entered the room', :position => 2)
48
+ room.messages.concat Chat.new(:body => 'Holla!' , :position => 3)
49
+
50
+ room = room.reload
51
+ messages = room.messages.all :order => "position"
52
+ messages[0]._type.should == 'Enter'
53
+ messages[1]._type.should == 'Exit'
54
+ messages[2]._type.should == 'Chat'
55
+ end
56
+
57
+ context "build" do
58
+ it "should assign foreign key" do
59
+ room = Room.create
60
+ message = room.messages.build
61
+ message.room_id.should == room._id
62
+ end
63
+
64
+ it "should assign _type" do
65
+ room = Room.create
66
+ message = room.messages.build
67
+ message._type.should == 'Message'
68
+ end
69
+
70
+ it "should allow assigning attributes" do
71
+ room = Room.create
72
+ message = room.messages.build(:body => 'Foo!')
73
+ message.body.should == 'Foo!'
74
+ end
75
+ end
76
+
77
+ context "create" do
78
+ it "should assign foreign key" do
79
+ room = Room.create
80
+ message = room.messages.create
81
+ message.room_id.should == room._id
82
+ end
83
+
84
+ it "should assign _type" do
85
+ room = Room.create
86
+ message = room.messages.create
87
+ message._type.should == 'Message'
88
+ end
89
+
90
+ it "should save record" do
91
+ room = Room.create
92
+ lambda {
93
+ room.messages.create
94
+ }.should change { Message.count }
95
+ end
96
+
97
+ it "should allow passing attributes" do
98
+ room = Room.create
99
+ message = room.messages.create(:body => 'Foo!')
100
+ message.body.should == 'Foo!'
101
+ end
102
+ end
103
+
104
+ context "count" do
105
+ it "should work scoped to association" do
106
+ room = Room.create
107
+ 3.times { room.messages.create }
108
+
109
+ other_room = Room.create
110
+ 2.times { other_room.messages.create }
111
+
112
+ room.messages.count.should == 3
113
+ other_room.messages.count.should == 2
114
+ end
115
+
116
+ it "should work with conditions" do
117
+ room = Room.create
118
+ room.messages.create(:body => 'Foo')
119
+ room.messages.create(:body => 'Other 1')
120
+ room.messages.create(:body => 'Other 2')
121
+
122
+ room.messages.count(:body => 'Foo').should == 1
123
+ end
124
+ end
125
+
126
+ context "Finding scoped to association" do
127
+ before do
128
+ @lounge = Room.create(:name => 'Lounge')
129
+ @lm1 = Message.create(:body => 'Loungin!', :position => 1)
130
+ @lm2 = Message.create(:body => 'I love loungin!', :position => 2)
131
+ @lounge.messages = [@lm1, @lm2]
132
+ @lounge.save
133
+
134
+ @hall = Room.create(:name => 'Hall')
135
+ @hm1 = Message.create(:body => 'Do not fall in the hall', :position => 1)
136
+ @hm3 = Message.create(:body => 'Loungin!', :position => 3)
137
+ @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
138
+ @hall.messages = [@hm1, @hm2, @hm3]
139
+ @hall.save
140
+ @hall.reload
141
+ end
142
+
143
+ context "dynamic finders" do
144
+ it "should work with single key" do
145
+ @lounge.messages.find_by_position(1).should == @lm1
146
+ @hall.messages.find_by_position(2).should == @hm2
147
+ end
148
+
149
+ it "should work with multiple keys" do
150
+ @lounge.messages.find_by_body_and_position('Loungin!', 1).should == @lm1
151
+ @lounge.messages.find_by_body_and_position('Loungin!', 2).should be_nil
152
+ end
153
+
154
+ it "should raise error when using !" do
155
+ lambda {
156
+ @lounge.messages.find_by_position!(222)
157
+ }.should raise_error(MarkMapper::DocumentNotFound)
158
+ end
159
+
160
+ context "find_or_create_by" do
161
+ it "should not create document if found" do
162
+ lambda {
163
+ message = @lounge.messages.find_or_create_by_body('Loungin!')
164
+ message.room.should == @lounge
165
+ message.should == @lm1
166
+ }.should_not change { Message.count }
167
+ end
168
+
169
+ it "should create document if not found" do
170
+ lambda {
171
+ message = @lounge.messages.find_or_create_by_body('Yo dawg!')
172
+ message.room.should == @lounge
173
+ message._type.should == 'Message'
174
+ }.should change { Message.count }.by(1)
175
+ end
176
+ end
177
+ end
178
+
179
+ context "with #all" do
180
+ it "should work" do
181
+ @lounge.messages.all(:order => "position").should == [@lm1, @lm2]
182
+ end
183
+
184
+ it "should work with conditions" do
185
+ messages = @lounge.messages.all(:body => 'Loungin!', :order => "position")
186
+ messages.should == [@lm1]
187
+ end
188
+
189
+ it "should work with order" do
190
+ messages = @lounge.messages.all(:order => 'position desc')
191
+ messages.should == [@lm2, @lm1]
192
+ end
193
+ end
194
+
195
+ context "with #first" do
196
+ it "should work" do
197
+ @lounge.messages.first(:order => "position asc").should == @lm1
198
+ end
199
+
200
+ it "should work with conditions" do
201
+ message = @lounge.messages.first(:body => 'I love loungin!', :order => "position asc")
202
+ message.should == @lm2
203
+ end
204
+ end
205
+
206
+ context "with #last" do
207
+ it "should work" do
208
+ @lounge.messages.last(:order => "position asc").should == @lm2
209
+ end
210
+
211
+ it "should work with conditions" do
212
+ message = @lounge.messages.last(:body => 'Loungin!', :order => "position asc")
213
+ message.should == @lm1
214
+ end
215
+ end
216
+
217
+ context "with one id" do
218
+ it "should work for id in association" do
219
+ @lounge.messages.find(@lm2._id).should == @lm2
220
+ end
221
+
222
+ it "should not work for id not in association" do
223
+ lambda {
224
+ @lounge.messages.find!(@hm2._id)
225
+ }.should raise_error(MarkMapper::DocumentNotFound)
226
+ end
227
+ end
228
+
229
+ context "with query options/criteria" do
230
+ it "should work with order on association" do
231
+ @lounge.messages.should == [@lm1, @lm2]
232
+ end
233
+
234
+ it "should allow overriding the order provided to the association" do
235
+ @lounge.messages.all(:order => 'position').should == [@lm1, @lm2]
236
+ end
237
+
238
+ it "should allow using conditions on association" do
239
+ @hall.latest_messages.should == [@hm3, @hm2]
240
+ end
241
+ end
242
+
243
+ context "with multiple ids" do
244
+ it "should work for ids in association" do
245
+ messages = @lounge.messages.find(@lm1._id, @lm2._id)
246
+ messages.should == [@lm1, @lm2]
247
+ end
248
+
249
+ it "should not work for ids not in association" do
250
+ expect {
251
+ @lounge.messages.find!(@lm1._id, @lm2._id, @hm2._id)
252
+ }.to raise_error(MarkMapper::DocumentNotFound)
253
+ end
254
+ end
255
+
256
+ context "with #paginate" do
257
+ before do
258
+ @messages = @hall.messages.paginate(:per_page => 2, :page => 1, :order => 'position asc')
259
+ end
260
+
261
+ it "should return total pages" do
262
+ @messages.total_pages.should == 2
263
+ end
264
+
265
+ it "should return total entries" do
266
+ @messages.total_entries.should == 3
267
+ end
268
+
269
+ it "should return the subject" do
270
+ @messages.should == [@hm1, @hm2]
271
+ end
272
+ end
273
+ end
274
+
275
+ context "extending the association" do
276
+ it "should work using a block passed to many" do
277
+ room = Room.new(:name => "Amazing Room")
278
+ messages = room.messages = [
279
+ Enter.new(:body => 'John entered room', :position => 3),
280
+ Chat.new(:body => 'Heyyyoooo!', :position => 4),
281
+ Exit.new(:body => 'John exited room', :position => 5),
282
+ Enter.new(:body => 'Steve entered room', :position => 6),
283
+ Chat.new(:body => 'Anyone there?', :position => 7),
284
+ Exit.new(:body => 'Steve exited room', :position => 8)
285
+ ]
286
+ room.save
287
+ room.messages.older.should == messages[3..5]
288
+ end
289
+
290
+ it "should work using many's :extend option" do
291
+
292
+ room = Room.new(:name => "Amazing Room")
293
+ accounts = room.accounts = [
294
+ Bot.new(:last_logged_in => 3.weeks.ago),
295
+ AccountUser.new(:last_logged_in => nil),
296
+ Bot.new(:last_logged_in => 1.week.ago)
297
+ ]
298
+ room.save
299
+ room.accounts.inactive.should == [accounts[1]]
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,489 @@
1
+ require 'spec_helper'
2
+ require 'support/models'
3
+
4
+ describe "OneAsProxy" do
5
+ before do
6
+ @post_class = Doc('Post')
7
+ @author_class = Doc('Author')
8
+ end
9
+
10
+ it "should default to nil" do
11
+ @post_class.one :author, :as => :authorable, :class => @author_class
12
+ @post_class.new.author.nil?.should be_truthy
13
+ end
14
+
15
+ it "should return nil instead of a proxy" do
16
+ @post_class.one :author, :as => :authorable, :class => @author_class
17
+ nil.should === @post_class.new.author
18
+ end
19
+
20
+ it "should not define any keys" do
21
+ count = @post_class.keys.length
22
+ @post_class.one :author, :class => @author_class
23
+ @post_class.keys.length.should == count
24
+ end
25
+
26
+ it "should allow assignment of associated document using a hash" do
27
+ @post_class.one :author, :as => :authorable, :class => @author_class
28
+
29
+ post = @post_class.new('author' => { 'name' => 'Frank' })
30
+ post.author.name.should == 'Frank'
31
+
32
+ post.save.should be_truthy
33
+ post.reload
34
+
35
+ post.author.name.should == 'Frank'
36
+ end
37
+
38
+ it "should only return a document with the correct type" do
39
+ @post_class.one :author, :as => :authorable, :class => @author_class
40
+ post = @post_class.create
41
+
42
+ author = @author_class.create(:authorable_id => post.id, :authorable_type => "Nada")
43
+ post.reload.author.should be_nil
44
+
45
+ author = @author_class.create(:authorable_id => post.id, :authorable_type => "Post")
46
+ post.reload.author.should == author
47
+ end
48
+
49
+ context "replacing the association" do
50
+ context "with an object of the class" do
51
+ before do
52
+ @post_class.one :author, :as => :authorable, :class => @author_class
53
+ @post = @post_class.new
54
+ @author = @author_class.new(:name => 'Frank')
55
+ end
56
+
57
+ it "should work" do
58
+ @post.author = @author
59
+ @post.reload
60
+
61
+ @post.author.should == @author
62
+ @post.author.nil?.should be_falsey
63
+
64
+ new_author = @author_class.new(:name => 'Emily')
65
+ @post.author = new_author
66
+ @post.author.should == new_author
67
+ end
68
+
69
+ it "should generate a new proxy instead of modifying the existing one" do
70
+ @post.author = @author
71
+ @post.reload
72
+
73
+ @post.author.should == @author
74
+ @post.author.nil?.should be_falsey
75
+
76
+ original_author = @post.author
77
+ original_author.name.should == 'Frank'
78
+ new_author = @author_class.new(:name => 'Emily')
79
+ @post.author = new_author
80
+ @post.author.should == new_author
81
+
82
+ original_author.name.should == 'Frank'
83
+ end
84
+
85
+ it "should assign foreign key" do
86
+ @post.author = @author
87
+ @post.author.authorable_id.should == @post.id
88
+ end
89
+
90
+ it "should assign _type" do
91
+ @post.author = @author
92
+ @post.author.authorable_type.should == "Post"
93
+ end
94
+ end
95
+
96
+ context "with a Hash" do
97
+ before do
98
+ @post_class.one :author, :as => :authorable, :class => @author_class
99
+ @post = @post_class.new
100
+ end
101
+
102
+ it "should convert to an object of the class and work" do
103
+ @post.author = {'name' => 'Frank'}
104
+ @post.reload
105
+
106
+ @post.author.name.should == 'Frank'
107
+ @post.author.nil?.should be_falsey
108
+
109
+ @post.author = {'name' => 'Emily'}
110
+ @post.author.name.should == 'Emily'
111
+ end
112
+
113
+ it "should assign foreign key" do
114
+ @post.author = {'name' => 'Frank'}
115
+ @post.author.authorable_id.should == @post.id
116
+ end
117
+
118
+ it "should assign _type" do
119
+ @post.author = {'name' => 'Frank'}
120
+ @post.author.authorable_type.should == "Post"
121
+ end
122
+ end
123
+
124
+ context "with :dependent" do
125
+ context "=> delete" do
126
+ before do
127
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :delete
128
+
129
+ @post = @post_class.create
130
+ @author = @author_class.new
131
+ @post.author = @author
132
+ end
133
+
134
+ it "should call delete on the existing document" do
135
+ expect_any_instance_of(@author_class).to receive(:delete).once
136
+ @post.author = @author_class.new
137
+ end
138
+
139
+ it "should remove the existing document from the database" do
140
+ @post.author = @author_class.new
141
+ lambda { @author.reload }.should raise_error(MarkMapper::DocumentNotFound)
142
+ end
143
+
144
+ it "should do nothing if it's the same document" do
145
+ expect_any_instance_of(@author_class).to receive(:delete).never
146
+ @post.author = @author
147
+ end
148
+ end
149
+
150
+ context "=> destory" do
151
+ before do
152
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :destroy
153
+
154
+ @post = @post_class.create
155
+ @author = @author_class.new
156
+ @post.author = @author
157
+ end
158
+
159
+ it "should call destroy the existing document" do
160
+ expect_any_instance_of(@author_class).to receive(:destroy).once
161
+ @post.author = @author_class.new
162
+ end
163
+
164
+ it "should remove the existing document from the database" do
165
+ @post.author = @author_class.new
166
+ lambda { @author.reload }.should raise_error(MarkMapper::DocumentNotFound)
167
+ end
168
+
169
+ it "should do nothing if it's the same document" do
170
+ expect_any_instance_of(@author_class).to receive(:destroy).never
171
+ @post.author = @author
172
+ end
173
+ end
174
+
175
+ context "=> nullify" do
176
+ before do
177
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :nullify
178
+
179
+ @post = @post_class.create
180
+ @author = @author_class.new
181
+ @post.author = @author
182
+ end
183
+
184
+ it "should nullify the existing document" do
185
+ @author.reload
186
+ @author.authorable_id.should == @post.id
187
+
188
+ @post.author = @author_class.new
189
+
190
+ @author.reload
191
+ @author.authorable_id.should be_nil
192
+ end
193
+
194
+ it "should work when it's the same document" do
195
+ old_author = @post.author
196
+ @post.author = @author
197
+ old_author.should == @post.author
198
+ end
199
+
200
+ it "should nullify _type" do
201
+ @post.author = @author_class.new
202
+ @author.reload
203
+ @author.authorable_type.should be_nil
204
+ end
205
+ end
206
+
207
+ context "unspecified" do
208
+ before do
209
+ @post_class.one :author, :as => :authorable, :class => @author_class
210
+
211
+ @post = @post_class.create
212
+ @author = @author_class.new
213
+ @post.author = @author
214
+ end
215
+
216
+ it "should nullify the existing document" do
217
+ @author.reload
218
+ @author.authorable_id.should == @post.id
219
+
220
+ @post.author = @author_class.new
221
+
222
+ @author.reload
223
+ @author.authorable_id.should be_nil
224
+ end
225
+
226
+ it "should nullify _type" do
227
+ @post.author = @author_class.new
228
+ @author.reload
229
+ @author.authorable_type.should be_nil
230
+ end
231
+ end
232
+ end
233
+
234
+ context "with nil" do
235
+ before do
236
+ @post_class.one :author, :as => :authorable, :class => @author_class
237
+
238
+ @post = @post_class.new
239
+ @author = @author_class.new(:name => 'Frank')
240
+ @post.author = @author
241
+ end
242
+
243
+ it "should nullify the existing document" do
244
+ @post.author = nil
245
+ @author.reload
246
+ @author.authorable_id.should be_nil
247
+ end
248
+
249
+ it "should set the target to nil" do
250
+ @post.author = nil
251
+ @post.author.should == nil
252
+ end
253
+
254
+ it "should nullify _type" do
255
+ @post.author = nil
256
+ @author.reload
257
+ @author.authorable_type.should be_nil
258
+ end
259
+ end
260
+ end
261
+
262
+ it "should have boolean method for testing presence" do
263
+ @post_class.one :author, :as => :authorable, :class => @author_class
264
+
265
+ post = @post_class.new
266
+ post.author?.should be_falsey
267
+
268
+ post.author = @author_class.new(:name => 'Frank')
269
+ post.author?.should be_truthy
270
+ end
271
+
272
+ it "should work with criteria" do
273
+ @post_class.one :primary_author, :as => :authorable, :class => @author_class, :primary => true
274
+ @post_class.one :author, :as => :authorable, :class => @author_class, :primary => false
275
+
276
+ post = @post_class.create
277
+ author = @author_class.create(:name => 'Frank', :primary => false, :authorable_id => post.id, :authorable_type => 'Post')
278
+ primary = @author_class.create(:name => 'Bill', :primary => true, :authorable_id => post.id, :authorable_type => 'Post')
279
+ post.reload
280
+ post.author.should == author
281
+ post.primary_author.should == primary
282
+ end
283
+
284
+ it "should unset the association" do
285
+ @post_class.one :author, :as => :authorable, :class => @author_class
286
+ post = @post_class.create
287
+ author = @author_class.create
288
+ post.update_attributes!(:author => author)
289
+ post.reload
290
+ post.author = nil
291
+ post.author.nil?.should be_truthy
292
+ end
293
+
294
+ context "destroying parent with :dependent" do
295
+ context "=> destroy" do
296
+ before do
297
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :destroy
298
+
299
+ @post = @post_class.create
300
+ @author = @author_class.new
301
+ @post.author = @author
302
+ end
303
+
304
+ it "should should call destroy on the associated documents" do
305
+ expect_any_instance_of(@author_class).to receive(:destroy).once
306
+ @post.destroy
307
+ end
308
+
309
+ it "should should remove the associated documents" do
310
+ @author_class.count.should == 1
311
+ @post.destroy
312
+ @post.author.should == nil
313
+ @author_class.count.should == 0
314
+ end
315
+ end
316
+
317
+ context "=> delete" do
318
+ before do
319
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :delete
320
+
321
+ @post = @post_class.create
322
+ @author = @author_class.new
323
+ @post.author = @author
324
+ end
325
+
326
+ it "should should call delete the associated documents" do
327
+ expect_any_instance_of(@author_class).to receive(:delete).once
328
+ @post.destroy
329
+ end
330
+
331
+ it "should remove the associated documents" do
332
+ @author_class.count.should == 1
333
+ @post.destroy
334
+ @post.author.should == nil
335
+ @author_class.count.should == 0
336
+ end
337
+ end
338
+
339
+ context "=> nullify" do
340
+ before do
341
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :nullify
342
+
343
+ @post = @post_class.create
344
+ @author = @author_class.new
345
+ @post.author = @author
346
+ end
347
+
348
+ it "should should nullify the relationship but not destroy the associated document" do
349
+ @author_class.count.should == 1
350
+ @post.destroy
351
+ @post.author.should == nil
352
+ @author_class.count.should == 1
353
+
354
+ @author_class.first.should == @author
355
+ @author.authorable_id.should == nil
356
+ end
357
+
358
+ it "should nullify _type" do
359
+ @post.destroy
360
+ @author.authorable_type.should be_nil
361
+ end
362
+ end
363
+
364
+ context "unspecified" do
365
+ before do
366
+ @post_class.one :author, :as => :authorable, :class => @author_class
367
+
368
+ @post = @post_class.create
369
+ @author = @author_class.new
370
+ @post.author = @author
371
+ end
372
+
373
+ it "should should nullify the relationship but not destroy the associated document" do
374
+ @author_class.count.should == 1
375
+ @post.destroy
376
+ @post.author.should == nil
377
+ @author_class.count.should == 1
378
+
379
+ @author_class.first.should == @author
380
+ @author.authorable_id.should == nil
381
+ end
382
+
383
+ it "should nullify _type" do
384
+ @post.destroy
385
+ @author.authorable_type.should be_nil
386
+ end
387
+ end
388
+ end
389
+
390
+ context "#build" do
391
+ before do
392
+ @post_class.one :author, :as => :authorable, :class => @author_class
393
+ @post = @post_class.create
394
+ end
395
+
396
+ it "should be able to build with attributes" do
397
+ author = @post.build_author(:name => 'John')
398
+ @post.author.should be_instance_of(@author_class)
399
+ @post.author.should be_new
400
+ @post.author.name.should == 'John'
401
+ @post.author.should == author
402
+ end
403
+
404
+ it "should assign foreign key" do
405
+ @post.build_author
406
+ @post.author.authorable_id.should == @post.id
407
+ end
408
+
409
+ it "should assign _type" do
410
+ @post.build_author
411
+ @post.author.authorable_type.should == 'Post'
412
+ end
413
+ end
414
+
415
+ context "#create" do
416
+ before do
417
+ @post_class.one :author, :as => :authorable, :class => @author_class
418
+ @post = @post_class.create
419
+ end
420
+
421
+ it "should be able to create" do
422
+ author = @post.create_author(:name => 'John')
423
+ @post.author.should be_instance_of(@author_class)
424
+ @post.author.should_not be_new
425
+ @post.author.name.should == 'John'
426
+ @post.author.should == author
427
+ end
428
+
429
+ it "should assign foreign key" do
430
+ @post.create_author
431
+ @post.author.authorable_id.should == @post.id
432
+ end
433
+
434
+ it "should assign _type" do
435
+ @post.create_author
436
+ @post.author.authorable_type.should == 'Post'
437
+ end
438
+ end
439
+
440
+ context "#create!" do
441
+ before do
442
+ @author_class.key :name, String, :required => true
443
+ @post_class.one :author, :as => :authorable, :class => @author_class
444
+ @post = @post_class.create
445
+ end
446
+
447
+ it "should raise exception if invalid" do
448
+ expect { @post.create_author! }.to raise_error(MarkMapper::DocumentNotValid)
449
+ end
450
+
451
+ it "should work if valid" do
452
+ author = @post.create_author!(:name => 'John')
453
+ @post.author.should be_instance_of(@author_class)
454
+ @post.author.should_not be_new
455
+ @post.author.name.should == 'John'
456
+ @post.author.should == author
457
+ end
458
+
459
+ it "should assign foreign key if valid" do
460
+ @post.create_author!(:name => 'John')
461
+ @post.author.authorable_id.should == @post.id
462
+ end
463
+
464
+ it "should assign _type if valid" do
465
+ @post.create_author!(:name => 'John')
466
+ @post.author.authorable_type.should == 'Post'
467
+ end
468
+ end
469
+
470
+ context "namespaced foreign keys" do
471
+ before do
472
+ News::Paper.one :article, :as => 'articleable', :class_name => 'News::Article'
473
+ News::Article.belongs_to :articleable, :polymorphic => true
474
+
475
+ @paper = News::Paper.create
476
+ end
477
+
478
+ it "should work" do
479
+ @paper.create_article
480
+ @paper.article.class.should == News::Article
481
+ end
482
+
483
+ it "should properly infer the foreign key" do
484
+ article = @paper.create_article
485
+ article.should respond_to(:articleable_id)
486
+ article.articleable_id.should == @paper.id
487
+ end
488
+ end
489
+ end