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,125 @@
1
+ require 'spec_helper'
2
+
3
+ describe "DynamicFinder" do
4
+ DynamicFinder = MarkMapper::Plugins::DynamicQuerying::DynamicFinder
5
+
6
+ it "should initialize with method" do
7
+ finder = DynamicFinder.new(:foobar)
8
+ finder.method.should == :foobar
9
+ end
10
+
11
+ context "found?" do
12
+ it "should be true for find_by" do
13
+ DynamicFinder.new(:find_by_foo).found?.should be_truthy
14
+ end
15
+
16
+ it "should be true for find_by with !" do
17
+ DynamicFinder.new(:find_by_foo!).found?.should be_truthy
18
+ end
19
+
20
+ it "should be true for find_all_by" do
21
+ DynamicFinder.new(:find_all_by_foo).found?.should be_truthy
22
+ end
23
+
24
+ it "should be true for find_or_initialize_by" do
25
+ DynamicFinder.new(:find_or_initialize_by_foo).found?.should be_truthy
26
+ end
27
+
28
+ it "should be true for find_or_create_by" do
29
+ DynamicFinder.new(:find_or_create_by_foo).found?.should be_truthy
30
+ end
31
+
32
+ it "should be false for anything else" do
33
+ [:foobar, :bazwick].each do |method|
34
+ DynamicFinder.new(method).found?.should be_falsey
35
+ end
36
+ end
37
+ end
38
+
39
+ context "find_all_by" do
40
+ it "should parse one attribute" do
41
+ DynamicFinder.new(:find_all_by_foo).attributes.should == %w(foo)
42
+ end
43
+
44
+ it "should parse multiple attributes" do
45
+ DynamicFinder.new(:find_all_by_foo_and_bar).attributes.should == %w(foo bar)
46
+ DynamicFinder.new(:find_all_by_foo_and_bar_and_baz).attributes.should == %w(foo bar baz)
47
+ end
48
+
49
+ it "should set finder to :all" do
50
+ DynamicFinder.new(:find_all_by_foo_and_bar).finder.should == :all
51
+ end
52
+ end
53
+
54
+ context "find_by" do
55
+ it "should parse one attribute" do
56
+ DynamicFinder.new(:find_by_foo).attributes.should == %w(foo)
57
+ end
58
+
59
+ it "should parse multiple attributes" do
60
+ DynamicFinder.new(:find_by_foo_and_bar).attributes.should == %w(foo bar)
61
+ end
62
+
63
+ it "should set finder to :first" do
64
+ DynamicFinder.new(:find_by_foo).finder.should == :first
65
+ end
66
+
67
+ it "should set bang to false" do
68
+ DynamicFinder.new(:find_by_foo).bang.should be_falsey
69
+ end
70
+ end
71
+
72
+ context "find_by with !" do
73
+ it "should parse one attribute" do
74
+ DynamicFinder.new(:find_by_foo!).attributes.should == %w(foo)
75
+ end
76
+
77
+ it "should parse multiple attributes" do
78
+ DynamicFinder.new(:find_by_foo_and_bar!).attributes.should == %w(foo bar)
79
+ end
80
+
81
+ it "should set finder to :first" do
82
+ DynamicFinder.new(:find_by_foo!).finder.should == :first
83
+ end
84
+
85
+ it "should set bang to true" do
86
+ DynamicFinder.new(:find_by_foo!).bang.should be_truthy
87
+ end
88
+ end
89
+
90
+ context "find_or_initialize_by" do
91
+ it "should parse one attribute" do
92
+ DynamicFinder.new(:find_or_initialize_by_foo).attributes.should == %w(foo)
93
+ end
94
+
95
+ it "should parse multiple attributes" do
96
+ DynamicFinder.new(:find_or_initialize_by_foo_and_bar).attributes.should == %w(foo bar)
97
+ end
98
+
99
+ it "should set finder to :first" do
100
+ DynamicFinder.new(:find_or_initialize_by_foo).finder.should == :first
101
+ end
102
+
103
+ it "should set instantiator to new" do
104
+ DynamicFinder.new(:find_or_initialize_by_foo).instantiator.should == :new
105
+ end
106
+ end
107
+
108
+ context "find_or_create_by" do
109
+ it "should parse one attribute" do
110
+ DynamicFinder.new(:find_or_create_by_foo).attributes.should == %w(foo)
111
+ end
112
+
113
+ it "should parse multiple attributes" do
114
+ DynamicFinder.new(:find_or_create_by_foo_and_bar).attributes.should == %w(foo bar)
115
+ end
116
+
117
+ it "should set finder to :first" do
118
+ DynamicFinder.new(:find_or_create_by_foo).finder.should == :first
119
+ end
120
+
121
+ it "should set instantiator to new" do
122
+ DynamicFinder.new(:find_or_create_by_foo).instantiator.should == :create
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,676 @@
1
+ require 'spec_helper'
2
+
3
+ module KeyOverride
4
+ def other_child
5
+ self[:other_child] || "special result"
6
+ end
7
+
8
+ def other_child=(value)
9
+ super(value + " modified")
10
+ end
11
+ end
12
+
13
+ describe "EmbeddedDocument" do
14
+ context "EmbeddedDocuments" do
15
+ before do
16
+ class ::Grandparent
17
+ include MarkMapper::EmbeddedDocument
18
+ key :grandparent, String
19
+ end
20
+
21
+ class ::Parent < ::Grandparent
22
+ include MarkMapper::EmbeddedDocument
23
+ key :parent, String
24
+ end
25
+
26
+ class ::Child < ::Parent
27
+ include MarkMapper::EmbeddedDocument
28
+ key :child, String
29
+ end
30
+
31
+ class ::OtherChild < ::Parent
32
+ include MarkMapper::EmbeddedDocument
33
+ include KeyOverride
34
+
35
+ key :other_child, String
36
+ end
37
+
38
+ class ::EDocWithAValidation
39
+ include MarkMapper::EmbeddedDocument
40
+ key :name, String, :required => true
41
+ end
42
+
43
+ class ::DocWithAValidation
44
+ include MarkMapper::Document
45
+ key :name, String, :required => true
46
+ many :e_doc_with_a_validations
47
+ end
48
+ end
49
+
50
+ after do
51
+ Object.send :remove_const, 'Grandparent' if defined?(::Grandparent)
52
+ Object.send :remove_const, 'Parent' if defined?(::Parent)
53
+ Object.send :remove_const, 'Child' if defined?(::Child)
54
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
55
+ Object.send :remove_const, 'EDocWithAValidation' if defined?(::EDocWithAValidation)
56
+ Object.send :remove_const, 'DocWithAValidation' if defined?(::DocWithAValidation)
57
+ end
58
+
59
+ context "Including MarkMapper::EmbeddedDocument in a class" do
60
+ before do
61
+ @klass = EDoc()
62
+ end
63
+
64
+ it "should add _id key" do
65
+ @klass.keys['_id'].should_not be_nil
66
+ end
67
+
68
+ it "should know it is using object id" do
69
+ @klass.using_object_id?.should be_truthy
70
+ end
71
+
72
+ it "should know it is not using object id if _id type is changed" do
73
+ @klass.key :_id, String
74
+ @klass.using_object_id?.should be_falsey
75
+ end
76
+ end
77
+
78
+ context "Class Methods" do
79
+ it "should include logger" do
80
+ @klass = EDoc()
81
+ @klass.logger.should == MarkMapper.logger
82
+ @klass.logger.should be_instance_of(Logger)
83
+ end
84
+
85
+ it "should return false for embeddable" do
86
+ EDoc().embeddable?.should be_truthy
87
+ end
88
+
89
+ context "#to_marklogic" do
90
+ before { @klass = EDoc() }
91
+
92
+ it "should be nil if nil" do
93
+ @klass.to_marklogic(nil).should be_nil
94
+ end
95
+
96
+ it "should convert to_marklogic for other values" do
97
+ doc = @klass.new(:foo => 'bar')
98
+ to_marklogic = @klass.to_marklogic(doc)
99
+ to_marklogic.is_a?(Hash).should be_truthy
100
+ to_marklogic['foo'].should == 'bar'
101
+ end
102
+ end
103
+
104
+ context "#from_marklogic" do
105
+ before { @klass = EDoc() }
106
+
107
+ it "should be nil if nil" do
108
+ @klass.from_marklogic(nil).should be_nil
109
+ end
110
+
111
+ it "should be instance if instance of class" do
112
+ doc = @klass.new
113
+ @klass.from_marklogic(doc).should == doc
114
+ end
115
+
116
+ it "should be instance if hash of attributes" do
117
+ doc = @klass.from_marklogic({:foo => 'bar'})
118
+ doc.instance_of?(@klass).should be_truthy
119
+ doc.foo.should == 'bar'
120
+ end
121
+ end
122
+
123
+ context "defining a key" do
124
+ before do
125
+ @document = EDoc()
126
+ end
127
+
128
+ it "should work with name" do
129
+ key = @document.key(:name)
130
+ key.name.should == 'name'
131
+ end
132
+
133
+ it "should work with name and type" do
134
+ key = @document.key(:name, String)
135
+ key.name.should == 'name'
136
+ key.type.should == String
137
+ end
138
+
139
+ it "should work with name, type and options" do
140
+ key = @document.key(:name, String, :required => true)
141
+ key.name.should == 'name'
142
+ key.type.should == String
143
+ key.options[:required].should be_truthy
144
+ end
145
+
146
+ it "should work with name and options" do
147
+ key = @document.key(:name, :required => true)
148
+ key.name.should == 'name'
149
+ key.options[:required].should be_truthy
150
+ end
151
+
152
+ it "should be tracked per document" do
153
+ @document.key(:name, String)
154
+ @document.key(:age, Integer)
155
+ @document.keys['name'].name.should == 'name'
156
+ @document.keys['name'].type.should == String
157
+ @document.keys['age'].name.should == 'age'
158
+ @document.keys['age'].type.should == Integer
159
+ end
160
+
161
+ it "should be redefinable" do
162
+ @document.key(:foo, String)
163
+ @document.keys['foo'].type.should == String
164
+ @document.key(:foo, Integer)
165
+ @document.keys['foo'].type.should == Integer
166
+ end
167
+
168
+ it "should create reader method" do
169
+ @document.new.should_not respond_to(:foo)
170
+ @document.key(:foo, String)
171
+ @document.new.should respond_to(:foo)
172
+ end
173
+
174
+ it "should create reader before type cast method" do
175
+ @document.new.should_not respond_to(:foo_before_type_cast)
176
+ @document.key(:foo, String)
177
+ @document.new.should respond_to(:foo_before_type_cast)
178
+ end
179
+
180
+ it "should create writer method" do
181
+ @document.new.should_not respond_to(:foo=)
182
+ @document.key(:foo, String)
183
+ @document.new.should respond_to(:foo=)
184
+ end
185
+
186
+ it "should create boolean method" do
187
+ @document.new.should_not respond_to(:foo?)
188
+ @document.key(:foo, String)
189
+ @document.new.should respond_to(:foo?)
190
+ end
191
+ end
192
+
193
+ context "keys" do
194
+ it "should be inherited" do
195
+ Grandparent.keys.keys.sort.should == ['_id', '_type', 'grandparent']
196
+ Parent.keys.keys.sort.should == ['_id', '_type', 'grandparent', 'parent']
197
+ Child.keys.keys.sort.should == ['_id', '_type', 'child', 'grandparent', 'parent']
198
+ end
199
+
200
+ it "should propogate to descendants if key added after class definition" do
201
+ Grandparent.key :foo, String
202
+
203
+ Grandparent.keys.keys.sort.should == ['_id', '_type', 'foo', 'grandparent']
204
+ Parent.keys.keys.sort.should == ['_id', '_type', 'foo', 'grandparent', 'parent']
205
+ Child.keys.keys.sort.should == ['_id', '_type', 'child', 'foo', 'grandparent', 'parent']
206
+ end
207
+
208
+ it "should not add anonymous objects to the ancestor tree" do
209
+ OtherChild.ancestors.any? { |a| a.name.blank? }.should be_falsey
210
+ end
211
+
212
+ it "should not include descendant keys" do
213
+ lambda { Parent.new.other_child }.should raise_error
214
+ end
215
+ end
216
+
217
+ context "descendants" do
218
+ it "should default to an empty array" do
219
+ Child.descendants.should == []
220
+ end
221
+
222
+ it "should be recorded" do
223
+ Grandparent.direct_descendants.should == [Parent]
224
+ Grandparent.descendants.to_set.should == [Parent, Child, OtherChild].to_set
225
+
226
+ Parent.descendants.should == [Child, OtherChild]
227
+ end
228
+ end
229
+ end
230
+
231
+ context "An instance of an embedded document" do
232
+ before do
233
+ @document = EDoc do
234
+ key :name, String
235
+ key :age, Integer
236
+ end
237
+ end
238
+
239
+ it "should respond to cache_key" do
240
+ @document.new.should respond_to(:cache_key)
241
+ end
242
+
243
+ it "should have access to class logger" do
244
+ doc = @document.new
245
+ doc.logger.should == @document.logger
246
+ doc.logger.should be_instance_of(Logger)
247
+ end
248
+
249
+ it "should automatically have an _id key" do
250
+ @document.keys.keys.should include('_id')
251
+ end
252
+
253
+ it "should create id during initialization" do
254
+ @document.new._id.should be_instance_of(MarkLogic::ObjectId)
255
+ end
256
+
257
+ it "should have id method returns _id" do
258
+ id = MarkLogic::ObjectId.new
259
+ doc = @document.new(:_id => id)
260
+ doc.id.should == id
261
+ end
262
+
263
+ it "should convert string object id to marklogic object id when assigning id with _id object id type" do
264
+ id = MarkLogic::ObjectId.new
265
+ doc = @document.new(:id => id.to_s)
266
+ doc._id.should == id
267
+ doc.id.should == id
268
+ doc = @document.new(:_id => id.to_s)
269
+ doc._id.should == id
270
+ doc.id.should == id
271
+ end
272
+
273
+ context "_parent_document" do
274
+ it "should default to nil" do
275
+ @document.new._parent_document.should be_nil
276
+ @document.new._root_document.should be_nil
277
+ end
278
+
279
+ it "should set _root_document when setting _parent_document" do
280
+ root = Doc().new
281
+ doc = @document.new(:_parent_document => root)
282
+ doc._parent_document.should be(root)
283
+ doc._root_document.should be(root)
284
+ end
285
+
286
+ it "should set _root_document when setting _parent_document on embedded many" do
287
+ root = Doc().new
288
+ klass = EDoc { many :children }
289
+ parent = klass.new(:_parent_document => root, :children => [{}])
290
+ child = parent.children.first
291
+ child._parent_document.should be(parent)
292
+ child._root_document.should be(root)
293
+ end
294
+ end
295
+
296
+ context "being initialized" do
297
+ it "should accept a hash that sets keys and values" do
298
+ doc = @document.new(:name => 'John', :age => 23)
299
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
300
+ doc.attributes['name'].should == 'John'
301
+ doc.attributes['age'].should == 23
302
+ end
303
+
304
+ it "should be able to assign keys dynamically" do
305
+ doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
306
+ doc.name.should == 'John'
307
+ doc.skills.should == ['ruby', 'rails']
308
+ end
309
+
310
+ it "should not throw error if initialized with nil" do
311
+ expect { @document.new(nil) }.to_not raise_error
312
+ end
313
+ end
314
+
315
+ context "initialized when _type key present" do
316
+ before do
317
+ @klass = EDoc('FooBar') { key :_type, String }
318
+ end
319
+
320
+ it "should set _type to class name" do
321
+ @klass.new._type.should == 'FooBar'
322
+ end
323
+
324
+ it "should ignore _type attribute and always use class" do
325
+ @klass.new(:_type => 'Foo')._type.should == 'FooBar'
326
+ end
327
+ end
328
+
329
+ context "attributes=" do
330
+ it "should update values for keys provided" do
331
+ doc = @document.new(:name => 'foobar', :age => 10)
332
+ doc.attributes = {:name => 'new value', :age => 5}
333
+ doc.attributes[:name].should == 'new value'
334
+ doc.attributes[:age].should == 5
335
+ end
336
+
337
+ it "should not update values for keys that were not provided" do
338
+ doc = @document.new(:name => 'foobar', :age => 10)
339
+ doc.attributes = {:name => 'new value'}
340
+ doc.attributes[:name].should == 'new value'
341
+ doc.attributes[:age].should == 10
342
+ end
343
+
344
+ it "should work with pre-defined methods" do
345
+ @document.class_eval do
346
+ attr_writer :password
347
+
348
+ def passwd
349
+ @password
350
+ end
351
+ end
352
+
353
+ doc = @document.new(:name => 'foobar', :password => 'secret')
354
+ doc.passwd.should == 'secret'
355
+ end
356
+
357
+ it "should type cast key values" do
358
+ doc = @document.new(:name => 1234, :age => '21')
359
+ doc.name.should == '1234'
360
+ doc.age.should == 21
361
+ end
362
+ end
363
+
364
+ context "attributes" do
365
+ it "should default to hash with all keys" do
366
+ doc = @document.new
367
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
368
+ doc.attributes.keys.sort.should == ['_id']
369
+ end
370
+
371
+ it "should return all keys with values" do
372
+ doc = @document.new(:name => 'string', :age => nil)
373
+ doc.attributes.keys.sort.should == ['_id', 'name']
374
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
375
+ doc.attributes.values.should include('string')
376
+ doc.attributes.values.should_not include(nil)
377
+ end
378
+
379
+ it "should have indifferent access" do
380
+ doc = @document.new(:name => 'string')
381
+ doc.attributes[:name].should == 'string'
382
+ doc.attributes['name'].should == 'string'
383
+ end
384
+ end
385
+
386
+ context "to_marklogic" do
387
+ it "should default to hash with _id key" do
388
+ doc = @document.new
389
+ doc.to_marklogic.keys.sort.should == ['_id']
390
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
391
+ end
392
+
393
+ it "should return all keys" do
394
+ doc = @document.new(:name => 'string', :age => nil)
395
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
396
+ doc.to_marklogic.keys.sort.should == ['_id','name']
397
+ doc.to_marklogic.values.should include('string')
398
+ doc.to_marklogic.values.should_not include(nil)
399
+ end
400
+ end
401
+
402
+ context "key shorcut access" do
403
+ context "[]" do
404
+ it "should work when key found" do
405
+ doc = @document.new(:name => 'string')
406
+ doc[:name].should == 'string'
407
+ end
408
+
409
+ it "should return nil when not found" do
410
+ doc = @document.new(:name => 'string')
411
+ doc[:not_here].should be_nil
412
+ end
413
+ end
414
+
415
+ context "[]=" do
416
+ it "should write key value for existing key" do
417
+ doc = @document.new
418
+ doc[:name] = 'string'
419
+ doc[:name].should == 'string'
420
+ end
421
+
422
+ it "should create key and write value for missing key" do
423
+ doc = @document.new
424
+ doc[:foo] = 'string'
425
+ doc.class.keys.include?('foo').should be_truthy
426
+ doc[:foo].should == 'string'
427
+ end
428
+
429
+ it "should share the new key with the class" do
430
+ doc = @document.new
431
+ doc[:foo] = 'string'
432
+ @document.keys.should include('foo')
433
+ end
434
+ end
435
+ end
436
+
437
+ context "reading a key" do
438
+ it "should work for defined keys" do
439
+ doc = @document.new(:name => 'string')
440
+ doc.name.should == 'string'
441
+ end
442
+
443
+ it "should raise no method error for undefined keys" do
444
+ doc = @document.new
445
+ lambda { doc.fart }.should raise_error(NoMethodError)
446
+ end
447
+
448
+ it "should be accessible for use in the model" do
449
+ @document.class_eval do
450
+ def name_and_age
451
+ "#{self[:name]} (#{self[:age]})"
452
+ end
453
+ end
454
+
455
+ doc = @document.new(:name => 'John', :age => 27)
456
+ doc.name_and_age.should == 'John (27)'
457
+ end
458
+
459
+ it "should set instance variable" do
460
+ @document.key :foo, Array
461
+ doc = @document.new
462
+ doc.instance_variable_get("@foo").should be_nil
463
+ doc.foo
464
+ doc.instance_variable_get("@foo").should == []
465
+ end
466
+
467
+ it "should be overrideable by modules" do
468
+ @document = Doc do
469
+ key :other_child, String
470
+ end
471
+
472
+ child = @document.new
473
+ child.other_child.should be_nil
474
+
475
+ @document.send :include, KeyOverride
476
+
477
+ overriden_child = @document.new
478
+ overriden_child.other_child.should == 'special result'
479
+ end
480
+ end
481
+
482
+ context "reading a key before typcasting" do
483
+ it "should work for defined keys" do
484
+ doc = @document.new(:name => 12)
485
+ doc.name_before_type_cast.should == 12
486
+ end
487
+
488
+ it "should raise no method error for undefined keys" do
489
+ doc = @document.new
490
+ lambda { doc.foo_before_type_cast }.should raise_error(NoMethodError)
491
+ end
492
+
493
+ it "should be accessible for use in a document" do
494
+ doc = @document.new(:name => 12)
495
+ doc.name.should == '12'
496
+ doc.name_before_type_cast.should == 12
497
+ end
498
+ end
499
+
500
+ context "writing a key" do
501
+ it "should work for defined keys" do
502
+ doc = @document.new
503
+ doc.name = 'John'
504
+ doc.name.should == 'John'
505
+ end
506
+
507
+ it "should raise no method error for undefined keys" do
508
+ doc = @document.new
509
+ lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
510
+ end
511
+
512
+ it "should type cast value" do
513
+ doc = @document.new
514
+ doc.name = 1234
515
+ doc.name.should == '1234'
516
+ doc.age = '21'
517
+ doc.age.should == 21
518
+ end
519
+
520
+ it "should be accessible for use in the model" do
521
+ @document.class_eval do
522
+ def name_and_age=(new_value)
523
+ new_value.match(/([^\(\s]+) \((.*)\)/)
524
+ write_key :name, $1
525
+ write_key :age, $2
526
+ end
527
+ end
528
+
529
+ doc = @document.new
530
+ doc.name_and_age = 'Frank (62)'
531
+ doc.name.should == 'Frank'
532
+ doc.age.should == 62
533
+ end
534
+
535
+ it "should be overrideable by modules" do
536
+ @document = Doc do
537
+ key :other_child, String
538
+ end
539
+
540
+ child = @document.new(:other_child => 'foo')
541
+ child.other_child.should == 'foo'
542
+
543
+ @document.send :include, KeyOverride
544
+
545
+ overriden_child = @document.new(:other_child => 'foo')
546
+ overriden_child.other_child.should == 'foo modified'
547
+ end
548
+ end # writing a key
549
+
550
+ context "checking if a keys value is present" do
551
+ it "should work for defined keys" do
552
+ doc = @document.new
553
+ doc.name?.should be_falsey
554
+ doc.name = 'John'
555
+ doc.name?.should be_truthy
556
+ end
557
+
558
+ it "should raise no method error for undefined keys" do
559
+ doc = @document.new
560
+ lambda { doc.fart? }.should raise_error(NoMethodError)
561
+ end
562
+ end
563
+
564
+ context "equality" do
565
+ before do
566
+ @oid = MarkLogic::ObjectId.new
567
+ end
568
+
569
+ it "should delegate hash to _id" do
570
+ doc = @document.new
571
+ doc.hash.should == doc._id.hash
572
+ end
573
+
574
+ it "should delegate eql to ==" do
575
+ doc = @document.new
576
+ other = @document.new
577
+ doc.eql?(other).should == (doc == other)
578
+ doc.eql?(doc).should == (doc == doc)
579
+ end
580
+
581
+ it "should know if same object as another" do
582
+ doc = @document.new
583
+ doc.should equal(doc)
584
+ doc.should_not equal(@document.new)
585
+ end
586
+
587
+ it "should allow set operations on array of documents" do
588
+ doc = @document.new
589
+ ([doc] & [doc]).should == [doc]
590
+ end
591
+
592
+ it "should be equal if id and class are the same" do
593
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be_truthy
594
+ end
595
+
596
+ it "should not be equal if class same but id different" do
597
+ (@document.new('_id' => @oid) == @document.new('_id' => MarkLogic::ObjectId.new)).should be_falsey
598
+ end
599
+
600
+ it "should not be equal if id same but class different" do
601
+ another_document = Doc()
602
+ (@document.new('_id' => @oid) == another_document.new('_id' => @oid)).should be_falsey
603
+ end
604
+ end
605
+
606
+ context "reading keys with default values" do
607
+ before do
608
+ @document = EDoc do
609
+ key :name, String, :default => 'foo'
610
+ key :age, Integer, :default => 20
611
+ key :net_worth, Float, :default => 100.00
612
+ key :active, Boolean, :default => true
613
+ key :smart, Boolean, :default => false
614
+ key :skills, Array, :default => [1]
615
+ key :options, Hash, :default => {'foo' => 'bar'}
616
+ end
617
+
618
+ @doc = @document.new
619
+ end
620
+
621
+ it "should work for strings" do
622
+ @doc.name.should == 'foo'
623
+ end
624
+
625
+ it "should work for integers" do
626
+ @doc.age.should == 20
627
+ end
628
+
629
+ it "should work for floats" do
630
+ @doc.net_worth.should == 100.00
631
+ end
632
+
633
+ it "should work for booleans" do
634
+ @doc.active.should == true
635
+ @doc.smart.should == false
636
+ end
637
+
638
+ it "should work for arrays" do
639
+ @doc.skills.should == [1]
640
+ @doc.skills << 2
641
+ @doc.skills.should == [1, 2]
642
+ end
643
+
644
+ it "should work for hashes" do
645
+ @doc.options['foo'].should == 'bar'
646
+ @doc.options['baz'] = 'wick'
647
+ @doc.options['baz'].should == 'wick'
648
+ end
649
+ end
650
+
651
+ context "#save!" do
652
+ before do
653
+ @root = DocWithAValidation.create(:name => "Root")
654
+ @doc = @root.e_doc_with_a_validations.build :name => "Embedded"
655
+ end
656
+
657
+ it "should should save when valid" do
658
+ @doc.save!
659
+ @root.reload.e_doc_with_a_validations.first.should == @doc
660
+ end
661
+
662
+ it "should should raise errors when invalid" do
663
+ @doc.name = ''
664
+ expect { @doc.save! }.to raise_error(MarkMapper::DocumentNotValid)
665
+ end
666
+
667
+ it "should should raise errors when root document is invalid" do
668
+ @root.name = ''
669
+ @root.save(:validate => false)
670
+ expect{ @doc.save! }.to raise_error(MarkMapper::DocumentNotValid)
671
+ end
672
+ end
673
+ end # instance of a embedded document
674
+ end
675
+ end
676
+