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,134 @@
1
+ # encoding: UTF-8
2
+ module MarkMapper
3
+ module Plugins
4
+ module Keys
5
+ class Key
6
+ attr_accessor :name, :type, :options, :default, :ivar, :abbr, :accessors
7
+
8
+ ID_STR = '_id'
9
+
10
+ def initialize(*args)
11
+ options_from_args = args.extract_options!
12
+ @name, @type = args.shift.to_s, args.shift
13
+ self.options = (options_from_args || {}).symbolize_keys
14
+ @dynamic = !!options[:__dynamic]
15
+ @embeddable = type.respond_to?(:embeddable?) ? type.embeddable? : false
16
+ @is_id = @name == ID_STR
17
+ @typecast = @options[:typecast]
18
+ @accessors = Array(@options[:accessors]).compact.map &:to_s
19
+ @has_default = !!options.key?(:default)
20
+ self.default = self.options[:default] if default?
21
+
22
+ if abbr = @options[:abbr] || @options[:alias] || @options[:field_name]
23
+ @abbr = abbr.to_s
24
+ elsif @name.match(/^[A-Z]/) and !dynamic?
25
+ @abbr = @name
26
+ @name = @name.gsub(/^([A-Z])/) {|m| m.downcase }
27
+ Kernel.warn "Key names may not start with uppercase letters. If your field starts " +
28
+ "with an uppercase letter, use :field_name to specify the real field name. " +
29
+ "Accessors called `#{@name}` have been created instead."
30
+ end
31
+ @ivar = :"@#{name}" if valid_ruby_name?
32
+ validate_key_name! unless dynamic? or !any_accessor?
33
+ end
34
+
35
+ def persisted_name
36
+ @abbr || @name
37
+ end
38
+
39
+ def ==(other)
40
+ @name == other.name && @type == other.type && @abbr == other.abbr
41
+ end
42
+
43
+ def embeddable?
44
+ @embeddable
45
+ end
46
+
47
+ def number?
48
+ type == Integer || type == Float
49
+ end
50
+
51
+ def default?
52
+ @has_default
53
+ end
54
+
55
+ def dynamic?
56
+ @dynamic
57
+ end
58
+
59
+ def get(value)
60
+ # Special Case: Generate default _id on access
61
+ value = default_value if @is_id and !value
62
+
63
+ if @typecast
64
+ klass = typecast_class # Don't make this lookup on every call
65
+ type.from_marklogic(value).map { |v| klass.from_marklogic(v) }
66
+ else
67
+ type.from_marklogic(value)
68
+ end
69
+ end
70
+
71
+ def set(value)
72
+ # Avoid tap here so we don't have to create a block binding.
73
+ values = type.to_marklogic(value)
74
+ if @typecast
75
+ values.map { |v| typecast_class.to_marklogic(v) }
76
+ else
77
+ values
78
+ end
79
+ end
80
+
81
+ def default_value
82
+ return unless default?
83
+ if default.instance_of? Proc
84
+ type.to_marklogic default.call
85
+ else
86
+ # Using Marshal is easiest way to get a copy of mutable objects
87
+ # without getting an error on immutable objects
88
+ type.to_marklogic Marshal.load(Marshal.dump(default))
89
+ end
90
+ end
91
+
92
+ def valid_ruby_name?
93
+ !!@name.match(/\A[a-z_][a-z0-9_]*\z/i)
94
+ end
95
+
96
+ RESERVED_KEYS = %w( id class object_id )
97
+ def reserved_name?
98
+ RESERVED_KEYS.include?(@name)
99
+ end
100
+
101
+ def read_accessor?
102
+ any_accessor? ["read"]
103
+ end
104
+
105
+ def write_accessor?
106
+ any_accessor? ["write"]
107
+ end
108
+
109
+ def predicate_accessor?
110
+ any_accessor? ["present", "predicate", "boolean"]
111
+ end
112
+
113
+ def any_accessor?(arr_opt = [])
114
+ return true if @accessors.empty?
115
+ return false unless (@accessors & ["skip", "none"]).empty?
116
+ return !(@accessors & arr_opt).empty?
117
+ end
118
+
119
+ private
120
+ def typecast_class
121
+ @typecast_class ||= options[:typecast].constantize
122
+ end
123
+
124
+ def validate_key_name!
125
+ if reserved_name?
126
+ raise MarkMapper::InvalidKey.new("`#{@name}` is a reserved key name (did you mean to use _id?)")
127
+ elsif !valid_ruby_name?
128
+ raise MarkMapper::InvalidKey.new("`#{@name}` is not a valid key name. Keys must match [a-z][a-z0-9_]*")
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,45 @@
1
+ module MarkMapper
2
+ module Plugins
3
+ module Keys
4
+ module Static
5
+ class MissingKeyError < StandardError; end
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ attr_writer :static_keys
11
+
12
+ def static_keys
13
+ @static_keys || false
14
+ end
15
+ end
16
+
17
+ def read_key(name)
18
+ if !self.class.static_keys || self.class.key?(name)
19
+ super
20
+ else
21
+ raise MissingKeyError, "Tried to read the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def write_key(name, value)
28
+ if !self.class.static_keys || self.class.key?(name)
29
+ super
30
+ else
31
+ raise MissingKeyError, "Tried to write the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
32
+ end
33
+ end
34
+
35
+ def load_from_database(attrs, with_cast = false)
36
+ return super if !self.class.static_keys || !attrs.respond_to?(:each)
37
+
38
+ attrs = attrs.select { |key, _| self.class.key?(key) }
39
+
40
+ super(attrs, with_cast)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module MarkMapper
3
+ module Plugins
4
+ module Logger
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def logger
9
+ MarkMapper.logger
10
+ end
11
+ end
12
+
13
+ def logger
14
+ self.class.logger
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+ module MarkMapper
3
+ module Plugins
4
+ module Modifiers
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def increment(*args)
9
+ modifier_update('$inc', args)
10
+ end
11
+
12
+ def decrement(*args)
13
+ criteria, keys, options = criteria_and_keys_from_args(args)
14
+ values, to_decrement = keys.values, {}
15
+ keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
16
+ collection.update(criteria, {'$inc' => to_decrement})
17
+ end
18
+
19
+ def set(*args)
20
+ criteria, updates, options = criteria_and_keys_from_args(args)
21
+ updates.each do |key, value|
22
+ updates[key] = keys[key.to_s].set(value) if key?(key)
23
+ end
24
+ modifier_update('$set', [criteria, updates, options])
25
+ end
26
+
27
+ def unset(*args)
28
+ if args[0].is_a?(Hash)
29
+ criteria, keys = args.shift, args
30
+ options = keys.last.is_a?(Hash) ? keys.pop : {}
31
+ else
32
+ keys, ids = args.partition { |arg| arg.is_a?(Symbol) }
33
+ options = ids.last.is_a?(Hash) ? ids.pop : {}
34
+ criteria = {:id => ids}
35
+ end
36
+
37
+ criteria = criteria_hash(criteria).to_hash
38
+ updates = keys.inject({}) { |hash, key| hash[key] = 1; hash }
39
+ modifier_update('$unset', [criteria, updates, options])
40
+ end
41
+
42
+ def push(*args)
43
+ modifier_update('$push', args)
44
+ end
45
+
46
+ def push_all(*args)
47
+ modifier_update('$pushAll', args)
48
+ end
49
+
50
+ def add_to_set(*args)
51
+ modifier_update('$addToSet', args)
52
+ end
53
+ alias push_uniq add_to_set
54
+
55
+ def pull(*args)
56
+ modifier_update('$pull', args)
57
+ end
58
+
59
+ def pull_all(*args)
60
+ modifier_update('$pullAll', args)
61
+ end
62
+
63
+ def pop(*args)
64
+ modifier_update('$pop', args)
65
+ end
66
+
67
+ def find_and_modify(args)
68
+ args[:query] = dealias_keys(args[:query]) if args.key? :query
69
+ args[:update] = dealias_keys(args[:update]) if args.key? :update
70
+ collection.find_and_modify(args)
71
+ end
72
+
73
+ private
74
+ def modifier_update(modifier, args)
75
+ criteria, updates, options = criteria_and_keys_from_args(args)
76
+ if options
77
+ collection.update(criteria, {modifier => updates}, options)
78
+ else
79
+ collection.update(criteria, {modifier => updates})
80
+ end
81
+ end
82
+
83
+ def criteria_and_keys_from_args(args)
84
+ if args[0].is_a?(Hash)
85
+ criteria = args[0]
86
+ updates = args[1]
87
+ options = args[2]
88
+ else
89
+ criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
90
+ criteria = { :id => criteria }
91
+ end
92
+ updates = dealias_keys updates
93
+
94
+ [criteria_hash(criteria).to_hash, updates, options]
95
+ end
96
+ end
97
+
98
+ def unset(*args)
99
+ self.class.unset({:_id => id}, *args)
100
+ end
101
+
102
+ def increment(hash, options=nil)
103
+ self.class.increment({:_id => id}, hash, options)
104
+ end
105
+
106
+ def decrement(hash, options=nil)
107
+ self.class.decrement({:_id => id}, hash, options)
108
+ end
109
+
110
+ def set(hash, options=nil)
111
+ self.class.set({:_id => id}, hash, options)
112
+ end
113
+
114
+ def push(hash, options=nil)
115
+ self.class.push({:_id => id}, hash, options)
116
+ end
117
+
118
+ def push_all(hash, options=nil)
119
+ self.class.push_all({:_id => id}, hash, options)
120
+ end
121
+
122
+ def pull(hash, options=nil)
123
+ self.class.pull({:_id => id}, hash, options)
124
+ end
125
+
126
+ def pull_all(hash, options=nil)
127
+ self.class.pull_all({:_id => id}, hash, options)
128
+ end
129
+
130
+ def add_to_set(hash, options=nil)
131
+ self.class.push_uniq({:_id => id}, hash, options)
132
+ end
133
+ alias push_uniq add_to_set
134
+
135
+ def pop(hash, options=nil)
136
+ self.class.pop({:_id => id}, hash, options)
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ module MarkMapper
3
+ module Plugins
4
+ module Pagination
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def per_page; 25 end
9
+
10
+ def paginate(opts={})
11
+ query.paginate({:per_page => per_page}.merge(opts))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,77 @@
1
+ module MarkMapper
2
+ module Plugins
3
+ module PartialUpdates
4
+ extend ActiveSupport::Concern
5
+
6
+ class PartialUpdatesDisabledError < StandardError; end
7
+
8
+ included do
9
+ class_attribute :partial_updates
10
+ self.partial_updates = false
11
+
12
+ self.after_find :_reset_partial_updates_callback
13
+ self.after_save :_reset_partial_updates_callback
14
+ end
15
+
16
+ def initialize(*)
17
+ _reset_partial_updates_callback
18
+ super
19
+ end
20
+
21
+ def fields_for_partial_update
22
+ raise PartialUpdatesDisabledError if !partial_updates
23
+
24
+ Hash.new.tap do |hash|
25
+ attrs = _dealiased_attributes
26
+
27
+ hash[:set_fields] = Array.new.tap do |array|
28
+ attrs.each do |key, value|
29
+ if !@_last_saved_attributes.include?(key) ||
30
+ @_last_saved_attributes[key] != value
31
+ array << key
32
+ end
33
+ end
34
+ end
35
+
36
+ hash[:unset_fields] = @_last_saved_attributes.keys - attrs.keys
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def _reset_partial_updates_callback
43
+ _reset_attributes_for_partial_update if partial_updates
44
+ true
45
+ end
46
+
47
+ def update(options={})
48
+ if partial_updates
49
+ updates = fields_for_partial_update
50
+
51
+ set_fields = updates[:set_fields]
52
+ unset_fields = updates[:unset_fields]
53
+
54
+ if set_fields.any? || unset_fields.any?
55
+ set_fields.push("_id") if !set_fields.include?("_id")
56
+ end
57
+
58
+ super(options.merge({
59
+ :persistence_method => :update,
60
+ :set_fields => set_fields,
61
+ :unset_fields => unset_fields
62
+ }))
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def _dealiased_attributes
69
+ self.class.dealias_keys(attributes)
70
+ end
71
+
72
+ def _reset_attributes_for_partial_update
73
+ @_last_saved_attributes = _dealiased_attributes._mark_mapper_deep_copy_
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: UTF-8
2
+ module MarkMapper
3
+ module Plugins
4
+ module Persistence
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def inherited(subclass)
9
+ unless subclass.embeddable?
10
+ subclass.connection(connection)
11
+ subclass.database = database
12
+ subclass.set_collection_name(collection_name) unless subclass.explicit_collection_defined?
13
+ end
14
+ super
15
+ end
16
+
17
+ def connection(marklogic_connection=nil)
18
+ assert_supported
19
+ if marklogic_connection.nil? && MarkMapper.connection?
20
+ @connection ||= MarkMapper.connection
21
+ else
22
+ @connection = marklogic_connection
23
+ end
24
+ @connection
25
+ end
26
+
27
+ def database_name
28
+ assert_supported
29
+ @database.database_name
30
+ end
31
+
32
+ def database=(database)
33
+ assert_supported
34
+ @database = database
35
+ end
36
+
37
+ def database
38
+ assert_supported
39
+ @database ||= MarkMapper.application.content_databases[0]
40
+ end
41
+
42
+ def set_collection_name(name)
43
+ assert_supported
44
+ @collection_name = name
45
+ end
46
+
47
+ def collection_name
48
+ assert_supported
49
+ @collection_name ||= begin
50
+ name = self.to_s.tableize.gsub(/\//, '.')
51
+ name = self.class.to_s.downcase if name[0] == '#'
52
+ name
53
+ end
54
+ end
55
+
56
+ def collection
57
+ assert_supported
58
+ database.collection(collection_name)
59
+ end
60
+
61
+ private
62
+ def assert_supported
63
+ @embeddable ||= embeddable?
64
+ if @embeddable
65
+ raise MarkMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
66
+ end
67
+ end
68
+ end
69
+
70
+ def collection
71
+ _root_document.class.collection
72
+ end
73
+
74
+ def database
75
+ _root_document.class.database
76
+ end
77
+ end
78
+ end
79
+ end