mongoid-multi-db 3.0.0

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 (276) hide show
  1. data/CHANGELOG.md +615 -0
  2. data/LICENSE +20 -0
  3. data/README.md +62 -0
  4. data/Rakefile +49 -0
  5. data/lib/config/locales/bg.yml +54 -0
  6. data/lib/config/locales/de.yml +54 -0
  7. data/lib/config/locales/en-GB.yml +55 -0
  8. data/lib/config/locales/en.yml +55 -0
  9. data/lib/config/locales/es.yml +52 -0
  10. data/lib/config/locales/fr.yml +55 -0
  11. data/lib/config/locales/hi.yml +46 -0
  12. data/lib/config/locales/hu.yml +57 -0
  13. data/lib/config/locales/id.yml +55 -0
  14. data/lib/config/locales/it.yml +52 -0
  15. data/lib/config/locales/ja.yml +50 -0
  16. data/lib/config/locales/kr.yml +47 -0
  17. data/lib/config/locales/nl.yml +52 -0
  18. data/lib/config/locales/pl.yml +52 -0
  19. data/lib/config/locales/pt-BR.yml +53 -0
  20. data/lib/config/locales/pt.yml +53 -0
  21. data/lib/config/locales/ro.yml +59 -0
  22. data/lib/config/locales/ru.yml +54 -0
  23. data/lib/config/locales/sv.yml +53 -0
  24. data/lib/config/locales/vi.yml +55 -0
  25. data/lib/config/locales/zh-CN.yml +46 -0
  26. data/lib/mongoid.rb +148 -0
  27. data/lib/mongoid/atomic.rb +230 -0
  28. data/lib/mongoid/atomic/modifiers.rb +243 -0
  29. data/lib/mongoid/atomic/paths.rb +3 -0
  30. data/lib/mongoid/atomic/paths/embedded.rb +43 -0
  31. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  32. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  33. data/lib/mongoid/atomic/paths/root.rb +40 -0
  34. data/lib/mongoid/attributes.rb +234 -0
  35. data/lib/mongoid/attributes/processing.rb +146 -0
  36. data/lib/mongoid/callbacks.rb +135 -0
  37. data/lib/mongoid/collection.rb +153 -0
  38. data/lib/mongoid/collection_proxy.rb +59 -0
  39. data/lib/mongoid/collections.rb +120 -0
  40. data/lib/mongoid/collections/master.rb +45 -0
  41. data/lib/mongoid/collections/operations.rb +44 -0
  42. data/lib/mongoid/collections/retry.rb +46 -0
  43. data/lib/mongoid/components.rb +96 -0
  44. data/lib/mongoid/config.rb +347 -0
  45. data/lib/mongoid/config/database.rb +186 -0
  46. data/lib/mongoid/config/replset_database.rb +82 -0
  47. data/lib/mongoid/connection_proxy.rb +30 -0
  48. data/lib/mongoid/contexts.rb +25 -0
  49. data/lib/mongoid/contexts/enumerable.rb +288 -0
  50. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  51. data/lib/mongoid/contexts/mongo.rb +409 -0
  52. data/lib/mongoid/copyable.rb +48 -0
  53. data/lib/mongoid/criteria.rb +418 -0
  54. data/lib/mongoid/criterion/builder.rb +34 -0
  55. data/lib/mongoid/criterion/complex.rb +84 -0
  56. data/lib/mongoid/criterion/creational.rb +34 -0
  57. data/lib/mongoid/criterion/exclusion.rb +108 -0
  58. data/lib/mongoid/criterion/inclusion.rb +305 -0
  59. data/lib/mongoid/criterion/inspection.rb +22 -0
  60. data/lib/mongoid/criterion/optional.rb +232 -0
  61. data/lib/mongoid/criterion/selector.rb +153 -0
  62. data/lib/mongoid/cursor.rb +86 -0
  63. data/lib/mongoid/database_proxy.rb +97 -0
  64. data/lib/mongoid/default_scope.rb +36 -0
  65. data/lib/mongoid/dirty.rb +110 -0
  66. data/lib/mongoid/document.rb +280 -0
  67. data/lib/mongoid/errors.rb +17 -0
  68. data/lib/mongoid/errors/callback.rb +26 -0
  69. data/lib/mongoid/errors/document_not_found.rb +28 -0
  70. data/lib/mongoid/errors/eager_load.rb +25 -0
  71. data/lib/mongoid/errors/invalid_collection.rb +18 -0
  72. data/lib/mongoid/errors/invalid_database.rb +19 -0
  73. data/lib/mongoid/errors/invalid_field.rb +18 -0
  74. data/lib/mongoid/errors/invalid_find.rb +19 -0
  75. data/lib/mongoid/errors/invalid_options.rb +28 -0
  76. data/lib/mongoid/errors/invalid_time.rb +25 -0
  77. data/lib/mongoid/errors/invalid_type.rb +25 -0
  78. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  79. data/lib/mongoid/errors/mongoid_error.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +20 -0
  81. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  82. data/lib/mongoid/errors/unsupported_version.rb +20 -0
  83. data/lib/mongoid/errors/validations.rb +23 -0
  84. data/lib/mongoid/extensions.rb +82 -0
  85. data/lib/mongoid/extensions/array/deletion.rb +29 -0
  86. data/lib/mongoid/extensions/false_class/equality.rb +26 -0
  87. data/lib/mongoid/extensions/hash/criteria_helpers.rb +45 -0
  88. data/lib/mongoid/extensions/hash/scoping.rb +25 -0
  89. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  90. data/lib/mongoid/extensions/nil/collectionization.rb +23 -0
  91. data/lib/mongoid/extensions/object/checks.rb +29 -0
  92. data/lib/mongoid/extensions/object/reflections.rb +48 -0
  93. data/lib/mongoid/extensions/object/substitutable.rb +15 -0
  94. data/lib/mongoid/extensions/object/yoda.rb +44 -0
  95. data/lib/mongoid/extensions/object_id/conversions.rb +60 -0
  96. data/lib/mongoid/extensions/proc/scoping.rb +25 -0
  97. data/lib/mongoid/extensions/string/checks.rb +36 -0
  98. data/lib/mongoid/extensions/string/conversions.rb +22 -0
  99. data/lib/mongoid/extensions/string/inflections.rb +118 -0
  100. data/lib/mongoid/extensions/symbol/checks.rb +23 -0
  101. data/lib/mongoid/extensions/symbol/inflections.rb +66 -0
  102. data/lib/mongoid/extensions/true_class/equality.rb +26 -0
  103. data/lib/mongoid/extras.rb +31 -0
  104. data/lib/mongoid/factory.rb +46 -0
  105. data/lib/mongoid/fields.rb +332 -0
  106. data/lib/mongoid/fields/mappings.rb +41 -0
  107. data/lib/mongoid/fields/serializable.rb +201 -0
  108. data/lib/mongoid/fields/serializable/array.rb +49 -0
  109. data/lib/mongoid/fields/serializable/big_decimal.rb +42 -0
  110. data/lib/mongoid/fields/serializable/bignum.rb +10 -0
  111. data/lib/mongoid/fields/serializable/binary.rb +11 -0
  112. data/lib/mongoid/fields/serializable/boolean.rb +43 -0
  113. data/lib/mongoid/fields/serializable/date.rb +51 -0
  114. data/lib/mongoid/fields/serializable/date_time.rb +28 -0
  115. data/lib/mongoid/fields/serializable/fixnum.rb +10 -0
  116. data/lib/mongoid/fields/serializable/float.rb +32 -0
  117. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +42 -0
  118. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +47 -0
  119. data/lib/mongoid/fields/serializable/hash.rb +11 -0
  120. data/lib/mongoid/fields/serializable/integer.rb +44 -0
  121. data/lib/mongoid/fields/serializable/localized.rb +41 -0
  122. data/lib/mongoid/fields/serializable/nil_class.rb +38 -0
  123. data/lib/mongoid/fields/serializable/object.rb +11 -0
  124. data/lib/mongoid/fields/serializable/object_id.rb +31 -0
  125. data/lib/mongoid/fields/serializable/range.rb +42 -0
  126. data/lib/mongoid/fields/serializable/set.rb +42 -0
  127. data/lib/mongoid/fields/serializable/string.rb +27 -0
  128. data/lib/mongoid/fields/serializable/symbol.rb +27 -0
  129. data/lib/mongoid/fields/serializable/time.rb +23 -0
  130. data/lib/mongoid/fields/serializable/time_with_zone.rb +23 -0
  131. data/lib/mongoid/fields/serializable/timekeeping.rb +106 -0
  132. data/lib/mongoid/finders.rb +152 -0
  133. data/lib/mongoid/hierarchy.rb +120 -0
  134. data/lib/mongoid/identity.rb +92 -0
  135. data/lib/mongoid/identity_map.rb +119 -0
  136. data/lib/mongoid/indexes.rb +54 -0
  137. data/lib/mongoid/inspection.rb +54 -0
  138. data/lib/mongoid/javascript.rb +20 -0
  139. data/lib/mongoid/javascript/functions.yml +63 -0
  140. data/lib/mongoid/json.rb +16 -0
  141. data/lib/mongoid/keys.rb +144 -0
  142. data/lib/mongoid/logger.rb +39 -0
  143. data/lib/mongoid/matchers.rb +32 -0
  144. data/lib/mongoid/matchers/all.rb +21 -0
  145. data/lib/mongoid/matchers/and.rb +30 -0
  146. data/lib/mongoid/matchers/default.rb +70 -0
  147. data/lib/mongoid/matchers/exists.rb +23 -0
  148. data/lib/mongoid/matchers/gt.rb +21 -0
  149. data/lib/mongoid/matchers/gte.rb +21 -0
  150. data/lib/mongoid/matchers/in.rb +21 -0
  151. data/lib/mongoid/matchers/lt.rb +21 -0
  152. data/lib/mongoid/matchers/lte.rb +21 -0
  153. data/lib/mongoid/matchers/ne.rb +21 -0
  154. data/lib/mongoid/matchers/nin.rb +21 -0
  155. data/lib/mongoid/matchers/or.rb +33 -0
  156. data/lib/mongoid/matchers/size.rb +21 -0
  157. data/lib/mongoid/matchers/strategies.rb +93 -0
  158. data/lib/mongoid/multi_database.rb +31 -0
  159. data/lib/mongoid/multi_parameter_attributes.rb +106 -0
  160. data/lib/mongoid/named_scope.rb +146 -0
  161. data/lib/mongoid/nested_attributes.rb +54 -0
  162. data/lib/mongoid/observer.rb +170 -0
  163. data/lib/mongoid/paranoia.rb +158 -0
  164. data/lib/mongoid/persistence.rb +264 -0
  165. data/lib/mongoid/persistence/atomic.rb +223 -0
  166. data/lib/mongoid/persistence/atomic/add_to_set.rb +35 -0
  167. data/lib/mongoid/persistence/atomic/bit.rb +37 -0
  168. data/lib/mongoid/persistence/atomic/inc.rb +31 -0
  169. data/lib/mongoid/persistence/atomic/operation.rb +85 -0
  170. data/lib/mongoid/persistence/atomic/pop.rb +34 -0
  171. data/lib/mongoid/persistence/atomic/pull.rb +34 -0
  172. data/lib/mongoid/persistence/atomic/pull_all.rb +34 -0
  173. data/lib/mongoid/persistence/atomic/push.rb +31 -0
  174. data/lib/mongoid/persistence/atomic/push_all.rb +31 -0
  175. data/lib/mongoid/persistence/atomic/rename.rb +31 -0
  176. data/lib/mongoid/persistence/atomic/sets.rb +30 -0
  177. data/lib/mongoid/persistence/atomic/unset.rb +28 -0
  178. data/lib/mongoid/persistence/deletion.rb +32 -0
  179. data/lib/mongoid/persistence/insertion.rb +41 -0
  180. data/lib/mongoid/persistence/modification.rb +37 -0
  181. data/lib/mongoid/persistence/operations.rb +211 -0
  182. data/lib/mongoid/persistence/operations/embedded/insert.rb +42 -0
  183. data/lib/mongoid/persistence/operations/embedded/remove.rb +40 -0
  184. data/lib/mongoid/persistence/operations/insert.rb +34 -0
  185. data/lib/mongoid/persistence/operations/remove.rb +33 -0
  186. data/lib/mongoid/persistence/operations/update.rb +64 -0
  187. data/lib/mongoid/railtie.rb +126 -0
  188. data/lib/mongoid/railties/database.rake +182 -0
  189. data/lib/mongoid/railties/document.rb +12 -0
  190. data/lib/mongoid/relations.rb +144 -0
  191. data/lib/mongoid/relations/accessors.rb +138 -0
  192. data/lib/mongoid/relations/auto_save.rb +38 -0
  193. data/lib/mongoid/relations/binding.rb +26 -0
  194. data/lib/mongoid/relations/bindings.rb +9 -0
  195. data/lib/mongoid/relations/bindings/embedded/in.rb +69 -0
  196. data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
  197. data/lib/mongoid/relations/bindings/embedded/one.rb +61 -0
  198. data/lib/mongoid/relations/bindings/referenced/in.rb +76 -0
  199. data/lib/mongoid/relations/bindings/referenced/many.rb +54 -0
  200. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +51 -0
  201. data/lib/mongoid/relations/bindings/referenced/one.rb +58 -0
  202. data/lib/mongoid/relations/builder.rb +57 -0
  203. data/lib/mongoid/relations/builders.rb +83 -0
  204. data/lib/mongoid/relations/builders/embedded/in.rb +29 -0
  205. data/lib/mongoid/relations/builders/embedded/many.rb +40 -0
  206. data/lib/mongoid/relations/builders/embedded/one.rb +30 -0
  207. data/lib/mongoid/relations/builders/nested_attributes/many.rb +110 -0
  208. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  209. data/lib/mongoid/relations/builders/referenced/in.rb +26 -0
  210. data/lib/mongoid/relations/builders/referenced/many.rb +27 -0
  211. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +38 -0
  212. data/lib/mongoid/relations/builders/referenced/one.rb +26 -0
  213. data/lib/mongoid/relations/cascading.rb +56 -0
  214. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  215. data/lib/mongoid/relations/cascading/destroy.rb +26 -0
  216. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  217. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  218. data/lib/mongoid/relations/constraint.rb +42 -0
  219. data/lib/mongoid/relations/conversions.rb +35 -0
  220. data/lib/mongoid/relations/cyclic.rb +103 -0
  221. data/lib/mongoid/relations/embedded/atomic.rb +89 -0
  222. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  223. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  224. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  225. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  226. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  227. data/lib/mongoid/relations/embedded/in.rb +220 -0
  228. data/lib/mongoid/relations/embedded/many.rb +560 -0
  229. data/lib/mongoid/relations/embedded/one.rb +206 -0
  230. data/lib/mongoid/relations/embedded/sort.rb +31 -0
  231. data/lib/mongoid/relations/macros.rb +310 -0
  232. data/lib/mongoid/relations/many.rb +135 -0
  233. data/lib/mongoid/relations/metadata.rb +919 -0
  234. data/lib/mongoid/relations/nested_builder.rb +75 -0
  235. data/lib/mongoid/relations/one.rb +36 -0
  236. data/lib/mongoid/relations/options.rb +47 -0
  237. data/lib/mongoid/relations/polymorphic.rb +40 -0
  238. data/lib/mongoid/relations/proxy.rb +145 -0
  239. data/lib/mongoid/relations/referenced/batch.rb +72 -0
  240. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  241. data/lib/mongoid/relations/referenced/in.rb +262 -0
  242. data/lib/mongoid/relations/referenced/many.rb +623 -0
  243. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  244. data/lib/mongoid/relations/referenced/one.rb +272 -0
  245. data/lib/mongoid/relations/reflections.rb +62 -0
  246. data/lib/mongoid/relations/synchronization.rb +153 -0
  247. data/lib/mongoid/relations/targets.rb +2 -0
  248. data/lib/mongoid/relations/targets/enumerable.rb +372 -0
  249. data/lib/mongoid/reloading.rb +91 -0
  250. data/lib/mongoid/safety.rb +105 -0
  251. data/lib/mongoid/scope.rb +31 -0
  252. data/lib/mongoid/serialization.rb +134 -0
  253. data/lib/mongoid/sharding.rb +61 -0
  254. data/lib/mongoid/state.rb +97 -0
  255. data/lib/mongoid/threaded.rb +530 -0
  256. data/lib/mongoid/threaded/lifecycle.rb +192 -0
  257. data/lib/mongoid/timestamps.rb +15 -0
  258. data/lib/mongoid/timestamps/created.rb +24 -0
  259. data/lib/mongoid/timestamps/timeless.rb +50 -0
  260. data/lib/mongoid/timestamps/updated.rb +26 -0
  261. data/lib/mongoid/validations.rb +140 -0
  262. data/lib/mongoid/validations/associated.rb +46 -0
  263. data/lib/mongoid/validations/uniqueness.rb +145 -0
  264. data/lib/mongoid/version.rb +4 -0
  265. data/lib/mongoid/versioning.rb +185 -0
  266. data/lib/rack/mongoid.rb +2 -0
  267. data/lib/rack/mongoid/middleware/identity_map.rb +38 -0
  268. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  269. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  270. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  271. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +19 -0
  272. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  273. data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +4 -0
  274. data/lib/rails/generators/mongoid_generator.rb +70 -0
  275. data/lib/rails/mongoid.rb +91 -0
  276. metadata +465 -0
