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,238 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ManyEmbeddedPolymorphicProxy" do
4
+ before do
5
+ Catalog.collection.remove
6
+ TrModels::Fleet.collection.remove
7
+ end
8
+
9
+ it "should default reader to empty array" do
10
+ catalog = Catalog.new
11
+ catalog.medias.should == []
12
+ end
13
+
14
+ it "should allow adding to association like it was an array" do
15
+ catalog = Catalog.new
16
+ catalog.medias << Video.new
17
+ catalog.medias.push Video.new
18
+ catalog.medias.size.should == 2
19
+ end
20
+
21
+ it "should be able to replace the association" do
22
+ catalog = Catalog.new
23
+ catalog.medias = [Video.new('file' => 'video.mpg', 'length' => 3600)]
24
+ catalog.save.should be_truthy
25
+
26
+ catalog = catalog.reload
27
+ catalog.medias.size.should == 1
28
+ catalog.medias[0].file.should == 'video.mpg'
29
+ catalog.medias[0].new?.should == false
30
+ end
31
+
32
+ context "associating objects of non-SCI class" do
33
+ it "should work on replacement" do
34
+ catalog = Catalog.new
35
+ catalog.medias = [Human.new(:name => 'Frank'), Robot.new(:serial_number => '1B')]
36
+
37
+ catalog.medias.size.should == 2
38
+ catalog.medias[0].name.should == 'Frank'
39
+ catalog.medias[0].class.should == Human
40
+ catalog.medias[1].serial_number.should == '1B'
41
+ catalog.medias[1].class.should == Robot
42
+
43
+ catalog.save.should be_truthy
44
+ catalog.reload
45
+
46
+ catalog.medias.size.should == 2
47
+ catalog.medias[0].name.should == 'Frank'
48
+ catalog.medias[0].class.should == Human
49
+ catalog.medias[1].serial_number.should == '1B'
50
+ catalog.medias[1].class.should == Robot
51
+ end
52
+
53
+ it "should work on replacement with hashes" do
54
+ catalog = Catalog.new
55
+ catalog.medias = [{:name => 'Frank', '_type' => 'Human'}, {:serial_number => '1B', '_type' => 'Robot'}]
56
+
57
+ catalog.medias.size.should == 2
58
+ catalog.medias[0].name.should == 'Frank'
59
+ catalog.medias[0].class.should == Human
60
+ catalog.medias[1].serial_number.should == '1B'
61
+ catalog.medias[1].class.should == Robot
62
+
63
+ catalog.save.should be_truthy
64
+ catalog.reload
65
+
66
+ catalog.medias.size.should == 2
67
+ catalog.medias[0].name.should == 'Frank'
68
+ catalog.medias[0].class.should == Human
69
+ catalog.medias[1].serial_number.should == '1B'
70
+ catalog.medias[1].class.should == Robot
71
+ end
72
+
73
+ it "should work with concatination" do
74
+ catalog = Catalog.new
75
+ catalog.medias << Human.new(:name => 'Frank')
76
+ catalog.medias << Robot.new(:serial_number => '1B')
77
+
78
+ catalog.medias.size.should == 2
79
+ catalog.medias[0].name.should == 'Frank'
80
+ catalog.medias[0].class.should == Human
81
+ catalog.medias[1].serial_number.should == '1B'
82
+ catalog.medias[1].class.should == Robot
83
+
84
+ catalog.save.should be_truthy
85
+ catalog.reload
86
+
87
+ catalog.medias.size.should == 2
88
+ catalog.medias[0].name.should == 'Frank'
89
+ catalog.medias[0].class.should == Human
90
+ catalog.medias[1].serial_number.should == '1B'
91
+ catalog.medias[1].class.should == Robot
92
+ end
93
+ end
94
+
95
+ context "count" do
96
+ it "should default to 0" do
97
+ Catalog.new.medias.count.should == 0
98
+ end
99
+
100
+ it 'should return correct count if any are embedded' do
101
+ catalog = Catalog.new
102
+ catalog.medias = [
103
+ Video.new('file' => 'video.mpg', 'length' => 3600),
104
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
105
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
106
+ ]
107
+ catalog.medias.count.should == 3
108
+ catalog.save.should be_truthy
109
+ catalog.reload
110
+ catalog.medias.count.should == 3
111
+ end
112
+ end
113
+
114
+ it "should store different associations" do
115
+ catalog = Catalog.new
116
+ catalog.medias = [
117
+ Video.new('file' => 'video.mpg', 'length' => 3600),
118
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
119
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
120
+ ]
121
+ catalog.save.should be_truthy
122
+
123
+ catalog = catalog.reload
124
+ catalog.medias.size.should == 3
125
+ catalog.medias[0].file.should == 'video.mpg'
126
+ catalog.medias[0].length.should == 3600
127
+ catalog.medias[1].file.should == 'music.mp3'
128
+ catalog.medias[1].bitrate.should == "128kbps"
129
+ catalog.medias[2].file.should == 'image.png'
130
+ catalog.medias[2].width.should == 800
131
+ catalog.medias[2].height.should == 600
132
+ end
133
+
134
+ context "With modularized models" do
135
+ it "should set associations correctly" do
136
+ fleet_attributes = {
137
+ 'name' => 'My Fleet',
138
+ 'transports' => [
139
+ {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true},
140
+ {'_type' => 'TrModels::Car', 'license_plate' => 'ABC123', 'model' => 'VW Golf', 'year' => 2001},
141
+ {'_type' => 'TrModels::Car', 'license_plate' => 'DEF123', 'model' => 'Honda Accord', 'year' => 2008},
142
+ ]
143
+ }
144
+
145
+ fleet = TrModels::Fleet.new(fleet_attributes)
146
+ fleet.transports.size.should == 3
147
+ fleet.transports[0].class.should == TrModels::Ambulance
148
+ fleet.transports[0].license_plate.should == 'GGG123'
149
+ fleet.transports[0].icu.should be_truthy
150
+ fleet.transports[1].class.should == TrModels::Car
151
+ fleet.transports[1].license_plate.should == 'ABC123'
152
+ fleet.transports[1].model.should == 'VW Golf'
153
+ fleet.transports[1].year.should == 2001
154
+ fleet.transports[2].class.should == TrModels::Car
155
+ fleet.transports[2].license_plate.should == 'DEF123'
156
+ fleet.transports[2].model.should == 'Honda Accord'
157
+ fleet.transports[2].year.should == 2008
158
+ fleet.save.should be_truthy
159
+
160
+ fleet = fleet.reload
161
+ fleet.transports.size.should == 3
162
+ fleet.transports[0].license_plate.should == 'GGG123'
163
+ fleet.transports[0].icu.should be_truthy
164
+ fleet.transports[1].license_plate.should == 'ABC123'
165
+ fleet.transports[1].model.should == 'VW Golf'
166
+ fleet.transports[1].year.should == 2001
167
+ fleet.transports[2].license_plate.should == 'DEF123'
168
+ fleet.transports[2].model.should == 'Honda Accord'
169
+ fleet.transports[2].year.should == 2008
170
+ end
171
+
172
+ it "should default reader to empty array" do
173
+ fleet = TrModels::Fleet.new
174
+ fleet.transports.should == []
175
+ end
176
+
177
+ it "should allow adding to association like it was an array" do
178
+ fleet = TrModels::Fleet.new
179
+ fleet.transports << TrModels::Car.new
180
+ fleet.transports.push TrModels::Bus.new
181
+ fleet.transports.size.should == 2
182
+ end
183
+
184
+ it "should be able to replace the association" do
185
+ fleet = TrModels::Fleet.new
186
+ fleet.transports = [TrModels::Car.new('license_plate' => 'DCU2013', 'model' => 'Honda Civic')]
187
+ fleet.save.should be_truthy
188
+
189
+ fleet = fleet.reload
190
+ fleet.transports.size.should == 1
191
+ fleet.transports[0].license_plate.should == 'DCU2013'
192
+ end
193
+
194
+ it "should store different associations" do
195
+ fleet = TrModels::Fleet.new
196
+ fleet.transports = [
197
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003),
198
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51),
199
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true)
200
+ ]
201
+ fleet.save.should be_truthy
202
+
203
+ fleet = fleet.reload
204
+ fleet.transports.size.should == 3
205
+ fleet.transports[0].license_plate.should == 'ABC1223'
206
+ fleet.transports[0].model.should == 'Honda Civic'
207
+ fleet.transports[0].year.should == 2003
208
+ fleet.transports[1].license_plate.should == 'XYZ9090'
209
+ fleet.transports[1].max_passengers.should == 51
210
+ fleet.transports[2].license_plate.should == 'HDD3030'
211
+ fleet.transports[2].icu.should == true
212
+ end
213
+ end
214
+
215
+ context "extending the association" do
216
+ it "should work using a block passed to many" do
217
+ catalog = Catalog.new
218
+ medias = catalog.medias = [
219
+ Video.new('file' => 'video.mpg', 'length' => 3600, :visible => true),
220
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps', :visible => true),
221
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600, :visible => false)
222
+ ]
223
+ catalog.save
224
+ catalog.medias.visible.should == [medias[0], medias[1]]
225
+ end
226
+
227
+ it "should work using many's :extend option" do
228
+ fleet = TrModels::Fleet.new
229
+ transports = fleet.transports = [
230
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003, :purchased_on => 2.years.ago.to_date),
231
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51, :purchased_on => 3.years.ago.to_date),
232
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true, :purchased_on => 1.year.ago.to_date)
233
+ ]
234
+ fleet.save
235
+ fleet.transports.to_be_replaced.should == [transports[1]]
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,288 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ManyEmbeddedProxy" do
4
+ before do
5
+ @comment_class = EDoc do
6
+ key :name, String
7
+ key :body, String
8
+ end
9
+ @post_class = Doc do
10
+ key :title, String
11
+ end
12
+ @post_class.many :comments, :class => @comment_class
13
+
14
+ @pet_class = EDoc do
15
+ key :name, String
16
+ end
17
+ @pet_class.embedded_in :person
18
+ @person_class = EDoc do
19
+ key :name, String
20
+ end
21
+ @person_class.key :child, @person_class
22
+ @person_class.many :pets, :class => @pet_class
23
+
24
+ @owner_class = Doc do
25
+ key :name, String
26
+ end
27
+ @owner_class.many :pets, :class => @pet_class
28
+ end
29
+
30
+ it "should default reader to empty array" do
31
+ @post_class.new.comments.should == []
32
+ end
33
+
34
+ it "should allow adding to association like it was an array" do
35
+ post = @post_class.new
36
+ post.comments << @comment_class.new
37
+ post.comments.push @comment_class.new
38
+ post.comments.size.should == 2
39
+ end
40
+
41
+ it "should be embedded in document on save" do
42
+ frank = @comment_class.new(:name => 'Frank', :body => 'Hi!')
43
+ bill = @comment_class.new(:name => 'Bill', :body => 'Hi!')
44
+ post = @post_class.new
45
+ post.comments << frank
46
+ post.comments << bill
47
+ post.save
48
+
49
+ post.reload
50
+ post.comments.size.should == 2
51
+ post.comments[0].should == frank
52
+ post.comments[0].new?.should == false
53
+ post.comments[1].should == bill
54
+ post.comments[1].new?.should == false
55
+ end
56
+
57
+ it "should allow embedding arbitrarily deep" do
58
+ @klass = Doc()
59
+ @klass.key :person, @person_class
60
+
61
+ meg = @person_class.new(:name => 'Meg')
62
+ meg.child = @person_class.new(:name => 'Steve')
63
+ meg.child.child = @person_class.new(:name => 'Linda')
64
+
65
+ doc = @klass.new(:person => meg)
66
+ doc.save
67
+ doc.reload
68
+
69
+ doc.person.name.should == 'Meg'
70
+ doc.person.child.name.should == 'Steve'
71
+ doc.person.child.child.name.should == 'Linda'
72
+ end
73
+
74
+ it "should allow assignment of many embedded documents using a hash" do
75
+ person_attributes = {
76
+ 'name' => 'Mr. Pet Lover',
77
+ 'pets' => [
78
+ {'name' => 'Jimmy', 'species' => 'Cocker Spainel'},
79
+ {'name' => 'Sasha', 'species' => 'Siberian Husky'},
80
+ ]
81
+ }
82
+
83
+ owner = @owner_class.new(person_attributes)
84
+ owner.name.should == 'Mr. Pet Lover'
85
+ owner.pets[0].id.class.should == MarkLogic::ObjectId
86
+ owner.pets[0].name.should == 'Jimmy'
87
+ owner.pets[0].species.should == 'Cocker Spainel'
88
+ owner.pets[1].id.class.should == MarkLogic::ObjectId
89
+ owner.pets[1].name.should == 'Sasha'
90
+ owner.pets[1].species.should == 'Siberian Husky'
91
+
92
+ owner.save.should be_truthy
93
+ owner.reload
94
+
95
+ owner.name.should == 'Mr. Pet Lover'
96
+ owner.pets[0].id.class.should == MarkLogic::ObjectId
97
+ owner.pets[0].name.should == 'Jimmy'
98
+ owner.pets[0].species.should == 'Cocker Spainel'
99
+ owner.pets[1].id.class.should == MarkLogic::ObjectId
100
+ owner.pets[1].name.should == 'Sasha'
101
+ owner.pets[1].species.should == 'Siberian Husky'
102
+ end
103
+
104
+ context "passing documents between versions of code" do
105
+ before do
106
+ @old_klass = Doc "Old" do
107
+ set_collection_name 'generic_parents'
108
+ key :name, String
109
+ end
110
+
111
+ @updated_klass = Doc "Updated" do
112
+ set_collection_name 'generic_parents'
113
+ key :name, String
114
+ end
115
+ @updated_klass.many :pets, :class => @pet_class
116
+ end
117
+
118
+ it "should not break many embedded proxy" do
119
+ @old_klass.collection.drop
120
+ created_by_new_code = @updated_klass.create!
121
+ created_by_new_code.pets.should == []
122
+
123
+ @old_klass.first # ensure_key_exists calls @old_klass.key(:embedded_docs) (not @old_klass.many(:embedded_docs))
124
+ @old_klass.create!(:name => 'created in old code') # creates doc with {embedded_docs : null}
125
+
126
+ lambda {
127
+ loaded_in_new_code = @updated_klass.find_by_name('created in old code')
128
+ expect(loaded_in_new_code.pets).to eq([])
129
+ }.should_not raise_error
130
+ end
131
+ end
132
+
133
+ context "embedding many embedded documents" do
134
+ before do
135
+ @klass = Doc()
136
+ @klass.many :people, :class => @person_class
137
+ end
138
+
139
+ it "should persist all embedded documents" do
140
+ meg = @person_class.new(:name => 'Meg', :pets => [
141
+ @pet_class.new(:name => 'Sparky', :species => 'Dog'),
142
+ @pet_class.new(:name => 'Koda', :species => 'Dog')
143
+ ])
144
+
145
+ doc = @klass.new
146
+ doc.people << meg
147
+ doc.save
148
+ doc.reload
149
+
150
+ doc.people.first.name.should == 'Meg'
151
+ doc.people.first.pets.should_not == []
152
+ doc.people.first.pets.first.name.should == 'Sparky'
153
+ doc.people.first.pets.first.species.should == 'Dog'
154
+ doc.people.first.pets[1].name.should == 'Koda'
155
+ doc.people.first.pets[1].species.should == 'Dog'
156
+ end
157
+
158
+ it "should create a reference to the root document for all embedded documents before save" do
159
+ doc = @klass.new
160
+ meg = @person_class.new(:name => 'Meg')
161
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
162
+
163
+ doc.people << meg
164
+ meg.pets << pet
165
+
166
+ doc.people.first._root_document.should == doc
167
+ doc.people.first.pets.first._root_document.should == doc
168
+ end
169
+ it "should create a reference to the owning document for all embedded documents before save" do
170
+ doc = @klass.new
171
+ meg = @person_class.new(:name => 'Meg')
172
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
173
+
174
+ doc.people << meg
175
+ meg.pets << pet
176
+
177
+ doc.people.first._parent_document.should == doc
178
+ doc.people.first.pets.first._parent_document.should == doc.people.first
179
+ end
180
+
181
+ it "should create a reference to the root document for all embedded documents" do
182
+ sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
183
+ meg = @person_class.new(:name => 'Meg', :pets => [sparky])
184
+ doc = @klass.new
185
+ doc.people << meg
186
+ doc.save
187
+
188
+ doc.reload
189
+ doc.people.first._root_document.should == doc
190
+ doc.people.first.pets.first._root_document.should == doc
191
+ end
192
+ it "should create a reference to the owning document for all embedded documents" do
193
+ doc = @klass.new
194
+ meg = @person_class.new(:name => 'Meg')
195
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
196
+
197
+ doc.people << meg
198
+ meg.pets << pet
199
+ doc.save
200
+
201
+ doc.reload
202
+ doc.people.first._parent_document.should == doc
203
+ doc.people.first.pets.first._parent_document.should == doc.people.first
204
+ end
205
+
206
+ it "should create embedded_in relationship for embedded docs" do
207
+ doc = @klass.new
208
+ meg = @person_class.new(:name => 'Meg')
209
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
210
+
211
+ doc.people << meg
212
+ meg.pets << pet
213
+ doc.save
214
+
215
+ doc.reload
216
+ doc.people.first.pets.first.person.should == doc.people.first
217
+ end
218
+ end
219
+
220
+ it "should allow finding by id" do
221
+ sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
222
+ meg = @owner_class.create(:name => 'Meg', :pets => [sparky])
223
+
224
+ meg.pets.find(sparky._id).should == sparky # oid
225
+ meg.pets.find(sparky.id.to_s).should == sparky # string
226
+ end
227
+
228
+ context "count" do
229
+ it "should default to 0" do
230
+ @owner_class.new.pets.count.should == 0
231
+ end
232
+
233
+ it "should return correct count if any are embedded" do
234
+ owner = @owner_class.new(:name => 'Meg')
235
+ owner.pets = [@pet_class.new, @pet_class.new]
236
+ owner.pets.count.should == 2
237
+ owner.save
238
+ owner.reload
239
+ owner.pets.count.should == 2
240
+ end
241
+ end
242
+
243
+ context "extending the association" do
244
+ before do
245
+ @address_class = EDoc do
246
+ key :address, String
247
+ key :city, String
248
+ key :state, String
249
+ key :zip, Integer
250
+ end
251
+
252
+ @project_class = Doc do
253
+ key :name, String
254
+ end
255
+ end
256
+
257
+ it "should work using a block passed to many" do
258
+ @project_class.many :addresses, :class => @address_class do
259
+ def find_all_by_state(state)
260
+ find_all { |a| a.state == state }
261
+ end
262
+ end
263
+
264
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
265
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
266
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
267
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
268
+
269
+ project.addresses.find_all_by_state("CA").should == [addr1, addr2]
270
+ end
271
+
272
+ it "should work using many's :extend option" do
273
+ module FindByCity
274
+ def find_by_city(city)
275
+ find_all { |a| a.city == city }
276
+ end
277
+ end
278
+ @project_class.many :addresses, :class => @address_class, :extend => FindByCity
279
+
280
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
281
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
282
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
283
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
284
+
285
+ project.addresses.find_by_city('Burbank').should == [addr2]
286
+ end
287
+ end
288
+ end