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,339 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Keys" do
4
+ it "should not have a disparity between the ivar and accessor" do
5
+ doc = Doc do
6
+ key :foo, String
7
+
8
+ def modify_foo
9
+ @foo = :baz
10
+ end
11
+
12
+ def get_foo
13
+ @foo
14
+ end
15
+ end
16
+
17
+ instance = doc.new(:foo => "bar")
18
+ instance.get_foo.should == instance.foo
19
+
20
+ instance.foo = :bing
21
+ instance.get_foo.should == instance.foo
22
+
23
+ instance.modify_foo
24
+ instance.get_foo.should == instance.foo
25
+ end
26
+
27
+ it "should return the value when set using send with the writer method" do
28
+ doc = Doc do
29
+ key :foo, String
30
+ end
31
+
32
+ instance = doc.new(:foo => 'bar')
33
+ instance.send("foo=", 'baz').should == 'baz'
34
+ instance.foo.should == 'baz'
35
+ end
36
+
37
+ context "when persisting an typecasted array" do
38
+ TypecastedKeyModel = Doc do
39
+ key :people, Array, :typecast => "Person"
40
+ end
41
+
42
+ Person = Struct.new(:name) do
43
+ def self.to_marklogic(value)
44
+ value.name
45
+ end
46
+
47
+ def self.from_marklogic(value)
48
+ Person.new value
49
+ end
50
+ end
51
+
52
+ it "should not mutate the model's state" do
53
+ person = Person.new "Bob"
54
+ doc = TypecastedKeyModel.new(:people => [person])
55
+
56
+ doc.save
57
+
58
+ doc.people.should == [person]
59
+ end
60
+ end
61
+
62
+ it "should not bomb if a key is written before Keys#initialize gets to get called" do
63
+ doc = Class.new do
64
+ include MarkMapper::Document
65
+
66
+ def initialize
67
+ self.class.key :something, String
68
+ self.something = :other_thing
69
+ super
70
+ end
71
+ end
72
+
73
+ expect { doc.new }.to_not raise_error
74
+ end
75
+
76
+ it "should not bomb if a key is read before Keys#initialize gets to get called" do
77
+ doc = Class.new do
78
+ include MarkMapper::Document
79
+
80
+ def initialize
81
+ self.class.key :something, String
82
+ self.something
83
+ super
84
+ end
85
+ end
86
+
87
+ expect { doc.new }.to_not raise_error
88
+ end
89
+
90
+ it "should permit for key overrides" do
91
+ doc = Class.new do
92
+ include MarkMapper::Document
93
+ key :class, String, :accessors => :skip
94
+ end
95
+
96
+ doc.collection.insert('class' => 'String')
97
+ doc.all.first.tap do |d|
98
+ d.class.should == doc
99
+ d["class"].should == "String"
100
+ d.attributes["class"].should == "String"
101
+ end
102
+ end
103
+
104
+ context "key segmenting" do
105
+ let(:doc) {
106
+ Doc {
107
+ key :defined
108
+ }
109
+ }
110
+
111
+ before do
112
+ doc.collection.insert(:dynamic => "foo")
113
+ doc.first
114
+ end
115
+
116
+ describe "#dynamic_keys" do
117
+ it "should find dynamic keys" do
118
+ doc.dynamic_keys.keys.should == ["dynamic"]
119
+ end
120
+ end
121
+
122
+ describe "#defined_keys" do
123
+ it "should find defined keys" do
124
+ doc.defined_keys.keys.should =~ ["_id", "defined"]
125
+ end
126
+ end
127
+ end
128
+
129
+ describe "with invalid names" do
130
+ it "should warn when key names start with an uppercase letter" do
131
+ doc = Doc {}
132
+ expect(Kernel).to receive(:warn).once.with(/may not start with uppercase letters/)
133
+ doc.class_eval do
134
+ key :NotConstant
135
+ end
136
+ end
137
+
138
+ it "should handle keys that start with uppercase letters by translating their first letter to lowercase" do
139
+ doc = Doc {}
140
+ allow(Kernel).to receive(:warn)
141
+ doc.class_eval do
142
+ key :NotConstant
143
+ end
144
+ doc.collection.insert("NotConstant" => "Just data!")
145
+ doc.first.notConstant.should == "Just data!"
146
+ end
147
+
148
+ it "should not create accessors for bad keys" do
149
+ doc = Doc {}
150
+ expect(doc).to_not receive(:create_accessors_for)
151
+ doc.class_eval do
152
+ key :"bad-name", :__dynamic => true
153
+ end
154
+ expect { doc.new.method(:"bad-name") }.to raise_error(NameError)
155
+ end
156
+
157
+ it "should not create accessors for reserved keys" do
158
+ doc = Doc {}
159
+ expect(doc).to_not receive(:create_accessors_for)
160
+ doc.class_eval do
161
+ key :"class", :__dynamic => true
162
+ end
163
+ expect(doc.new.class).to eq doc
164
+ end
165
+
166
+ it "should create accessors for good keys" do
167
+ doc = Doc {
168
+ key :good_name
169
+ }
170
+ doc.new.good_name.should be_nil
171
+ expect { doc.new.method("good_name") }.to_not raise_error
172
+ end
173
+ end
174
+
175
+ it "should handle loading dynamic fields from the database that have bad names" do
176
+ doc = Doc {}
177
+ doc.collection.insert("foo-bar" => "baz-bin")
178
+
179
+ doc.first["foo-bar"].should == "baz-bin"
180
+ end
181
+
182
+ describe "with aliases" do
183
+ AliasedKeyModel = Doc do
184
+ key :foo, :abbr => :f
185
+ key :with_underscores, :alias => "with-hyphens"
186
+ key :field_name, :field_name => "alternate_field_name"
187
+ key :bar
188
+ end
189
+
190
+ before { AliasedKeyModel.collection.drop }
191
+
192
+ context "standard key operations" do
193
+ before do
194
+ AliasedKeyModel.create(:foo => "whee!", :bar => "whoo!")
195
+ end
196
+
197
+ it "should serialize with aliased keys" do
198
+ AliasedKeyModel.collection.find_one.keys.should =~ %w(_id f bar)
199
+
200
+ AliasedKeyModel.first.tap do |d|
201
+ d.foo.should == "whee!"
202
+ d.bar.should == "whoo!"
203
+ end
204
+ end
205
+
206
+ it "should permit querying via direct field names" do
207
+ AliasedKeyModel.where(AliasedKeyModel.abbr(:foo) => "whee!").first.foo.should == "whee!"
208
+ end
209
+
210
+ it "should permit querying via direct field names" do
211
+ AliasedKeyModel.where(:foo => "whee!").criteria_hash.keys.should == ["f"]
212
+ AliasedKeyModel.where(:foo => "whee!").first.foo.should == "whee!"
213
+ end
214
+
215
+ it "should permit filtering via aliases" do
216
+ AliasedKeyModel.where(:foo => "whee!").fields(:foo).first.foo.should == "whee!"
217
+ end
218
+
219
+ it "should permit dealiasing of atomic operations" do
220
+ m = AliasedKeyModel.first
221
+ m.set(:foo => 1)
222
+ AliasedKeyModel.collection.find_one["f"].should == 1
223
+ AliasedKeyModel.collection.find_one["foo"].should be_nil
224
+ end
225
+
226
+ it "should permit dealiasing of update operations" do
227
+ m = AliasedKeyModel.first
228
+ m.update_attributes(:foo => 1)
229
+ AliasedKeyModel.collection.find_one["f"].should == 1
230
+ AliasedKeyModel.collection.find_one["foo"].should be_nil
231
+ end
232
+
233
+ it "should not break when unaliasing non-keys" do
234
+ AliasedKeyModel.where(:badkey => "whee!").criteria_hash.keys.should == [:badkey]
235
+ end
236
+
237
+ it "should serialize to JSON with full keys" do
238
+ AliasedKeyModel.first.as_json.tap do |json|
239
+ json.should have_key "foo"
240
+ json.should_not have_key "f"
241
+ end
242
+ end
243
+ end
244
+
245
+ context "given field which are not valid Ruby method names" do
246
+ before { AliasedKeyModel.create(:with_underscores => "foobar") }
247
+ it "should work" do
248
+ AliasedKeyModel.first.with_underscores.should == "foobar"
249
+ AliasedKeyModel.collection.find_one["with-hyphens"].should == "foobar"
250
+ end
251
+ end
252
+
253
+ context "given a field aliased with :field_name" do
254
+ before { AliasedKeyModel.create(:field_name => "foobar") }
255
+ it "should work" do
256
+ AliasedKeyModel.first.field_name.should == "foobar"
257
+ AliasedKeyModel.collection.find_one["alternate_field_name"].should == "foobar"
258
+ end
259
+ end
260
+
261
+ context "associations" do
262
+ AssociatedKeyWithAlias = Doc do
263
+ set_collection_name "associated_documents"
264
+ key :name, String, :abbr => :n
265
+ key :association_id, ObjectId, :abbr => :aid
266
+ end
267
+
268
+ OwnerDocWithKeyAliases = Doc do
269
+ set_collection_name "owner_documents"
270
+ key :name, String, :abbr => :n
271
+ many :associated_documents, :class_name => "AssociatedKeyWithAlias", :foreign_key => AssociatedKeyWithAlias.abbr(:association_id)
272
+ many :other_documents, :class_name => "EmbeddedDocWithAliases"
273
+ end
274
+
275
+ EmbeddedDocWithAliases = EDoc do
276
+ key :embedded_name, String, :abbr => :en
277
+ end
278
+
279
+ before do
280
+ AssociatedKeyWithAlias.collection.drop
281
+ OwnerDocWithKeyAliases.collection.drop
282
+ end
283
+
284
+ it "should work" do
285
+ owner = OwnerDocWithKeyAliases.create(:name => "Big Boss")
286
+
287
+ associated_documents = 3.times.map {|i| AssociatedKeyWithAlias.new(:name => "Associated Record #{i}") }
288
+ owner.associated_documents = associated_documents
289
+ owner.save
290
+
291
+ owner.reload
292
+ owner.associated_documents.to_a.should =~ associated_documents.to_a
293
+
294
+ AssociatedKeyWithAlias.collection.find_one.keys.should =~ %w(_id n aid)
295
+ end
296
+
297
+ it "should work with embedded documents" do
298
+ owner = OwnerDocWithKeyAliases.create(:name => "Big Boss")
299
+ owner.other_documents << EmbeddedDocWithAliases.new(:embedded_name => "Underling")
300
+ owner.save
301
+
302
+ owner.reload
303
+ owner.other_documents[0].embedded_name.should == "Underling"
304
+ owner.collection.find_one["other_documents"][0]["en"].should == "Underling"
305
+ end
306
+ end
307
+ end
308
+
309
+ describe "removing keys" do
310
+ DocWithRemovedKey = Doc do
311
+ key :something
312
+ validates_uniqueness_of :something
313
+ remove_key :something
314
+ end
315
+
316
+ it 'should remove the key' do
317
+ DocWithRemovedKey.keys.should_not have_key "_something"
318
+ end
319
+
320
+ it 'should remove validations' do
321
+ DocWithRemovedKey._validate_callbacks.should be_empty
322
+ end
323
+ end
324
+
325
+ describe "removing keys in the presence of a validation method" do
326
+ DocWithRemovedValidator = Doc do
327
+ key :something
328
+ validate :something_valid?
329
+ remove_key :something
330
+
331
+ def something_valid?; true; end
332
+ end
333
+
334
+ it 'should remove the key' do
335
+ DocWithRemovedKey.keys.should_not have_key "_something"
336
+ end
337
+
338
+ end
339
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Logger" do
4
+ context "with connection that has logger" do
5
+ before do
6
+ @output = StringIO.new
7
+ @logger = Logger.new(@output)
8
+ MarkLogic.logger = @logger
9
+ end
10
+
11
+ it "should be able to get access to that logger" do
12
+ MarkMapper.logger.should == @logger
13
+ end
14
+
15
+ it "should be able to log messages" do
16
+ MarkMapper.logger.debug 'testing'
17
+ @output.string.include?('testing').should be_truthy
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,446 @@
1
+ require 'spec_helper'
2
+
3
+ module Modifiers
4
+ describe "Modifiers" do
5
+ let(:page_class_with_compound_key) {
6
+ Doc do
7
+ key :_id, Hash, :default => lambda { { 'n' => 42, 'i' => MarkLogic::ObjectId.new } }
8
+ key :title, String
9
+ key :day_count, Integer, :default => 0
10
+ key :week_count, Integer, :default => 0
11
+ key :month_count, Integer, :default => 0
12
+ key :tags, Array
13
+ end
14
+ }
15
+
16
+ let(:page_class_with_standard_key) {
17
+ Doc do
18
+ key :title, String
19
+ key :day_count, Integer, :default => 0
20
+ key :week_count, Integer, :default => 0
21
+ key :month_count, Integer, :default => 0
22
+ key :tags, Array
23
+ end
24
+ }
25
+
26
+ def assert_page_counts(page, day_count, week_count, month_count)
27
+ doc = page.collection.find_one(:_id => page.id)
28
+ doc.should be_present, "Could not find document"
29
+ doc.fetch('day_count').should == day_count
30
+ doc.fetch('week_count').should == week_count
31
+ doc.fetch('month_count').should == month_count
32
+ end
33
+
34
+ def assert_keys_removed(page, *keys)
35
+ page.class.collection.find_one(:_id => page.id).tap do |doc|
36
+ doc.should be_present, "Could not find document"
37
+ (doc.keys & keys).should be_empty, "Expected to not have keys #{keys.inspect}, got #{(keys & doc.keys).inspect}"
38
+ end
39
+ end
40
+
41
+ context "ClassMethods" do
42
+ let!(:page_class) { page_class_with_standard_key }
43
+ let!(:page) { page_class.create(:title => 'Home') }
44
+ let!(:page2) { page_class.create(:title => 'Home') }
45
+
46
+ context "unset" do
47
+ let!(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
48
+
49
+ it "should work with criteria and keys" do
50
+ page_class.unset({:title => 'Home'}, :title, :tags)
51
+ assert_keys_removed page, :title, :tags
52
+ assert_keys_removed page2, :title, :tags
53
+ end
54
+
55
+ it "should work with ids and keys" do
56
+ page_class.unset(page.id, page2.id, :title, :tags)
57
+ assert_keys_removed page, :title, :tags
58
+ assert_keys_removed page2, :title, :tags
59
+ end
60
+ end
61
+
62
+ context "increment" do
63
+ it "should work with criteria and modifier hashes" do
64
+ page_class.increment({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
65
+
66
+ assert_page_counts page, 1, 2, 3
67
+ assert_page_counts page2, 1, 2, 3
68
+ end
69
+
70
+ it "should work with ids and modifier hash" do
71
+ page_class.increment(page.id, page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
72
+
73
+ assert_page_counts page, 1, 2, 3
74
+ assert_page_counts page2, 1, 2, 3
75
+ end
76
+
77
+ it "should work with ids given as strings" do
78
+ page_class.increment(page.id.to_s, page2.id.to_s, :day_count => 1, :week_count => 2, :month_count => 3)
79
+
80
+ assert_page_counts page, 1, 2, 3
81
+ assert_page_counts page2, 1, 2, 3
82
+ end
83
+ end
84
+
85
+ context "decrement" do
86
+ let!(:page) { page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3) }
87
+ let!(:page2) { page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3) }
88
+
89
+ it "should work with criteria and modifier hashes" do
90
+ page_class.decrement({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
91
+
92
+ assert_page_counts page, 0, 0, 0
93
+ assert_page_counts page2, 0, 0, 0
94
+ end
95
+
96
+ it "should work with ids and modifier hash" do
97
+ page_class.decrement(page.id, page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
98
+
99
+ assert_page_counts page, 0, 0, 0
100
+ assert_page_counts page2, 0, 0, 0
101
+ end
102
+
103
+ it "should decrement with positive or negative numbers" do
104
+ page_class.decrement(page.id, page2.id, :day_count => -1, :week_count => 2, :month_count => -3)
105
+
106
+ assert_page_counts page, 0, 0, 0
107
+ assert_page_counts page2, 0, 0, 0
108
+ end
109
+
110
+ it "should work with ids given as strings" do
111
+ page_class.decrement(page.id.to_s, page2.id.to_s, :day_count => -1, :week_count => 2, :month_count => -3)
112
+
113
+ assert_page_counts page, 0, 0, 0
114
+ assert_page_counts page2, 0, 0, 0
115
+ end
116
+ end
117
+
118
+ context "set" do
119
+ it "should work with criteria and modifier hashes" do
120
+ page_class.set({:title => 'Home'}, :title => 'Home Revised')
121
+
122
+ page.reload
123
+ page.title.should == 'Home Revised'
124
+
125
+ page2.reload
126
+ page2.title.should == 'Home Revised'
127
+ end
128
+
129
+ it "should work with ids and modifier hash" do
130
+ page_class.set(page.id, page2.id, :title => 'Home Revised')
131
+
132
+ page.reload
133
+ page.title.should == 'Home Revised'
134
+
135
+ page2.reload
136
+ page2.title.should == 'Home Revised'
137
+ end
138
+
139
+ it "should typecast values before querying" do
140
+ page_class.key :tags, Set
141
+
142
+ expect {
143
+ page_class.set(page.id, :tags => ['foo', 'bar'].to_set)
144
+ page.reload
145
+ page.tags.should == Set.new(['foo', 'bar'])
146
+ }.to_not raise_error
147
+ end
148
+
149
+ # it "should not typecast keys that are not defined in document" do
150
+ # expect {
151
+ # page_class.set(page.id, :colors => ['red', 'green'].to_set)
152
+ # }.to raise_error(BSON::InvalidDocument)
153
+ # end
154
+
155
+ it "should set keys that are not defined in document" do
156
+ page_class.set(page.id, :colors => %w[red green])
157
+ page.reload
158
+ page[:colors].should == %w[red green]
159
+ end
160
+ end
161
+
162
+ context "push" do
163
+ it "should work with criteria and modifier hashes" do
164
+ page_class.push({:title => 'Home'}, :tags => 'foo')
165
+
166
+ page.reload
167
+ page.tags.should == %w(foo)
168
+
169
+ page2.reload
170
+ page2.tags.should == %w(foo)
171
+ end
172
+
173
+ it "should work with ids and modifier hash" do
174
+ page_class.push(page.id, page2.id, :tags => 'foo')
175
+
176
+ page.reload
177
+ page.tags.should == %w(foo)
178
+
179
+ page2.reload
180
+ page2.tags.should == %w(foo)
181
+ end
182
+ end
183
+
184
+ context "push_all" do
185
+ let(:tags) { %w(foo bar) }
186
+
187
+ it "should work with criteria and modifier hashes" do
188
+ page_class.push_all({:title => 'Home'}, :tags => tags)
189
+
190
+ page.reload
191
+ page.tags.should == tags
192
+
193
+ page2.reload
194
+ page2.tags.should == tags
195
+ end
196
+
197
+ it "should work with ids and modifier hash" do
198
+ page_class.push_all(page.id, page2.id, :tags => tags)
199
+
200
+ page.reload
201
+ page.tags.should == tags
202
+
203
+ page2.reload
204
+ page2.tags.should == tags
205
+ end
206
+ end
207
+
208
+ # context "pull" do
209
+ # let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
210
+ # let(:page2) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
211
+
212
+ # it "should work with criteria and modifier hashes" do
213
+ # page_class.pull({:title => 'Home'}, :tags => 'foo')
214
+
215
+ # page.reload
216
+ # page.tags.should == %w(bar)
217
+
218
+ # page2.reload
219
+ # page2.tags.should == %w(bar)
220
+ # end
221
+
222
+ # it "should be able to pull with ids and modifier hash" do
223
+ # page_class.pull(page.id, page2.id, :tags => 'foo')
224
+
225
+ # page.reload
226
+ # page.tags.should == %w(bar)
227
+
228
+ # page2.reload
229
+ # page2.tags.should == %w(bar)
230
+ # end
231
+ # end
232
+
233
+ # context "pull_all" do
234
+ # let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar baz)) }
235
+ # let(:page2) { page_class.create(:title => 'Home', :tags => %w(foo bar baz)) }
236
+
237
+ # it "should work with criteria and modifier hashes" do
238
+ # page_class.pull_all({:title => 'Home'}, :tags => %w(foo bar))
239
+
240
+ # page.reload
241
+ # page.tags.should == %w(baz)
242
+
243
+ # page2.reload
244
+ # page2.tags.should == %w(baz)
245
+ # end
246
+
247
+ # it "should work with ids and modifier hash" do
248
+ # page_class.pull_all(page.id, page2.id, :tags => %w(foo bar))
249
+
250
+ # page.reload
251
+ # page.tags.should == %w(baz)
252
+
253
+ # page2.reload
254
+ # page2.tags.should == %w(baz)
255
+ # end
256
+ # end
257
+
258
+ # context "add_to_set" do
259
+ # let(:page) { page_class.create(:title => 'Home', :tags => 'foo') }
260
+
261
+ # it "should be able to add to set with criteria and modifier hash" do
262
+ # page_class.add_to_set({:title => 'Home'}, :tags => 'foo')
263
+
264
+ # page.reload
265
+ # page.tags.should == %w(foo)
266
+
267
+ # page2.reload
268
+ # page2.tags.should == %w(foo)
269
+ # end
270
+
271
+ # it "should be able to add to set with ids and modifier hash" do
272
+ # page_class.add_to_set(page.id, page2.id, :tags => 'foo')
273
+
274
+ # page.reload
275
+ # page.tags.should == %w(foo)
276
+
277
+ # page2.reload
278
+ # page2.tags.should == %w(foo)
279
+ # end
280
+ # end
281
+
282
+ # context "push_uniq" do
283
+ # let(:page) { page_class.create(:title => 'Home', :tags => 'foo') }
284
+
285
+ # it "should be able to push uniq with criteria and modifier hash" do
286
+ # page_class.push_uniq({:title => 'Home'}, :tags => 'foo')
287
+
288
+ # page.reload
289
+ # page.tags.should == %w(foo)
290
+
291
+ # page2.reload
292
+ # page2.tags.should == %w(foo)
293
+ # end
294
+
295
+ # it "should be able to push uniq with ids and modifier hash" do
296
+ # page_class.push_uniq(page.id, page2.id, :tags => 'foo')
297
+
298
+ # page.reload
299
+ # page.tags.should == %w(foo)
300
+
301
+ # page2.reload
302
+ # page2.tags.should == %w(foo)
303
+ # end
304
+ # end
305
+
306
+ # context "pop" do
307
+ # let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
308
+
309
+ # it "should be able to remove the last element the array" do
310
+ # page_class.pop(page.id, :tags => 1)
311
+ # page.reload
312
+ # page.tags.should == %w(foo)
313
+ # end
314
+
315
+ # it "should be able to remove the first element of the array" do
316
+ # page_class.pop(page.id, :tags => -1)
317
+ # page.reload
318
+ # page.tags.should == %w(bar)
319
+ # end
320
+ # end
321
+ end
322
+
323
+ context "compound keys" do
324
+ it "should create a document" do
325
+ expect {
326
+ page_class_with_compound_key.create(:title => 'Foo', :tags => %w(foo))
327
+ }.to change { page_class_with_compound_key.count }.by(1)
328
+ doc = page_class_with_compound_key.first
329
+ page_class_with_compound_key.find(doc._id).should == doc
330
+ end
331
+ end
332
+
333
+ context "instance methods" do
334
+ {
335
+ :page_class_with_standard_key => "with standard key",
336
+ :page_class_with_compound_key => "with compound key",
337
+ }.each do |klass, description|
338
+ context description do
339
+ let!(:page_class) { send(klass) }
340
+
341
+ it "should be able to unset with keys" do
342
+ page = page_class.create(:title => 'Foo', :tags => %w(foo))
343
+ page.unset(:title, :tags)
344
+ assert_keys_removed page, :title, :tags
345
+ end
346
+
347
+ it "should be able to increment with modifier hashes" do
348
+ page = page_class.create
349
+ page.increment(:day_count => 1, :week_count => 2, :month_count => 3)
350
+
351
+ assert_page_counts page, 1, 2, 3
352
+ end
353
+
354
+ it "should be able to decrement with modifier hashes" do
355
+ page = page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
356
+ page.decrement(:day_count => 1, :week_count => 2, :month_count => 3)
357
+
358
+ assert_page_counts page, 0, 0, 0
359
+ end
360
+
361
+ it "should always decrement when decrement is called whether number is positive or negative" do
362
+ page = page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
363
+ page.decrement(:day_count => -1, :week_count => 2, :month_count => -3)
364
+ assert_page_counts page, 0, 0, 0
365
+ end
366
+
367
+ it "should be able to set with modifier hashes" do
368
+ page = page_class.create(:title => 'Home')
369
+ page.set(:title => 'Home Revised')
370
+
371
+ page.reload
372
+ page.title.should == 'Home Revised'
373
+ end
374
+
375
+ it "should be able to push with modifier hashes" do
376
+ page = page_class.create
377
+ page.push(:tags => 'foo')
378
+
379
+ page.reload
380
+ page.tags.should == %w(foo)
381
+ end
382
+
383
+ it "should be able to push_all with modifier hashes" do
384
+ page = page_class.create
385
+ page.push_all(:tags => %w(foo bar))
386
+
387
+ page.reload
388
+ page.tags.should == %w(foo bar)
389
+ end
390
+
391
+ # it "should be able to pull with criteria and modifier hashes" do
392
+ # page = page_class.create(:tags => %w(foo bar))
393
+ # page.pull(:tags => 'foo')
394
+
395
+ # page.reload
396
+ # page.tags.should == %w(bar)
397
+ # end
398
+
399
+ # it "should be able to pull_all with criteria and modifier hashes" do
400
+ # page = page_class.create(:tags => %w(foo bar baz))
401
+ # page.pull_all(:tags => %w(foo bar))
402
+
403
+ # page.reload
404
+ # page.tags.should == %w(baz)
405
+ # end
406
+
407
+ # it "should be able to add_to_set with criteria and modifier hash" do
408
+ # page = page_class.create(:tags => 'foo')
409
+ # page2 = page_class.create
410
+
411
+ # page.add_to_set(:tags => 'foo')
412
+ # page2.add_to_set(:tags => 'foo')
413
+
414
+ # page.reload
415
+ # page.tags.should == %w(foo)
416
+
417
+ # page2.reload
418
+ # page2.tags.should == %w(foo)
419
+ # end
420
+
421
+ # it "should be able to push uniq with criteria and modifier hash" do
422
+ # page = page_class.create(:tags => 'foo')
423
+ # page2 = page_class.create
424
+
425
+ # page.push_uniq(:tags => 'foo')
426
+ # page2.push_uniq(:tags => 'foo')
427
+
428
+ # page.reload
429
+ # page.tags.should == %w(foo)
430
+
431
+ # page2.reload
432
+ # page2.tags.should == %w(foo)
433
+ # end
434
+
435
+ # it "should be able to pop with modifier hashes" do
436
+ # page = page_class.create(:tags => %w(foo bar))
437
+ # page.pop(:tags => 1)
438
+
439
+ # page.reload
440
+ # page.tags.should == %w(foo)
441
+ # end
442
+ end
443
+ end
444
+ end
445
+ end
446
+ end