@@ -0,0 +1,97 @@
1
+ require 'thread'
2
+ require 'mongoid/collection_proxy'
3
+
4
+ #
5
+ # Proxy that enables runtime swapping of a MongoDB database, as it
6
+ # appears to be cached at several points within Mongoid.
7
+ #
8
+ # This proxy is generated by the ConnectionProxy when asked for a
9
+ # specific database.
10
+ #
11
+ class DatabaseProxy
12
+ #
13
+ # Semaphore for preventing badness when multithreading.
14
+ #
15
+ @mutex = Mutex.new
16
+
17
+ #
18
+ # All connections that we know about, and then the databases tied to
19
+ # them get stored in here.
20
+ #
21
+ @pool = Hash.new
22
+
23
+ #
24
+ # Accessor for class-level instance variable that holds all the
25
+ # connection-database pairs that we know about, so that we can
26
+ # switch all of them globally.
27
+ #
28
+ def DatabaseProxy.pool
29
+ @pool
30
+ end
31
+
32
+ #
33
+ # Global mutex... for great thread safety!
34
+ #
35
+ def DatabaseProxy.mutex
36
+ @mutex
37
+ end
38
+
39
+ #
40
+ # Set our default connection and name.
41
+ #
42
+ def initialize(connection, name)
43
+ @connection = connection
44
+ switch(name)
45
+ end
46
+
47
+ #
48
+ # Convenience method for synchronizing threads.
49
+ #
50
+ def synchronize(&block)
51
+ DatabaseProxy.mutex.synchronize(&block)
52
+ end
53
+
54
+ #
55
+ # Switch to a different database on the same connection.
56
+ #
57
+ def switch(name)
58
+ synchronize do
59
+ # Connect to the cached database if available.
60
+ pool = (DatabaseProxy.pool[@connection] ||= {})
61
+ database = (pool[name] || (pool[name] = @connection.db(name)))
62
+
63
+ # Set the default if we haven't, and away we go (for this
64
+ # thread only).
65
+ @default ||= database
66
+ Thread.current[:mongo_database] = database
67
+ end
68
+ end
69
+
70
+ #
71
+ # Resets back to the default database connections.
72
+ #
73
+ def reset!
74
+ synchronize { Thread.current[:mongo_database] = nil }
75
+ end
76
+
77
+ #
78
+ # Returns the raw Mongo::DB object.
79
+ #
80
+ def target
81
+ synchronize { Thread.current[:mongo_database] || @default }
82
+ end
83
+
84
+ #
85
+ # Create a proxied collection.
86
+ #
87
+ def create_collection(name, opts)
88
+ CollectionProxy.new(self, name, opts)
89
+ end
90
+
91
+ #
92
+ # Proxy methods to the correct database.
93
+ #
94
+ def method_missing(*args, &block)
95
+ target.send(*args, &block)
96
+ end
97
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # This module handles functionality for creating default scopes.
5
+ module DefaultScope
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :default_scoping
10
+ end
11
+
12
+ module ClassMethods #:nodoc:
13
+
14
+ # Creates a default_scope for the +Document+, similar to ActiveRecord's
15
+ # default_scope. +DefaultScopes+ are proxied +Criteria+ objects that are
16
+ # applied by default to all queries for the class.
17
+ #
18
+ # @example Create a default scope.
19
+ #
20
+ # class Person
21
+ # include Mongoid::Document
22
+ # field :active, :type => Boolean
23
+ # field :count, :type => Integer
24
+ #
25
+ # default_scope :where => { :active => true }
26
+ # end
27
+ #
28
+ # @param [ Hash ] conditions The conditions to create with.
29
+ #
30
+ # @since 2.0.0.rc.1
31
+ def default_scope(conditions = {})
32
+ self.default_scoping = Scope.new(conditions).conditions.scoped
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Dirty #:nodoc:
4
+ extend ActiveSupport::Concern
5
+ include ActiveModel::Dirty
6
+
7
+ # Call this method after save, so the changes can be properly switched.
8
+ #
9
+ # This will unset the memoized children array, set new record to
10
+ # false, set the document as validated, and move the dirty changes.
11
+ #
12
+ # @example Move the changes to previous.
13
+ # person.move_changes
14
+ #
15
+ # @since 2.1.0
16
+ def move_changes
17
+ @_children = nil
18
+ @previously_changed = changes
19
+ atomic_pulls.clear
20
+ atomic_unsets.clear
21
+ delayed_atomic_sets.clear
22
+ delayed_atomic_pulls.clear
23
+ changed_attributes.clear
24
+ end
25
+
26
+ # Remove a change from the dirty attributes hash. Used by the single field
27
+ # atomic updators.
28
+ #
29
+ # @example Remove a flagged change.
30
+ # model.remove_change(:field)
31
+ #
32
+ # @param [ Symbol, String ] name The name of the field.
33
+ #
34
+ # @since 2.1.0
35
+ def remove_change(name)
36
+ changed_attributes.delete(name.to_s)
37
+ end
38
+
39
+ # Gets all the new values for each of the changed fields, to be passed to
40
+ # a MongoDB $set modifier.
41
+ #
42
+ # @example Get the setters for the atomic updates.
43
+ # person = Person.new(:title => "Sir")
44
+ # person.title = "Madam"
45
+ # person.setters # returns { "title" => "Madam" }
46
+ #
47
+ # @return [ Hash ] A +Hash+ of atomic setters.
48
+ def setters
49
+ {}.tap do |modifications|
50
+ changes.each_pair do |field, changes|
51
+ if changes
52
+ key = embedded? ? "#{atomic_position}.#{field}" : field
53
+ modifications[key] = changes[1]
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # Get the current value for the specified attribute, if the attribute has changed.
62
+ #
63
+ # @note This is overriding the AM::Dirty implementation to read from the mongoid
64
+ # attributes hash, which may contain a serialized version of the attributes data. It is
65
+ # necessary to read the serialized version as the changed value, to allow updates to
66
+ # the MongoDB document to persist correctly. For example, if a DateTime field is updated
67
+ # it must be persisted as a UTC Time.
68
+ #
69
+ # @return [ Object ] The current value of the field, or nil if no change made.
70
+ #
71
+ # @since 2.1.0
72
+ def attribute_change(attr)
73
+ [changed_attributes[attr], attributes[attr]] if attribute_changed?(attr)
74
+ end
75
+
76
+ # Determine if a specific attribute has changed.
77
+ #
78
+ # @note Overriding AM::Dirty once again since their implementation is not
79
+ # friendly to fields that can be changed in place.
80
+ #
81
+ # @param [ String ] attr The name of the attribute.
82
+ #
83
+ # @return [ true, false ] Whether the attribute has changed.
84
+ #
85
+ # @since 2.1.6
86
+ def attribute_changed?(attr)
87
+ return false unless changed_attributes.include?(attr)
88
+ changed_attributes[attr] != attributes[attr]
89
+ end
90
+
91
+ # Override Active Model's behaviour here in order to stay away from
92
+ # infinite loops on getter/setter overrides.
93
+ #
94
+ # @example Flag an attribute as changing.
95
+ # document.attribute_will_change!(:name)
96
+ #
97
+ # @param [ Symbol ] attr The attribute.
98
+ #
99
+ # @return [ Object ] The value of the attribute.
100
+ #
101
+ # @since 2.3.0
102
+ def attribute_will_change!(attr)
103
+ unless changed_attributes.include?(attr)
104
+ value = read_attribute(attr)
105
+ value = value.duplicable? ? value.clone : value
106
+ changed_attributes[attr] = value
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,280 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # This is the base module for all domain objects that need to be persisted to
5
+ # the database as documents.
6
+ module Document
7
+ extend ActiveSupport::Concern
8
+ include Mongoid::Components
9
+
10
+ attr_reader :new_record
11
+
12
+ # Default comparison is via the string version of the id.
13
+ #
14
+ # @example Compare two documents.
15
+ # person <=> other_person
16
+ #
17
+ # @param [ Document ] other The document to compare with.
18
+ #
19
+ # @return [ Integer ] -1, 0, 1.
20
+ def <=>(other)
21
+ attributes["_id"].to_s <=> other.attributes["_id"].to_s
22
+ end
23
+
24
+ # Performs equality checking on the document ids. For more robust
25
+ # equality checking please override this method.
26
+ #
27
+ # @example Compare for equality.
28
+ # document == other
29
+ #
30
+ # @param [ Document, Object ] other The other object to compare with.
31
+ #
32
+ # @return [ true, false ] True if the ids are equal, false if not.
33
+ def ==(other)
34
+ self.class == other.class &&
35
+ attributes["_id"] == other.attributes["_id"]
36
+ end
37
+
38
+ # Performs class equality checking.
39
+ #
40
+ # @example Compare the classes.
41
+ # document === other
42
+ #
43
+ # @param [ Document, Object ] other The other object to compare with.
44
+ #
45
+ # @return [ true, false ] True if the classes are equal, false if not.
46
+ def ===(other)
47
+ other.is_a?(self.class)
48
+ end
49
+
50
+ # Delegates to ==. Used when needing checks in hashes.
51
+ #
52
+ # @example Perform equality checking.
53
+ # document.eql?(other)
54
+ #
55
+ # @param [ Document, Object ] other The object to check against.
56
+ #
57
+ # @return [ true, false ] True if equal, false if not.
58
+ def eql?(other)
59
+ self == (other)
60
+ end
61
+
62
+ # Freezes the internal attributes of the document.
63
+ #
64
+ # @example Freeze the document
65
+ # document.freeze
66
+ #
67
+ # @return [ Document ] The document.
68
+ #
69
+ # @since 2.0.0
70
+ def freeze
71
+ attributes.freeze
72
+ self
73
+ end
74
+
75
+ # Checks if the document is frozen
76
+ #
77
+ # @example Check if frozen
78
+ # document.frozen?
79
+ #
80
+ # @return [ true, false ] True if frozen, else false.
81
+ #
82
+ # @since 2.0.0
83
+ def frozen?
84
+ raw_attributes.frozen?
85
+ end
86
+
87
+ # Delegates to id in order to allow two records of the same type and id to
88
+ # work with something like:
89
+ #
90
+ # [ Person.find(1), Person.find(2), Person.find(3) ] &
91
+ # [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
92
+ #
93
+ # @example Get the hash.
94
+ # document.hash
95
+ #
96
+ # @return [ Integer ] The hash of the document's id.
97
+ def hash
98
+ raw_attributes["_id"].hash
99
+ end
100
+
101
+ # Generate an id for this +Document+.
102
+ #
103
+ # @example Create the id.
104
+ # person.identify
105
+ #
106
+ # @return [ BSON::ObjectId, String ] A newly created id.
107
+ def identify
108
+ Identity.new(self).create
109
+ end
110
+
111
+ # Instantiate a new +Document+, setting the Document's attributes if
112
+ # given. If no attributes are provided, they will be initialized with
113
+ # an empty +Hash+.
114
+ #
115
+ # If a primary key is defined, the document's id will be set to that key,
116
+ # otherwise it will be set to a fresh +BSON::ObjectId+ string.
117
+ #
118
+ # @example Create a new document.
119
+ # Person.new(:title => "Sir")
120
+ #
121
+ # @param [ Hash ] attrs The attributes to set up the document with.
122
+ # @param [ Hash ] options A mass-assignment protection options. Supports
123
+ # :as and :without_protection
124
+ #
125
+ # @return [ Document ] A new document.
126
+ def initialize(attrs = nil, options = nil)
127
+ _building do
128
+ @new_record = true
129
+ @attributes ||= {}
130
+ options ||= {}
131
+ process(attrs, options[:as] || :default, !options[:without_protection]) do
132
+ identify
133
+ apply_defaults
134
+ yield(self) if block_given?
135
+ end
136
+ run_callbacks(:initialize) { self }
137
+ end
138
+ end
139
+
140
+ # Return an array with this +Document+ only in it.
141
+ #
142
+ # @example Return the document in an array.
143
+ # document.to_a
144
+ #
145
+ # @return [ Array<Document> ] An array with the document as its only item.
146
+ def to_a
147
+ [ self ]
148
+ end
149
+
150
+ # Return a hash of the entire document hierarchy from this document and
151
+ # below. Used when the attributes are needed for everything and not just
152
+ # the current document.
153
+ #
154
+ # @example Get the full hierarchy.
155
+ # person.as_document
156
+ #
157
+ # @return [ Hash ] A hash of all attributes in the hierarchy.
158
+ def as_document
159
+ attributes.tap do |attrs|
160
+ relations.each_pair do |name, meta|
161
+ if meta.embedded?
162
+ relation = send(name)
163
+ attrs[name] = relation.as_document unless relation.blank?
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ # Returns an instance of the specified class with the attributes
170
+ # and errors of the current document.
171
+ #
172
+ # @example Return a subclass document as a superclass instance.
173
+ # manager.becomes(Person)
174
+ #
175
+ # @raise [ ArgumentError ] If the class doesn't include Mongoid::Document
176
+ #
177
+ # @param [ Class ] klass The class to become.
178
+ #
179
+ # @return [ Document ] An instance of the specified class.
180
+ def becomes(klass)
181
+ unless klass.include?(Mongoid::Document)
182
+ raise ArgumentError, "A class which includes Mongoid::Document is expected"
183
+ end
184
+ klass.instantiate(frozen? ? attributes.dup : attributes).tap do |became|
185
+ became.instance_variable_set(:@errors, errors)
186
+ became.instance_variable_set(:@new_record, new_record?)
187
+ became.instance_variable_set(:@destroyed, destroyed?)
188
+ became._type = klass.to_s
189
+ end
190
+ end
191
+
192
+ private
193
+
194
+ # Returns the logger
195
+ #
196
+ # @return [ Logger ] The configured logger or a default Logger instance.
197
+ #
198
+ # @since 2.2.0
199
+ def logger
200
+ Mongoid.logger
201
+ end
202
+
203
+ # Implement this for calls to flatten on array.
204
+ #
205
+ # @example Get the document as an array.
206
+ # document.to_ary
207
+ #
208
+ # @return [ nil ] Always nil.
209
+ #
210
+ # @since 2.1.0
211
+ def to_ary
212
+ nil
213
+ end
214
+
215
+ module ClassMethods #:nodoc:
216
+
217
+ # Performs class equality checking.
218
+ #
219
+ # @example Compare the classes.
220
+ # document === other
221
+ #
222
+ # @param [ Document, Object ] other The other object to compare with.
223
+ #
224
+ # @return [ true, false ] True if the classes are equal, false if not.
225
+ #
226
+ # @since 2.0.0.rc.4
227
+ def ===(other)
228
+ self == (other.is_a?(Class) ? other : other.class)
229
+ end
230
+
231
+ # Instantiate a new object, only when loaded from the database or when
232
+ # the attributes have already been typecast.
233
+ #
234
+ # @example Create the document.
235
+ # Person.instantiate(:title => "Sir", :age => 30)
236
+ #
237
+ # @param [ Hash ] attrs The hash of attributes to instantiate with.
238
+ #
239
+ # @return [ Document ] A new document.
240
+ def instantiate(attrs = nil)
241
+ attributes = attrs || {}
242
+ allocate.tap do |doc|
243
+ doc.instance_variable_set(:@attributes, attributes)
244
+ doc.send(:apply_defaults)
245
+ IdentityMap.set(doc) unless _loading_revision?
246
+ doc.run_callbacks(:initialize) { doc }
247
+ end
248
+ end
249
+
250
+ # Returns all types to query for when using this class as the base.
251
+ #
252
+ # @example Get the types.
253
+ # document._types
254
+ #
255
+ # @return [ Array<Class> ] All subclasses of the current document.
256
+ def _types
257
+ @_type ||= [descendants + [self]].flatten.uniq.map { |t| t.to_s }
258
+ end
259
+
260
+ # Set the i18n scope to overwrite ActiveModel.
261
+ #
262
+ # @return [ Symbol ] :mongoid
263
+ def i18n_scope
264
+ :mongoid
265
+ end
266
+
267
+ # Returns the logger
268
+ #
269
+ # @example Get the logger.
270
+ # Person.logger
271
+ #
272
+ # @return [ Logger ] The configured logger or a default Logger instance.
273
+ #
274
+ # @since 2.2.0
275
+ def logger
276
+ Mongoid.logger
277
+ end
278
+ end
279
+ end
280
+ end