mark_mapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +39 -0
  4. data/examples/attr_accessible.rb +24 -0
  5. data/examples/attr_protected.rb +24 -0
  6. data/examples/cache_key.rb +26 -0
  7. data/examples/custom_types.rb +26 -0
  8. data/examples/identity_map.rb +30 -0
  9. data/examples/identity_map/automatic.rb +2 -0
  10. data/examples/keys.rb +42 -0
  11. data/examples/modifiers/set.rb +27 -0
  12. data/examples/plugins.rb +40 -0
  13. data/examples/querying.rb +39 -0
  14. data/examples/sample_app.rb +43 -0
  15. data/examples/scopes.rb +56 -0
  16. data/examples/validating/embedded_docs.rb +31 -0
  17. data/lib/mark_mapper.rb +125 -0
  18. data/lib/mark_mapper/config.rb +90 -0
  19. data/lib/mark_mapper/connection.rb +60 -0
  20. data/lib/mark_mapper/criteria_hash.rb +194 -0
  21. data/lib/mark_mapper/document.rb +46 -0
  22. data/lib/mark_mapper/embedded_document.rb +32 -0
  23. data/lib/mark_mapper/exceptions.rb +33 -0
  24. data/lib/mark_mapper/extensions/array.rb +27 -0
  25. data/lib/mark_mapper/extensions/boolean.rb +45 -0
  26. data/lib/mark_mapper/extensions/date.rb +29 -0
  27. data/lib/mark_mapper/extensions/duplicable.rb +86 -0
  28. data/lib/mark_mapper/extensions/float.rb +18 -0
  29. data/lib/mark_mapper/extensions/hash.rb +26 -0
  30. data/lib/mark_mapper/extensions/integer.rb +27 -0
  31. data/lib/mark_mapper/extensions/kernel.rb +11 -0
  32. data/lib/mark_mapper/extensions/nil_class.rb +18 -0
  33. data/lib/mark_mapper/extensions/object.rb +30 -0
  34. data/lib/mark_mapper/extensions/object_id.rb +18 -0
  35. data/lib/mark_mapper/extensions/set.rb +20 -0
  36. data/lib/mark_mapper/extensions/string.rb +31 -0
  37. data/lib/mark_mapper/extensions/symbol.rb +87 -0
  38. data/lib/mark_mapper/extensions/time.rb +29 -0
  39. data/lib/mark_mapper/locale/en.yml +5 -0
  40. data/lib/mark_mapper/middleware/identity_map.rb +41 -0
  41. data/lib/mark_mapper/normalizers/criteria_hash_key.rb +17 -0
  42. data/lib/mark_mapper/normalizers/criteria_hash_value.rb +66 -0
  43. data/lib/mark_mapper/normalizers/fields_value.rb +26 -0
  44. data/lib/mark_mapper/normalizers/hash_key.rb +19 -0
  45. data/lib/mark_mapper/normalizers/integer.rb +19 -0
  46. data/lib/mark_mapper/normalizers/options_hash_value.rb +83 -0
  47. data/lib/mark_mapper/normalizers/sort_value.rb +55 -0
  48. data/lib/mark_mapper/options_hash.rb +103 -0
  49. data/lib/mark_mapper/pagination.rb +6 -0
  50. data/lib/mark_mapper/pagination/collection.rb +32 -0
  51. data/lib/mark_mapper/pagination/paginator.rb +46 -0
  52. data/lib/mark_mapper/plugins.rb +22 -0
  53. data/lib/mark_mapper/plugins/accessible.rb +61 -0
  54. data/lib/mark_mapper/plugins/active_model.rb +18 -0
  55. data/lib/mark_mapper/plugins/associations.rb +96 -0
  56. data/lib/mark_mapper/plugins/associations/base.rb +98 -0
  57. data/lib/mark_mapper/plugins/associations/belongs_to_association.rb +63 -0
  58. data/lib/mark_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +35 -0
  59. data/lib/mark_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  60. data/lib/mark_mapper/plugins/associations/collection.rb +29 -0
  61. data/lib/mark_mapper/plugins/associations/embedded_collection.rb +44 -0
  62. data/lib/mark_mapper/plugins/associations/in_array_proxy.rb +133 -0
  63. data/lib/mark_mapper/plugins/associations/many_association.rb +63 -0
  64. data/lib/mark_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  65. data/lib/mark_mapper/plugins/associations/many_documents_proxy.rb +142 -0
  66. data/lib/mark_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  67. data/lib/mark_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  68. data/lib/mark_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  69. data/lib/mark_mapper/plugins/associations/one_as_proxy.rb +22 -0
  70. data/lib/mark_mapper/plugins/associations/one_association.rb +48 -0
  71. data/lib/mark_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  72. data/lib/mark_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  73. data/lib/mark_mapper/plugins/associations/one_proxy.rb +95 -0
  74. data/lib/mark_mapper/plugins/associations/proxy.rb +138 -0
  75. data/lib/mark_mapper/plugins/associations/single_association.rb +46 -0
  76. data/lib/mark_mapper/plugins/caching.rb +21 -0
  77. data/lib/mark_mapper/plugins/callbacks.rb +42 -0
  78. data/lib/mark_mapper/plugins/clone.rb +24 -0
  79. data/lib/mark_mapper/plugins/counter_cache.rb +97 -0
  80. data/lib/mark_mapper/plugins/dirty.rb +61 -0
  81. data/lib/mark_mapper/plugins/document.rb +41 -0
  82. data/lib/mark_mapper/plugins/dumpable.rb +22 -0
  83. data/lib/mark_mapper/plugins/dynamic_querying.rb +45 -0
  84. data/lib/mark_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  85. data/lib/mark_mapper/plugins/embedded_callbacks.rb +81 -0
  86. data/lib/mark_mapper/plugins/embedded_document.rb +53 -0
  87. data/lib/mark_mapper/plugins/equality.rb +23 -0
  88. data/lib/mark_mapper/plugins/identity_map.rb +144 -0
  89. data/lib/mark_mapper/plugins/indexable.rb +86 -0
  90. data/lib/mark_mapper/plugins/inspect.rb +16 -0
  91. data/lib/mark_mapper/plugins/keys.rb +470 -0
  92. data/lib/mark_mapper/plugins/keys/key.rb +134 -0
  93. data/lib/mark_mapper/plugins/keys/static.rb +45 -0
  94. data/lib/mark_mapper/plugins/logger.rb +18 -0
  95. data/lib/mark_mapper/plugins/modifiers.rb +140 -0
  96. data/lib/mark_mapper/plugins/pagination.rb +16 -0
  97. data/lib/mark_mapper/plugins/partial_updates.rb +77 -0
  98. data/lib/mark_mapper/plugins/persistence.rb +79 -0
  99. data/lib/mark_mapper/plugins/protected.rb +45 -0
  100. data/lib/mark_mapper/plugins/querying.rb +173 -0
  101. data/lib/mark_mapper/plugins/querying/decorated_markmapper_query.rb +75 -0
  102. data/lib/mark_mapper/plugins/rails.rb +79 -0
  103. data/lib/mark_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  104. data/lib/mark_mapper/plugins/sci.rb +82 -0
  105. data/lib/mark_mapper/plugins/scopes.rb +28 -0
  106. data/lib/mark_mapper/plugins/serialization.rb +109 -0
  107. data/lib/mark_mapper/plugins/timestamps.rb +29 -0
  108. data/lib/mark_mapper/plugins/touch.rb +18 -0
  109. data/lib/mark_mapper/plugins/userstamps.rb +18 -0
  110. data/lib/mark_mapper/plugins/validations.rb +96 -0
  111. data/lib/mark_mapper/query.rb +278 -0
  112. data/lib/mark_mapper/railtie.rb +52 -0
  113. data/lib/mark_mapper/railtie/database.rake +65 -0
  114. data/lib/mark_mapper/translation.rb +10 -0
  115. data/lib/mark_mapper/version.rb +4 -0
  116. data/lib/rails/generators/mark_mapper/config/config_generator.rb +37 -0
  117. data/lib/rails/generators/mark_mapper/config/templates/marklogic.yml +19 -0
  118. data/lib/rails/generators/mark_mapper/model/model_generator.rb +40 -0
  119. data/lib/rails/generators/mark_mapper/model/templates/model.rb +17 -0
  120. data/spec/config/mark_mapper.yml +6 -0
  121. data/spec/examples_spec.rb +25 -0
  122. data/spec/functional/accessible_spec.rb +198 -0
  123. data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +64 -0
  124. data/spec/functional/associations/belongs_to_proxy_spec.rb +255 -0
  125. data/spec/functional/associations/in_array_proxy_spec.rb +349 -0
  126. data/spec/functional/associations/many_documents_as_proxy_spec.rb +230 -0
  127. data/spec/functional/associations/many_documents_proxy_spec.rb +968 -0
  128. data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +238 -0
  129. data/spec/functional/associations/many_embedded_proxy_spec.rb +288 -0
  130. data/spec/functional/associations/many_polymorphic_proxy_spec.rb +302 -0
  131. data/spec/functional/associations/one_as_proxy_spec.rb +489 -0
  132. data/spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb +207 -0
  133. data/spec/functional/associations/one_embedded_proxy_spec.rb +100 -0
  134. data/spec/functional/associations/one_proxy_spec.rb +406 -0
  135. data/spec/functional/associations_spec.rb +48 -0
  136. data/spec/functional/caching_spec.rb +75 -0
  137. data/spec/functional/callbacks_spec.rb +330 -0
  138. data/spec/functional/counter_cache_spec.rb +235 -0
  139. data/spec/functional/dirty_spec.rb +316 -0
  140. data/spec/functional/document_spec.rb +310 -0
  141. data/spec/functional/dumpable_spec.rb +24 -0
  142. data/spec/functional/dynamic_querying_spec.rb +75 -0
  143. data/spec/functional/embedded_document_spec.rb +316 -0
  144. data/spec/functional/equality_spec.rb +20 -0
  145. data/spec/functional/extensions_spec.rb +16 -0
  146. data/spec/functional/identity_map_spec.rb +483 -0
  147. data/spec/functional/keys_spec.rb +339 -0
  148. data/spec/functional/logger_spec.rb +20 -0
  149. data/spec/functional/modifiers_spec.rb +446 -0
  150. data/spec/functional/options_hash_spec.rb +41 -0
  151. data/spec/functional/pagination_spec.rb +89 -0
  152. data/spec/functional/partial_updates_spec.rb +530 -0
  153. data/spec/functional/protected_spec.rb +199 -0
  154. data/spec/functional/querying_spec.rb +984 -0
  155. data/spec/functional/rails_spec.rb +55 -0
  156. data/spec/functional/sci_spec.rb +374 -0
  157. data/spec/functional/scopes_spec.rb +204 -0
  158. data/spec/functional/static_keys_spec.rb +153 -0
  159. data/spec/functional/timestamps_spec.rb +97 -0
  160. data/spec/functional/touch_spec.rb +125 -0
  161. data/spec/functional/userstamps_spec.rb +46 -0
  162. data/spec/functional/validations_spec.rb +416 -0
  163. data/spec/quality_spec.rb +51 -0
  164. data/spec/spec_helper.rb +150 -0
  165. data/spec/support/matchers.rb +15 -0
  166. data/spec/support/models.rb +256 -0
  167. data/spec/symbol_operator_spec.rb +70 -0
  168. data/spec/symbol_spec.rb +9 -0
  169. data/spec/unit/associations/base_spec.rb +146 -0
  170. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  171. data/spec/unit/associations/many_association_spec.rb +64 -0
  172. data/spec/unit/associations/one_association_spec.rb +48 -0
  173. data/spec/unit/associations/proxy_spec.rb +103 -0
  174. data/spec/unit/clone_spec.rb +79 -0
  175. data/spec/unit/config_generator_spec.rb +24 -0
  176. data/spec/unit/criteria_hash_spec.rb +218 -0
  177. data/spec/unit/document_spec.rb +251 -0
  178. data/spec/unit/dynamic_finder_spec.rb +125 -0
  179. data/spec/unit/embedded_document_spec.rb +676 -0
  180. data/spec/unit/equality_spec.rb +38 -0
  181. data/spec/unit/exceptions_spec.rb +12 -0
  182. data/spec/unit/extensions_spec.rb +368 -0
  183. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  184. data/spec/unit/inspect_spec.rb +47 -0
  185. data/spec/unit/key_spec.rb +276 -0
  186. data/spec/unit/keys_spec.rb +155 -0
  187. data/spec/unit/mark_mapper_spec.rb +37 -0
  188. data/spec/unit/model_generator_spec.rb +45 -0
  189. data/spec/unit/normalizers/criteria_hash_key_spec.rb +37 -0
  190. data/spec/unit/normalizers/criteria_hash_value_spec.rb +200 -0
  191. data/spec/unit/normalizers/fields_value_spec.rb +45 -0
  192. data/spec/unit/normalizers/hash_key_spec.rb +15 -0
  193. data/spec/unit/normalizers/integer_spec.rb +24 -0
  194. data/spec/unit/normalizers/options_hash_value_spec.rb +99 -0
  195. data/spec/unit/normalizers/sort_value_spec.rb +98 -0
  196. data/spec/unit/options_hash_spec.rb +64 -0
  197. data/spec/unit/pagination/collection_spec.rb +30 -0
  198. data/spec/unit/pagination/paginator_spec.rb +118 -0
  199. data/spec/unit/pagination_spec.rb +11 -0
  200. data/spec/unit/plugins_spec.rb +89 -0
  201. data/spec/unit/query_spec.rb +837 -0
  202. data/spec/unit/rails_compatibility_spec.rb +40 -0
  203. data/spec/unit/rails_reflect_on_association_spec.rb +118 -0
  204. data/spec/unit/rails_spec.rb +188 -0
  205. data/spec/unit/serialization_spec.rb +169 -0
  206. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  207. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  208. data/spec/unit/time_zones_spec.rb +44 -0
  209. data/spec/unit/translation_spec.rb +27 -0
  210. data/spec/unit/validations_spec.rb +588 -0
  211. metadata +307 -0
@@ -0,0 +1,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