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,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Documents with the Rails plugin" do
4
+ let(:doc) { Doc {
5
+ key :foo, String
6
+ key :long_field, String, :alias => "lf"
7
+ }}
8
+
9
+ context "with values from the DB" do
10
+ subject { doc.create(:foo => "bar", :long_field => "long value") }
11
+ it "should have x_before_type_cast" do
12
+ subject.foo_before_type_cast.should == "bar"
13
+ end
14
+
15
+ it "should have x_before_type_cast for aliased fields" do
16
+ subject.long_field_before_type_cast.should == "long value"
17
+ end
18
+
19
+ it "should honor app-set values over DB-set values" do
20
+ subject.foo = nil
21
+ subject.foo_before_type_cast.should == nil
22
+ end
23
+ end
24
+
25
+ context "when blank" do
26
+ subject { doc.create() }
27
+ it "should have x_before_type_cast" do
28
+ subject.foo_before_type_cast.should == nil
29
+ end
30
+
31
+ it "should honor app-set values over DB-set values" do
32
+ subject.foo = nil
33
+ subject.foo_before_type_cast.should == nil
34
+
35
+ subject.foo = :baz
36
+ subject.foo_before_type_cast.should == :baz
37
+
38
+ subject.save
39
+ subject.reload.foo_before_type_cast.should == "baz"
40
+ end
41
+ end
42
+
43
+ context "#has_one" do
44
+ subject do
45
+ Doc do
46
+ has_one :foo
47
+ end
48
+ end
49
+
50
+ it "should create a one association" do
51
+ subject.associations.should have_key :foo
52
+ subject.associations[:foo].should be_a MarkMapper::Plugins::Associations::OneAssociation
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,374 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Single collection inheritance (document)" do
4
+ # context "without a connection", :without_connection => true do
5
+ # it "should attempt to create a connection during inheritance" do
6
+ # expect(MarkLogic::Connection).to_not receive(:new)
7
+ # doc = Class.new
8
+ # doc.send(:include, MarkMapper::Document)
9
+ # expect {
10
+ # Class.new(doc)
11
+ # }.to_not raise_error
12
+ # end
13
+
14
+ # it "should pick up a connection if one wasn't set" do
15
+ # doc = Class.new
16
+ # doc.send(:include, MarkMapper::Document)
17
+ # klass = Class.new(doc)
18
+ # klass.connection.should be_nil
19
+ # MarkMapper.connection
20
+ # klass.connection.should be_a MarkLogic::Connection
21
+ # end
22
+ # end
23
+
24
+ context "with a connection" do
25
+ before do
26
+ class ::DocParent
27
+ include MarkMapper::Document
28
+ key :name, String
29
+ end
30
+ DocParent.collection.remove
31
+
32
+ class ::DocDaughter < ::DocParent; end
33
+ class ::DocSon < ::DocParent; end
34
+ class ::DocGrandSon < ::DocSon; end
35
+ class ::DocGrandGrandSon < ::DocGrandSon; end
36
+
37
+ DocSon.many :children, :class_name => 'DocGrandSon'
38
+
39
+ @parent = DocParent.new({:name => "Daddy Warbucks"})
40
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
41
+ end
42
+
43
+ after do
44
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
45
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
46
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
47
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
48
+ Object.send :remove_const, 'DocGrandGrandSon' if defined?(::DocGrandGrandSon)
49
+ end
50
+
51
+ it "should automatically add _type key to store class" do
52
+ DocParent.key?(:_type).should be_truthy
53
+ end
54
+
55
+ it "should use the same connection in the subclass" do
56
+ parent_class = Class.new do
57
+ include MarkMapper::Document
58
+ connection MarkLogic::Connection.new(HOST, PORT)
59
+ end
60
+
61
+ child_class = Class.new(parent_class) do
62
+ include MarkMapper::Document
63
+ end
64
+
65
+ child_class.connection.should == child_class.connection
66
+ end
67
+
68
+ it "should use the same database in the subclass" do
69
+ parent_class = Class.new do
70
+ include MarkMapper::Document
71
+ database = MarkMapper.application.content_databases[0]
72
+ end
73
+
74
+ child_class = Class.new(parent_class) do
75
+ include MarkMapper::Document
76
+ end
77
+
78
+ child_class.database.should == MarkMapper.application.content_databases[0]
79
+ end
80
+
81
+ it "should use the same collection in the subclass" do
82
+ DocDaughter.collection.name.should == DocParent.collection.name
83
+ end
84
+
85
+ context "if the subclass changes its collection" do
86
+ before do
87
+ class ::DocSCIOrphan < ::DocParent
88
+ set_collection_name "foobars"
89
+ end
90
+ end
91
+
92
+ after do
93
+ Object.send :remove_const, 'DocSCIOrphan' if defined?(::DocSCIOrphan)
94
+ end
95
+
96
+ it "should negate SCI" do
97
+ DocSCIOrphan.collection.name.should == "foobars"
98
+ DocSCIOrphan.should_not be_single_collection_inherited
99
+ end
100
+
101
+ it "should remove the _type key" do
102
+ DocParent.keys.should_not have_key "_type"
103
+ DocSCIOrphan.keys.should_not have_key "_type"
104
+ end
105
+
106
+ context "and then is subclassed again" do
107
+ before do
108
+ class ::DocSCIOrphanChild < ::DocSCIOrphan
109
+ end
110
+ end
111
+
112
+ after do
113
+ Object.send :remove_const, 'DocSCIOrphanChild' if defined?(::DocSCIOrphanChild)
114
+ end
115
+
116
+ it "should reinstate SCI" do
117
+ DocSCIOrphan.should_not be_single_collection_inherited
118
+ DocSCIOrphanChild.should be_single_collection_inherited
119
+ end
120
+
121
+ it "should have the _type key" do
122
+ DocSCIOrphan.keys.should have_key "_type"
123
+ DocSCIOrphanChild.keys.should have_key "_type"
124
+ end
125
+ end
126
+ end
127
+
128
+ it "should know single_collection_parent" do
129
+ DocParent.single_collection_parent.should be_nil
130
+ DocDaughter.single_collection_parent.should == DocParent
131
+ DocSon.single_collection_parent.should == DocParent
132
+ DocGrandSon.single_collection_parent.should == DocSon
133
+ DocGrandGrandSon.single_collection_parent.should == DocGrandSon
134
+ end
135
+
136
+ it "should know single_collection_root" do
137
+ DocParent.single_collection_root.should == DocParent
138
+ DocDaughter.single_collection_root.should == DocParent
139
+ DocSon.single_collection_root.should == DocParent
140
+ DocGrandSon.single_collection_root.should == DocParent
141
+ DocGrandGrandSon.single_collection_root.should == DocParent
142
+ end
143
+
144
+ context ".single_collection_inherited?" do
145
+ it "should be false if has not inherited" do
146
+ DocParent.should_not be_single_collection_inherited
147
+ end
148
+
149
+ it "should be true if inherited" do
150
+ DocDaughter.should be_single_collection_inherited
151
+ DocSon.should be_single_collection_inherited
152
+ DocGrandSon.should be_single_collection_inherited
153
+ end
154
+ end
155
+
156
+ it "should set _type on initialize" do
157
+ DocDaughter.new._type.should == 'DocDaughter'
158
+ DocSon.new._type.should == 'DocSon'
159
+ DocGrandSon.new._type.should == 'DocGrandSon'
160
+ end
161
+
162
+ it "should set _type based on class and ignore assigned values" do
163
+ DocSon.new(:_type => 'DocDaughter')._type.should == 'DocSon'
164
+ end
165
+
166
+ context "loading" do
167
+ it "should be based on _type" do
168
+ @parent.save
169
+ @daughter.save
170
+
171
+ collection = DocParent.all
172
+ collection.size.should == 2
173
+ collection.first.should be_kind_of(DocParent)
174
+ collection.first.name.should == "Daddy Warbucks"
175
+ collection.last.should be_kind_of(DocDaughter)
176
+ collection.last.name.should == "Little Orphan Annie"
177
+ end
178
+
179
+ it "should gracefully handle when _type cannot be constantized" do
180
+ doc = DocParent.new(:name => 'Nunes')
181
+ doc._type = 'FoobarBaz'
182
+ doc.save
183
+
184
+ collection = DocParent.all
185
+ collection.last.should == doc
186
+ collection.last.should be_kind_of(DocParent)
187
+ end
188
+ end
189
+
190
+ context "querying" do
191
+ it "should find scoped to class" do
192
+ john = DocSon.create(:name => 'John')
193
+ steve = DocSon.create(:name => 'Steve')
194
+ steph = DocDaughter.create(:name => 'Steph')
195
+ carrie = DocDaughter.create(:name => 'Carrie')
196
+ boris = DocGrandSon.create(:name => 'Boris')
197
+
198
+ DocGrandGrandSon.all(:order => 'name').should == []
199
+ DocGrandSon.all(:order => 'name').should == [boris]
200
+ DocSon.all(:order => 'name').should == [boris, john, steve]
201
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
202
+ DocParent.all(:order => 'name').should == [boris, carrie, john, steph, steve]
203
+
204
+ sigmund = DocGrandGrandSon.create(:name => 'Sigmund')
205
+
206
+ DocGrandSon.all(:order => 'name').should == [boris, sigmund]
207
+ DocSon.all(:order => 'name').should == [boris, john, sigmund, steve]
208
+ DocParent.all(:order => 'name').should == [boris, carrie, john, sigmund, steph, steve]
209
+ end
210
+
211
+ it "should work with nested hash conditions" do
212
+ john = DocSon.create(:name => 'John')
213
+ steve = DocSon.create(:name => 'Steve')
214
+ DocSon.all(:name => {'$ne' => 'Steve'}).should == [john]
215
+ end
216
+
217
+ it "should raise error if not found scoped to class" do
218
+ john = DocSon.create(:name => 'John')
219
+ steph = DocDaughter.create(:name => 'Steph')
220
+
221
+ lambda {
222
+ DocSon.find!(steph._id)
223
+ }.should raise_error(MarkMapper::DocumentNotFound)
224
+ end
225
+
226
+ it "should not raise error for find with parent" do
227
+ john = DocSon.create(:name => 'John')
228
+
229
+ DocParent.find!(john._id).should == john
230
+ end
231
+
232
+ it "should count scoped to class" do
233
+ john = DocSon.create(:name => 'John')
234
+ steve = DocSon.create(:name => 'Steve')
235
+ steph = DocDaughter.create(:name => 'Steph')
236
+ carrie = DocDaughter.create(:name => 'Carrie')
237
+
238
+ DocGrandSon.count.should == 0
239
+ DocSon.count.should == 2
240
+ DocDaughter.count.should == 2
241
+ DocParent.count.should == 4
242
+ end
243
+
244
+ it "should not be able to destroy each other" do
245
+ john = DocSon.create(:name => 'John')
246
+ steph = DocDaughter.create(:name => 'Steph')
247
+
248
+ lambda {
249
+ DocSon.destroy(steph._id)
250
+ }.should raise_error(MarkMapper::DocumentNotFound)
251
+ end
252
+
253
+ it "should not be able to delete each other" do
254
+ john = DocSon.create(:name => 'John')
255
+ steph = DocDaughter.create(:name => 'Steph')
256
+
257
+ lambda {
258
+ DocSon.delete(steph._id)
259
+ }.should_not change { DocParent.count }
260
+ end
261
+
262
+ it "should be able to destroy using parent" do
263
+ john = DocSon.create(:name => 'John')
264
+ steph = DocDaughter.create(:name => 'Steph')
265
+
266
+ lambda {
267
+ DocParent.destroy_all
268
+ }.should change { DocParent.count }.by(-2)
269
+ end
270
+
271
+ it "should be able to delete using parent" do
272
+ john = DocSon.create(:name => 'John')
273
+ steph = DocDaughter.create(:name => 'Steph')
274
+
275
+ lambda {
276
+ DocParent.delete_all
277
+ }.should change { DocParent.count }.by(-2)
278
+ end
279
+ end
280
+
281
+ it "should be able to reload single collection inherited parent class" do
282
+ brian = DocParent.create(:name => 'Brian')
283
+ brian.name = 'B-Dawg'
284
+ brian.reload
285
+ brian.name.should == 'Brian'
286
+ end
287
+ end
288
+
289
+ describe "Single collection inheritance (embedded document)" do
290
+ before do
291
+ class ::Grandparent
292
+ include MarkMapper::EmbeddedDocument
293
+ key :grandparent, String
294
+ end
295
+
296
+ class ::Parent < ::Grandparent
297
+ include MarkMapper::EmbeddedDocument
298
+ key :parent, String
299
+ end
300
+
301
+ class ::Child < ::Parent
302
+ include MarkMapper::EmbeddedDocument
303
+ key :child, String
304
+ end
305
+
306
+ class ::OtherChild < ::Parent
307
+ include MarkMapper::EmbeddedDocument
308
+ key :other_child, String
309
+ end
310
+ end
311
+
312
+ after do
313
+ Object.send :remove_const, 'Grandparent' if defined?(::Grandparent)
314
+ Object.send :remove_const, 'Parent' if defined?(::Parent)
315
+ Object.send :remove_const, 'Child' if defined?(::Child)
316
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
317
+ end
318
+
319
+ it "should automatically add _type key" do
320
+ Grandparent.key?(:_type).should be_truthy
321
+ end
322
+
323
+ context ".single_collection_inherited?" do
324
+ it "should be false if has not inherited" do
325
+ Grandparent.should_not be_single_collection_inherited
326
+ end
327
+
328
+ it "should be true if inherited" do
329
+ Parent.should be_single_collection_inherited
330
+ Child.should be_single_collection_inherited
331
+ OtherChild.should be_single_collection_inherited
332
+ end
333
+ end
334
+
335
+ it "should set _type on initialize" do
336
+ Parent.new._type.should == 'Parent'
337
+ Child.new._type.should == 'Child'
338
+ OtherChild.new._type.should == 'OtherChild'
339
+ end
340
+
341
+ it "should set _type based on class and ignore assigned values" do
342
+ Child.new(:_type => 'OtherChild')._type.should == 'Child'
343
+ end
344
+ end
345
+
346
+ describe "With polymorphism" do
347
+ before :all do
348
+ class SciPolymorphicPost
349
+ include MarkMapper::Document
350
+ belongs_to :article_parent, :polymorphic => true
351
+ end
352
+
353
+ class GalleryItem
354
+ include MarkMapper::Document
355
+ belongs_to :gallery_album
356
+ key :text, Hash
357
+ timestamps!
358
+ end
359
+
360
+ class TextGalleryItem < GalleryItem;
361
+ many :sci_polymorphic_posts, :as => :article_parent
362
+ end
363
+ end
364
+
365
+ it "should find polymorphic SCI items" do
366
+ item = TextGalleryItem.new()
367
+ p = SciPolymorphicPost.create(:article_parent => item)
368
+ p.article_parent_id.should be_a MarkLogic::ObjectId
369
+ p.article_parent_type.should == "TextGalleryItem"
370
+
371
+ p.reload.article_parent.sci_polymorphic_posts.all.should include(p)
372
+ end
373
+ end
374
+ end
@@ -0,0 +1,204 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Scopes" do
4
+ context "Scopes" do
5
+ before do
6
+ @document = Doc() do
7
+ key :name, String
8
+ key :age, Integer
9
+ timestamps!
10
+ end
11
+ end
12
+
13
+ context "basic scopes" do
14
+ before do
15
+ @document.class_eval do
16
+ scope :old, :age.gt => 60
17
+ scope :teens, :age.ge => 13, :age.le => 19
18
+ end
19
+ end
20
+
21
+ it "should know what scopes have been added" do
22
+ @document.scopes.size.should == 2
23
+ @document.scopes.keys.map(&:to_s).sort.should == %w(old teens)
24
+ end
25
+
26
+ it "should return a query" do
27
+ @document.old.should be_kind_of(MarkMapper::Query)
28
+ end
29
+
30
+ it "should work" do
31
+ @document.create(:name => 'John', :age => 99)
32
+ @document.create(:name => 'Frank', :age => 15)
33
+ docs = @document.old.all
34
+ docs.size.should == 1
35
+ docs[0].name.should == 'John'
36
+ end
37
+
38
+ # Regression test for #534
39
+ context "when where() is invoked via a scope before a key is defined" do
40
+ let(:given_id) { MarkLogic::ObjectId.new }
41
+ let(:doc) { Doc {
42
+ key :type, String
43
+
44
+ # Ordering is important here; where needs to happen before foo_id is defined
45
+ # in order to produce the behavior we're testing against regression.
46
+ scope :type, where(:type => "bar")
47
+ key :foo_id, ObjectId
48
+ }}
49
+ before {
50
+ doc.collection.drop
51
+ doc.create({:foo_id => given_id})
52
+ }
53
+
54
+ it "should work without typecasts" do
55
+ doc.where(:foo_id => given_id).count.should == 1
56
+ end
57
+
58
+ it "should work with typecasts" do
59
+ doc.where(:foo_id => given_id.to_s).count.should == 1
60
+ end
61
+ end
62
+ end
63
+
64
+ context "dynamic scopes" do
65
+ before do
66
+ @document.class_eval do
67
+ scope :age, lambda { |age| {:age => age} }
68
+ scope :ages, lambda { |low, high| {:age.ge => low, :age.le => high} }
69
+ scope :ordered, lambda { |sort| sort(sort) }
70
+ end
71
+ end
72
+
73
+ it "should work with single argument" do
74
+ @document.create(:name => 'John', :age => 60)
75
+ @document.create(:name => 'Frank', :age => 50)
76
+ docs = @document.age(60).all
77
+ docs.size.should == 1
78
+ docs.first.name.should == 'John'
79
+ end
80
+
81
+ it "should work with multiple arguments" do
82
+ @document.create(:name => 'John', :age => 60)
83
+ @document.create(:name => 'Frank', :age => 50)
84
+ @document.create(:name => 'Bill', :age => 40)
85
+ docs = @document.ages(50, 70).all
86
+ docs.size.should == 2
87
+ docs.map(&:name).sort.should == %w(Frank John)
88
+ end
89
+
90
+ it "should work with queries" do
91
+ john = @document.create(:name => 'John', :age => 60)
92
+ frank = @document.create(:name => 'Frank', :age => 50)
93
+ bill = @document.create(:name => 'Bill', :age => 40)
94
+ @document.ordered(:age).all.should == [bill, frank, john]
95
+ end
96
+ end
97
+
98
+ context "query scopes" do
99
+ before do
100
+ @document.class_eval do
101
+ scope :boomers, where(:age.ge => 60).sort(:age)
102
+ end
103
+ end
104
+
105
+ it "should work" do
106
+ todd = @document.create(:name => 'Todd', :age => 65)
107
+ john = @document.create(:name => 'John', :age => 60)
108
+ @document.create(:name => 'Frank', :age => 50)
109
+ @document.create(:name => 'Bill', :age => 40)
110
+ docs = @document.boomers.all
111
+ docs[0].should == john
112
+ docs[1].should == todd
113
+ end
114
+ end
115
+
116
+ context "chaining" do
117
+ before do
118
+ @document.class_eval do
119
+ scope :by_age, lambda { |age| {:age => age} }
120
+ scope :by_name, lambda { |name| {:name => name} }
121
+ end
122
+ end
123
+
124
+ it "should work with scope methods" do
125
+ @document.create(:name => 'John', :age => 60)
126
+ @document.create(:name => 'Frank', :age => 60)
127
+ @document.create(:name => 'Bill', :age => 50)
128
+ docs = @document.by_age(60).by_name('John').all
129
+ docs.size.should == 1
130
+ docs.first.name.should == 'John'
131
+ end
132
+
133
+ it "should work on query methods" do
134
+ @document.create(:name => 'John', :age => 60)
135
+ @document.create(:name => 'John', :age => 50)
136
+ @document.create(:name => 'Bill', :age => 50)
137
+ docs = @document.where(:name => 'John').by_age(50).all
138
+ docs.size.should == 1
139
+ docs.first.age.should == 50
140
+ end
141
+
142
+ context "with model methods" do
143
+ it "should work if method returns a query" do
144
+ @document.create(:name => 'John', :age => 10)
145
+ @document.create(:name => 'John', :age => 20)
146
+ @document.class_eval do
147
+ def self.young
148
+ query(:age.le => 12)
149
+ end
150
+ end
151
+ docs = @document.by_name('John').young.all
152
+ docs.size.should == 1
153
+ docs.first.age.should == 10
154
+ end
155
+
156
+ it "should not work if method does not return a query" do
157
+ @document.class_eval { def self.age; 20 end }
158
+ @document.by_name('John').age.should == 20
159
+ end
160
+ end
161
+ end
162
+
163
+ context "with single collection inheritance" do
164
+ before do
165
+ class ::Item
166
+ include MarkMapper::Document
167
+ scope :by_title, lambda { |title| {:title => title} }
168
+ scope :published, lambda { {:published_at.le => Time.now.utc} }
169
+
170
+ key :title, String
171
+ key :published_at, Time
172
+ end
173
+ Item.collection.remove
174
+
175
+ class ::Page < ::Item; end
176
+ class ::Blog < ::Item
177
+ key :slug, String
178
+ scope :by_slug, lambda { |slug| {:slug => slug} }
179
+ end
180
+ end
181
+
182
+ after do
183
+ Object.send :remove_const, 'Item' if defined?(::Item)
184
+ Object.send :remove_const, 'Page' if defined?(::Page)
185
+ Object.send :remove_const, 'Blog' if defined?(::Blog)
186
+ end
187
+
188
+ it "should inherit scopes" do
189
+ Page.scopes.keys.map(&:to_s).sort.should == %w(by_title published)
190
+ end
191
+
192
+ it "should work with _type" do
193
+ item = Item.create(:title => 'Home')
194
+ page = Page.create(:title => 'Home')
195
+ Page.by_title('Home').first.should == page
196
+ end
197
+
198
+ it "should limit subclass scopes to subclasses" do
199
+ Item.scopes.keys.map(&:to_s).should =~ %w(by_title published)
200
+ Blog.scopes.keys.map(&:to_s).should =~ %w(by_slug by_title published)
201
+ end
202
+ end
203
+ end
204
+ end