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,310 @@
1
+ require 'spec_helper'
2
+ require 'support/models'
3
+
4
+ describe "Document" do
5
+ before do
6
+ @document = Doc do
7
+ key :first_name, String
8
+ key :last_name, String
9
+ key :age, Integer
10
+ key :date, Date
11
+ end
12
+ end
13
+
14
+ context "array key" do
15
+ before do
16
+ @document.key :tags, Array
17
+ end
18
+
19
+ it "should give correct default" do
20
+ doc = @document.new
21
+ doc.tags.should == []
22
+ end
23
+
24
+ it "should work with assignment" do
25
+ doc = @document.new
26
+ doc.tags = %w(foo bar)
27
+ doc.tags.should == %w(foo bar)
28
+ end
29
+
30
+ it "should work with assignment after saving" do
31
+ doc = @document.new
32
+ doc.tags = %w(foo bar)
33
+ doc.save
34
+ doc.tags.should == %w(foo bar)
35
+ doc.reload.tags.should == %w(foo bar)
36
+ end
37
+
38
+ it "should work with assignment then <<" do
39
+ doc = @document.new
40
+ doc.tags = []
41
+ doc.tags << "foo"
42
+ doc.tags.should == ["foo"]
43
+ end
44
+
45
+ it "should work with <<" do
46
+ doc = @document.new
47
+ doc.tags << "foo"
48
+ doc.tags.should == ["foo"]
49
+ end
50
+
51
+ it "should work with << then save" do
52
+ doc = @document.new
53
+ doc.tags << "foo"
54
+ doc.tags << "bar"
55
+ doc.save
56
+ doc.tags.should == %w(foo bar)
57
+ doc.reload.tags.should == %w(foo bar)
58
+ end
59
+ end
60
+
61
+ context "hash key" do
62
+ before do
63
+ @document.key :foo, Hash
64
+ end
65
+
66
+ it "should give correct default" do
67
+ doc = @document.new
68
+ doc.foo.should == {}
69
+ end
70
+
71
+ it "should work with []=" do
72
+ doc = @document.new
73
+ doc.foo["quux"] = "bar"
74
+ doc.foo["quux"].should == "bar"
75
+ doc.foo.should == { "quux" => "bar" }
76
+ end
77
+
78
+ it "should work with indifferent access" do
79
+ doc = @document.new
80
+ doc.foo = {:baz => 'bar'}
81
+ doc.foo[:baz].should == 'bar'
82
+ doc.foo['baz'].should == 'bar'
83
+ end
84
+
85
+ it "should work with indifferent access after save" do
86
+ doc = @document.new
87
+ doc.foo = {:baz => 'bar'}
88
+ doc.save
89
+
90
+ doc = doc.reload
91
+ doc.foo[:baz].should == 'bar'
92
+ doc.foo['baz'].should == 'bar'
93
+ end
94
+ end
95
+
96
+ context "custom type key with default" do
97
+ before do
98
+ @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
99
+ end
100
+
101
+ it "should default to default" do
102
+ doc = @document.new
103
+ doc.window.should == WindowSize.new(600, 480)
104
+
105
+ end
106
+
107
+ it "should save and load from marklogic" do
108
+ doc = @document.new
109
+ doc.save
110
+
111
+ doc = doc.reload
112
+ doc.window.should == WindowSize.new(600, 480)
113
+ end
114
+ end
115
+
116
+ context "key with proc default value" do
117
+ before do
118
+ @document.key :proc_default, String, :default => lambda { return 'string' }
119
+ end
120
+
121
+ it "should detect and run proc default" do
122
+ doc = @document.new
123
+ doc.proc_default.should == 'string'
124
+ end
125
+
126
+ it "should save and load from marklogic" do
127
+ doc = @document.create
128
+ doc = doc.reload
129
+ doc.proc_default.should == 'string'
130
+ end
131
+ end
132
+
133
+ context "symbol key" do
134
+ before do
135
+ @document.key :foo, Symbol, :default => lambda { 123 }
136
+ end
137
+
138
+ it "should return default value" do
139
+ doc = @document.new
140
+ doc.foo.should == :'123'
141
+ end
142
+
143
+ it "should return symbol value" do
144
+ doc = @document.create :foo => 'qwerty'
145
+ doc.foo.should == :qwerty
146
+
147
+ doc.set :foo => 'poiuyt'
148
+ doc.reload
149
+ doc.foo.should == :poiuyt
150
+
151
+ doc.foo = 'asdf'
152
+ doc.foo.should == :asdf
153
+ end
154
+
155
+ it "should return typecasted value" do
156
+ doc = @document.new
157
+ (doc.foo = 'qwerty').should == 'qwerty'
158
+ end
159
+ end
160
+
161
+ it "should have instance method for collection" do
162
+ @document.new.collection.name.should == @document.collection.name
163
+ end
164
+
165
+ it "should have instance method for database" do
166
+ @document.new.database.should == @document.database
167
+ end
168
+
169
+ context "#destroyed?" do
170
+ before do
171
+ @doc1 = @document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
172
+ end
173
+
174
+ it "should be true if deleted" do
175
+ @doc1.delete
176
+ @doc1.should be_destroyed
177
+ end
178
+
179
+ it "should be true if destroyed" do
180
+ @doc1.destroy
181
+ @doc1.should be_destroyed
182
+ end
183
+
184
+ it "should be false if not deleted or destroyed" do
185
+ @doc1.should_not be_destroyed
186
+ end
187
+ end
188
+
189
+ context "#persisted?" do
190
+ before do
191
+ @doc = @document.new(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
192
+ end
193
+
194
+ it "should be false if new" do
195
+ @doc.should_not be_persisted
196
+ end
197
+
198
+ it "should be false if destroyed" do
199
+ @doc.save
200
+ @doc.destroy
201
+ @doc.should be_destroyed
202
+ @doc.should_not be_persisted
203
+ end
204
+
205
+ it "should be true if not new or destroyed" do
206
+ @doc.save
207
+ @doc.should be_persisted
208
+ end
209
+ end
210
+
211
+ context "#reload" do
212
+ before do
213
+ @foo_class = Doc do
214
+ key :name
215
+ end
216
+
217
+ @bar_class = EDoc do
218
+ key :name
219
+ end
220
+
221
+ @document.many :foos, :class => @foo_class
222
+ @document.many :bars, :class => @bar_class
223
+ @document.belongs_to :foo, :class => @foo_class
224
+ @document.one :bar, :class => @bar_class
225
+
226
+ @instance = @document.create({
227
+ :age => 39,
228
+ :foos => [@foo_class.new(:name => '1')],
229
+ :bars => [@bar_class.new(:name => '1')],
230
+ :foo => @foo_class.new(:name => '2'),
231
+ :bar => @bar_class.new(:name => '2')
232
+ })
233
+ end
234
+
235
+ it "should reload keys from the database" do
236
+ @instance.age = 37
237
+ @instance.age.should == 37
238
+ @instance.reload
239
+ @instance.age.should == 39
240
+ end
241
+
242
+ it "should reset many associations" do
243
+ expect(@instance.foos).to receive(:reset).at_least(1).times
244
+ expect(@instance.bars).to receive(:reset).at_least(1).times
245
+ @instance.reload
246
+ end
247
+
248
+ it "should reset belongs_to association" do
249
+ @instance.foo = nil
250
+ @instance.reload
251
+ @instance.foo.should_not be_nil
252
+ end
253
+
254
+ it "should reset one association" do
255
+ @instance.bar = nil
256
+ @instance.reload
257
+ @instance.bar.should_not be_nil
258
+ end
259
+
260
+ it "should reset nil one association" do
261
+ end
262
+
263
+ it "should reinstantiate embedded associations" do
264
+ @instance.reload
265
+ @instance.bars.first.name.should == '1'
266
+ end
267
+
268
+ it "should return self" do
269
+ @instance.reload.object_id.should == @instance.object_id
270
+ end
271
+
272
+ it "should raise DocumentNotFound if not found" do
273
+ @instance.destroy
274
+ expect { @instance.reload }.to raise_error(MarkMapper::DocumentNotFound)
275
+ end
276
+
277
+ it "should clear keys that were removed from the database" do
278
+ @instance.unset(:age)
279
+ @instance.reload.age.should be_nil
280
+ end
281
+ end
282
+
283
+ context "database has keys not defined in model" do
284
+ before do
285
+ @id = MarkLogic::ObjectId.new
286
+ @document.collection.insert({
287
+ :_id => @id,
288
+ :first_name => 'John',
289
+ :last_name => 'Nunemaker',
290
+ :age => 27,
291
+ :favorite_color => 'red',
292
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
293
+ })
294
+ end
295
+
296
+ it "should assign all keys from database" do
297
+ doc = @document.find(@id)
298
+ doc.first_name.should == 'John'
299
+ doc.last_name.should == 'Nunemaker'
300
+ doc.age.should == 27
301
+ doc.favorite_color.should == 'red'
302
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
303
+ end
304
+ end
305
+
306
+ it "should not walk ObjectSpace when creating a model" do
307
+ expect(ObjectSpace).to receive(:each_object).never
308
+ Doc()
309
+ end
310
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'active_support/cache/memory_store'
3
+
4
+ describe "Documents with the Dumpable plugin" do
5
+ let(:doc) { Doc { key :foo, String } }
6
+ let(:answer) { Answer.create(:body => "answer body") }
7
+ let(:store) { ActiveSupport::Cache::MemoryStore.new(:size => 1.megabyte) }
8
+
9
+ it "should be able to be marshalled" do
10
+ expect { Marshal.dump(answer) }.to_not raise_error
11
+ end
12
+
13
+ it "should be able to be unmarshalled" do
14
+ dumped = Marshal.dump(answer)
15
+ reconstituted_answer = Marshal.load(dumped)
16
+ reconstituted_answer.attributes.should == answer.attributes
17
+ end
18
+
19
+ it "should be able to be saved in a Rails cache" do
20
+ fetched = store.fetch("foo") { Answer.find(answer._id) }
21
+ fetched.body.should == "answer body"
22
+ fetched._id.should == answer._id
23
+ end
24
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Dynamic Querying" do
4
+ before do
5
+ @document = Doc do
6
+ scope :nunes, where(:last_name => 'Nunemaker')
7
+
8
+ key :first_name, String
9
+ key :last_name, String
10
+ key :age, Integer
11
+ key :date, Date
12
+ end
13
+
14
+ @doc1 = @document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => 27)
15
+ @doc2 = @document.create(:first_name => 'Steve', :last_name => 'Smith', :age => 28)
16
+ @doc3 = @document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => 26)
17
+ end
18
+
19
+ it "should find document based on argument" do
20
+ @document.find_by_first_name('John').should == @doc1
21
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
22
+ @document.find_by_age(27).should == @doc1
23
+ end
24
+
25
+ it "should not raise error" do
26
+ @document.find_by_first_name('MarkLogic').should be_nil
27
+ end
28
+
29
+ it "should define a method for each key" do
30
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
31
+ end
32
+
33
+ it "should find document based on all arguments" do
34
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
35
+ end
36
+
37
+ it "should not find the document if an argument is wrong" do
38
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
39
+ end
40
+
41
+ it "should find all documents based on arguments" do
42
+ docs = @document.find_all_by_last_name('Nunemaker')
43
+ docs.should be_kind_of(Array)
44
+ docs.should include(@doc1)
45
+ docs.should include(@doc3)
46
+ end
47
+
48
+ it "should initialize document with given arguments" do
49
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
50
+ doc.should be_new
51
+ doc.first_name.should == 'David'
52
+ end
53
+
54
+ it "should not initialize document if document is found" do
55
+ doc = @document.find_or_initialize_by_first_name('John')
56
+ doc.should_not be_new
57
+ end
58
+
59
+ it "should create document with given arguments" do
60
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
61
+ doc.should_not be_new
62
+ doc.first_name.should == 'David'
63
+ end
64
+
65
+ it "should raise error if document is not found when using !" do
66
+ lambda {
67
+ @document.find_by_first_name_and_last_name!(1,2)
68
+ }.should raise_error(MarkMapper::DocumentNotFound)
69
+ end
70
+
71
+ it "should work on scopes" do
72
+ @document.nunes.find_by_first_name('Steph').should == @doc3
73
+ @document.nunes.find_all_by_first_name('Steph').should == [@doc3]
74
+ end
75
+ end
@@ -0,0 +1,316 @@
1
+ require 'spec_helper'
2
+ require 'support/models'
3
+
4
+ describe "EmbeddedDocument" do
5
+ before do
6
+ @klass = Doc('Person') do
7
+ key :name, String
8
+ end
9
+
10
+ @pet_klass = EDoc('Pet') do
11
+ key :name, String
12
+ key :flag, Boolean
13
+ end
14
+
15
+ @klass.many :pets, :class => @pet_klass
16
+
17
+ @address_class = EDoc('Address') do
18
+ key :city, String
19
+ key :state, String
20
+ end
21
+ end
22
+
23
+ context "Saving a document with a key that is an embedded document" do
24
+ before do
25
+ @klass.key :foo, @address_class
26
+ end
27
+
28
+ it "should embed embedded document" do
29
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
30
+ doc = @klass.create(:foo => address)
31
+ doc.foo.city.should == 'South Bend'
32
+ doc.foo.state.should == 'IN'
33
+
34
+ doc = doc.reload
35
+ doc.foo.city.should == 'South Bend'
36
+ doc.foo.state.should == 'IN'
37
+ end
38
+
39
+ it "should assign _parent_document and _root_document" do
40
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
41
+ address._parent_document.should be_nil
42
+ doc = @klass.create(:foo => address)
43
+ address._parent_document.should be(doc)
44
+ address._root_document.should be(doc)
45
+ end
46
+
47
+ it "should assign _parent_document and _root_document when loading" do
48
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
49
+ doc = @klass.create(:foo => address)
50
+ doc.reload
51
+ doc.foo._parent_document.should be(doc)
52
+ doc.foo._root_document.should be(doc)
53
+ end
54
+ end
55
+
56
+ it "should correctly instantiate single collection inherited embedded documents" do
57
+ document = Doc('Foo') do
58
+ key :message, Message
59
+ end
60
+
61
+ doc1 = document.create(:message => Enter.new)
62
+ doc1.reload.message.class.should be(Enter)
63
+ end
64
+
65
+ context "new? (embedded key)" do
66
+ before do
67
+ @klass.key :foo, @address_class
68
+ end
69
+
70
+ it "should be true until document is created" do
71
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
72
+ doc = @klass.new(:foo => address)
73
+ address.new?.should be_truthy
74
+ end
75
+
76
+ it "should be false after document is saved" do
77
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
78
+ doc = @klass.new(:foo => address)
79
+ doc.save
80
+ doc.foo.new?.should be_falsey
81
+ end
82
+
83
+ it "should be false when loaded from database" do
84
+ address = @address_class.new(:city => 'South Bend', :state => 'IN')
85
+ doc = @klass.new(:foo => address)
86
+ doc.save
87
+
88
+ doc.reload
89
+ doc.foo.new?.should be_falsey
90
+ end
91
+ end
92
+
93
+ context "new? (embedded many association)" do
94
+ before do
95
+ @doc = @klass.new(:pets => [{:name => 'poo bear'}])
96
+ end
97
+
98
+ it "should be true until document is saved" do
99
+ @doc.should be_new
100
+ @doc.pets.first.should be_new
101
+ end
102
+
103
+ it "should be false after document is saved" do
104
+ @doc.save
105
+ @doc.pets.first.should_not be_new
106
+ end
107
+
108
+ it "should be false when loaded from database" do
109
+ @doc.save
110
+ @doc.pets.first.should_not be_new
111
+ @doc.reload
112
+ @doc.pets.first.should_not be_new
113
+ end
114
+
115
+ it "should be true until existing document is saved" do
116
+ @doc.save
117
+ pet = @doc.pets.build(:name => 'Rasmus')
118
+ pet.new?.should be_truthy
119
+ @doc.save
120
+ pet.new?.should be_falsey
121
+ end
122
+ end
123
+
124
+ context "new? (nested embedded many association)" do
125
+ before do
126
+ @pet_klass.many :addresses, :class=> @address_class
127
+ @doc = @klass.new
128
+ @doc.pets.build(:name => 'Rasmus')
129
+ @doc.save
130
+ end
131
+
132
+ it "should be true until existing document is saved" do
133
+ address = @doc.pets.first.addresses.build(:city => 'Holland', :state => 'MI')
134
+ address.new?.should be_truthy
135
+ @doc.save
136
+ address.new?.should be_falsey
137
+ end
138
+ end
139
+
140
+ context "new? (embedded one association)" do
141
+ before do
142
+ @klass.one :address, :class => @address_class
143
+ @doc = @klass.new
144
+ end
145
+
146
+ it "should be true until existing document is saved" do
147
+ @doc.save
148
+ @doc.build_address(:city => 'Holland', :state => 'MI')
149
+ @doc.address.new?.should be_truthy
150
+ @doc.save
151
+ @doc.address.new?.should be_falsey
152
+ end
153
+ end
154
+
155
+ context "new? (nested embedded one association)" do
156
+ before do
157
+ @pet_klass.one :address, :class => @address_class
158
+ @doc = @klass.new
159
+ @doc.pets.build(:name => 'Rasmus')
160
+ @doc.save
161
+ end
162
+
163
+ it "should be true until existing document is saved" do
164
+ address = @doc.pets.first.build_address(:city => 'Holland', :stats => 'MI')
165
+ address.new?.should be_truthy
166
+ @doc.save
167
+ address.new?.should be_falsey
168
+ end
169
+ end
170
+
171
+ context "#destroyed?" do
172
+ before do
173
+ @doc = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
174
+ end
175
+
176
+ it "should be false if root document is not destroyed" do
177
+ @doc.should_not be_destroyed
178
+ @doc.pets.first.should_not be_destroyed
179
+ end
180
+
181
+ it "should be true if root document is destroyed" do
182
+ @doc.destroy
183
+ @doc.should be_destroyed
184
+ @doc.pets.first.should be_destroyed
185
+ end
186
+ end
187
+
188
+ context "#persisted?" do
189
+ before do
190
+ @doc = @klass.new(:name => 'persisted doc', :pets => [@pet_klass.new(:name => 'persisted pet')])
191
+ end
192
+
193
+ it "should be false if new" do
194
+ @doc.pets.first.should_not be_persisted
195
+ end
196
+
197
+ it "should be false if destroyed" do
198
+ @doc.save
199
+ @doc.destroy
200
+ @doc.pets.first.should be_destroyed
201
+ @doc.pets.first.should_not be_persisted
202
+ end
203
+
204
+ it "should be true if not new or destroyed" do
205
+ @doc.save
206
+ @doc.pets.first.should be_persisted
207
+ end
208
+ end
209
+
210
+ it "should be able to save" do
211
+ person = @klass.create
212
+
213
+ pet = @pet_klass.new(:name => 'sparky')
214
+ person.pets << pet
215
+ pet.should be_new
216
+ pet.save
217
+ pet.should_not be_new
218
+
219
+ person.reload
220
+ person.pets.first.should == pet
221
+ end
222
+
223
+ it "should be able to save!" do
224
+ person = @klass.create
225
+
226
+ pet = @pet_klass.new(:name => 'sparky')
227
+ person.pets << pet
228
+ pet.should be_new
229
+
230
+ expect(person).to receive(:save!)
231
+ pet.save!
232
+ end
233
+
234
+ it "should be able to dynamically add new keys and save" do
235
+ person = @klass.create
236
+
237
+ pet = @pet_klass.new(:name => 'sparky', :crazy_key => 'crazy')
238
+ person.pets << pet
239
+ pet.save
240
+
241
+ person.reload
242
+ person.pets.first.crazy_key.should == 'crazy'
243
+ end
244
+
245
+ it "should be able to update_attribute" do
246
+ pet = @pet_klass.new(:name => 'sparky')
247
+ person = @klass.create(:pets => [pet])
248
+ person.reload
249
+ pet = person.pets.first
250
+
251
+ pet.update_attribute('name', 'koda').should be_truthy
252
+ person.reload
253
+ person.pets.first._id.should == pet._id
254
+ person.pets.first.name.should == 'koda'
255
+ end
256
+
257
+ it "should be able to update_attributes" do
258
+ pet = @pet_klass.new(:name => 'sparky')
259
+ person = @klass.create(:pets => [pet])
260
+ person.reload
261
+ pet = person.pets.first
262
+
263
+ pet.update_attributes(:name => 'koda').should be_truthy
264
+ person.reload
265
+ person.pets.first._id.should == pet._id
266
+ person.pets.first.name.should == 'koda'
267
+ end
268
+
269
+ it "should be able to update_attributes!" do
270
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
271
+ person.reload
272
+ pet = person.pets.first
273
+
274
+ attributes = {:name => 'koda'}
275
+ expect(pet).to receive(:attributes=).with(attributes)
276
+ expect(pet).to receive(:save!)
277
+ pet.update_attributes!(attributes)
278
+ end
279
+
280
+ it "should have database instance method that is equal to root document" do
281
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
282
+ person.pets.first.database.should == person.database
283
+ end
284
+
285
+ it "should have collection instance method that is equal to root document" do
286
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'sparky')])
287
+ person.pets.first.collection.name.should == person.collection.name
288
+ end
289
+
290
+ it "should not fail if the source document contains nils in the embedded document list" do
291
+ @klass.collection.insert(:pets => [nil, {:name => "Sasha"}])
292
+ expect { @klass.all.first.pets }.to_not raise_error
293
+ @klass.all.first.pets.tap do |pets|
294
+ pets.length.should == 1
295
+ pets[0].name.should == "Sasha"
296
+ end
297
+ end
298
+
299
+ context "Issue #536" do
300
+ it "should update attributes with string keys" do
301
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'Rasmus', :flag => true)])
302
+ person.update_attributes!({"pets" => ["name" => "sparky", "flag" => "false"]})
303
+ person.reload
304
+ person.pets.first.name.should == "sparky"
305
+ person.pets.first.flag.should be_falsey
306
+ end
307
+
308
+ it "should update attributes with symbol keys" do
309
+ person = @klass.create(:pets => [@pet_klass.new(:name => 'Rasmus', :flag => true)])
310
+ person.update_attributes!({:pets => [:name => "sparky", :flag => "false"]})
311
+ person.reload
312
+ person.pets.first.name.should == "sparky"
313
+ person.pets.first.flag.should be_falsey
314
+ end
315
+ end
316
+ end