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,158 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Include this module to get soft deletion of root level documents.
5
+ # This will add a deleted_at field to the +Document+, managed automatically.
6
+ # Potentially incompatible with unique indices. (if collisions with deleted items)
7
+ #
8
+ # @example Make a document paranoid.
9
+ # class Person
10
+ # include Mongoid::Document
11
+ # include Mongoid::Paranoia
12
+ # end
13
+ module Paranoia
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ field :deleted_at, :type => Time
18
+ end
19
+
20
+ # Delete the paranoid +Document+ from the database completely. This will
21
+ # run the destroy callbacks.
22
+ #
23
+ # @example Hard destroy the document.
24
+ # document.destroy!
25
+ #
26
+ # @return [ true, false ] If the operation succeeded.
27
+ #
28
+ # @since 1.0.0
29
+ def destroy!
30
+ run_callbacks(:destroy) { delete! }
31
+ end
32
+
33
+ # Delete the paranoid +Document+ from the database completely.
34
+ #
35
+ # @example Hard delete the document.
36
+ # document.delete!
37
+ #
38
+ # @return [ true, false ] If the operation succeeded.
39
+ #
40
+ # @since 1.0.0
41
+ def delete!
42
+ Persistence::Operations.remove(self).persist
43
+ end
44
+
45
+ # Delete the +Document+, will set the deleted_at timestamp and not actually
46
+ # delete it.
47
+ #
48
+ # @example Soft remove the document.
49
+ # document.remove
50
+ #
51
+ # @param [ Hash ] options The database options.
52
+ #
53
+ # @return [ true ] True.
54
+ #
55
+ # @since 1.0.0
56
+ def remove(options = {})
57
+ time = self.deleted_at = Time.now
58
+ paranoid_collection.update(
59
+ atomic_selector,
60
+ { "$set" => { paranoid_field => time }},
61
+ Safety.merge_safety_options(options)
62
+ )
63
+ cascade!
64
+ @destroyed = true
65
+ IdentityMap.remove(self)
66
+ Threaded.clear_options!
67
+ true
68
+ end
69
+ alias :delete :remove
70
+
71
+ # Determines if this document is destroyed.
72
+ #
73
+ # @example Is the document destroyed?
74
+ # person.destroyed?
75
+ #
76
+ # @return [ true, false ] If the document is destroyed.
77
+ #
78
+ # @since 1.0.0
79
+ def destroyed?
80
+ @destroyed || !!deleted_at
81
+ end
82
+
83
+ # Restores a previously soft-deleted document. Handles this by removing the
84
+ # deleted_at flag.
85
+ #
86
+ # @example Restore the document from deleted state.
87
+ # document.restore
88
+ #
89
+ # @return [ Time ] The time the document had been deleted.
90
+ #
91
+ # @since 1.0.0
92
+ def restore
93
+ paranoid_collection.update(
94
+ atomic_selector,
95
+ { "$unset" => { paranoid_field => true }}
96
+ )
97
+ attributes.delete("deleted_at")
98
+ end
99
+
100
+ private
101
+
102
+ # Get the collection to be used for paranoid operations.
103
+ #
104
+ # @example Get the paranoid collection.
105
+ # document.paranoid_collection
106
+ #
107
+ # @return [ Collection ] The root collection.
108
+ #
109
+ # @since 2.3.1
110
+ def paranoid_collection
111
+ embedded? ? _root.collection : self.collection
112
+ end
113
+
114
+ # Get the field to be used for paranoid operations.
115
+ #
116
+ # @example Get the paranoid field.
117
+ # document.paranoid_field
118
+ #
119
+ # @return [ String ] The deleted at field.
120
+ #
121
+ # @since 2.3.1
122
+ def paranoid_field
123
+ embedded? ? "#{atomic_position}.deleted_at" : "deleted_at"
124
+ end
125
+
126
+ module ClassMethods #:nodoc:
127
+
128
+ # Override the default +Criteria+ accessor to only get existing
129
+ # documents. Passes all arguments up to +NamedScope.criteria+
130
+ #
131
+ # @example Override the criteria.
132
+ # Person.criteria
133
+ #
134
+ # @param [ Array ] args The arguments.
135
+ #
136
+ # @return [ Criteria ] The paranoid compliant criteria.
137
+ #
138
+ # @since 1.0.0
139
+ def criteria(embedded = false, scoped = true)
140
+ scoped ? super.where(:deleted_at => nil) : super
141
+ end
142
+
143
+ # Find deleted documents
144
+ #
145
+ # @example Find deleted documents.
146
+ # Person.deleted
147
+ # Company.first.employees.deleted
148
+ # Person.deleted.find("4c188dea7b17235a2a000001").first
149
+ #
150
+ # @return [ Criteria ] The deleted criteria.
151
+ #
152
+ # @since 1.0.0
153
+ def deleted
154
+ where(:deleted_at.ne => nil)
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,264 @@
1
+ # encoding: utf-8
2
+ require "mongoid/persistence/atomic"
3
+ require "mongoid/persistence/deletion"
4
+ require "mongoid/persistence/insertion"
5
+ require "mongoid/persistence/modification"
6
+ require "mongoid/persistence/operations"
7
+
8
+ module Mongoid #:nodoc:
9
+
10
+ # The persistence module is a mixin to provide database accessor methods for
11
+ # the document. These correspond to the appropriate accessors on a
12
+ # mongo collection and retain the same DSL.
13
+ #
14
+ # @example Sample persistence operations.
15
+ # document.insert
16
+ # document.update
17
+ # document.upsert
18
+ module Persistence
19
+ extend ActiveSupport::Concern
20
+ include Atomic
21
+
22
+ # Remove the document from the datbase with callbacks.
23
+ #
24
+ # @example Destroy a document.
25
+ # document.destroy
26
+ #
27
+ # @param [ Hash ] options Options to pass to destroy.
28
+ #
29
+ # @return [ true, false ] True if successful, false if not.
30
+ def destroy(options = {})
31
+ run_callbacks(:destroy) { remove(options) }
32
+ end
33
+
34
+ # Insert a new document into the database. Will return the document
35
+ # itself whether or not the save was successful.
36
+ #
37
+ # @example Insert a document.
38
+ # document.insert
39
+ #
40
+ # @param [ Hash ] options Options to pass to insert.
41
+ #
42
+ # @return [ Document ] The persisted document.
43
+ def insert(options = {})
44
+ Operations.insert(self, options).persist
45
+ end
46
+
47
+ # Remove the document from the datbase.
48
+ #
49
+ # @example Remove the document.
50
+ # document.remove
51
+ #
52
+ # @param [ Hash ] options Options to pass to remove.
53
+ #
54
+ # @return [ TrueClass ] True.
55
+ def remove(options = {})
56
+ Operations.remove(self, options).persist
57
+ end
58
+ alias :delete :remove
59
+
60
+ # Save the document - will perform an insert if the document is new, and
61
+ # update if not. If a validation error occurs an error will get raised.
62
+ #
63
+ # @example Save the document.
64
+ # document.save!
65
+ #
66
+ # @param [ Hash ] options Options to pass to the save.
67
+ #
68
+ # @return [ true, false ] True if validation passed.
69
+ def save!(options = {})
70
+ unless upsert(options)
71
+ self.class.fail_validate!(self) if errors.any?
72
+ self.class.fail_callback!(self, :save!)
73
+ end
74
+ return true
75
+ end
76
+
77
+ # Update the document in the datbase.
78
+ #
79
+ # @example Update an existing document.
80
+ # document.update
81
+ #
82
+ # @param [ Hash ] options Options to pass to update.
83
+ #
84
+ # @return [ true, false ] True if succeeded, false if not.
85
+ def update(options = {})
86
+ Operations.update(self, options).persist
87
+ end
88
+
89
+ # Update a single attribute and persist the entire document.
90
+ # This skips validation but fires the callbacks.
91
+ #
92
+ # @example Update the attribute.
93
+ # person.update_attribute(:title, "Sir")
94
+ #
95
+ # @param [ Symbol, String ] name The name of the attribute.
96
+ # @param [ Object ] value The new value of the attribute.a
97
+ #
98
+ # @return [ true, false ] True if save was successfull, false if not.
99
+ #
100
+ # @since 2.0.0.rc.6
101
+ def update_attribute(name, value)
102
+ write_attribute(name, value)
103
+ save(:validate => false)
104
+ end
105
+
106
+ # Update the document attributes in the datbase.
107
+ #
108
+ # @example Update the document's attributes
109
+ # document.update_attributes(:title => "Sir")
110
+ #
111
+ # @param [ Hash ] attributes The attributes to update.
112
+ #
113
+ # @return [ true, false ] True if validation passed, false if not.
114
+ def update_attributes(attributes = {})
115
+ write_attributes(attributes); save
116
+ end
117
+
118
+ # Update the document attributes in the database and raise an error if
119
+ # validation failed.
120
+ #
121
+ # @example Update the document's attributes.
122
+ # document.update_attributes(:title => "Sir")
123
+ #
124
+ # @param [ Hash ] attributes The attributes to update.
125
+ #
126
+ # @raise [ Errors::Validations ] If validation failed.
127
+ #
128
+ # @return [ true, false ] True if validation passed.
129
+ def update_attributes!(attributes = {})
130
+ update_attributes(attributes).tap do |result|
131
+ unless result
132
+ self.class.fail_validate!(self) if errors.any?
133
+ self.class.fail_callback!(self, :update_attributes!)
134
+ end
135
+ end
136
+ end
137
+
138
+ # Upsert the document - will perform an insert if the document is new, and
139
+ # update if not.
140
+ #
141
+ # @example Upsert the document.
142
+ # document.upsert
143
+ #
144
+ # @param [ Hash ] options Options to pass to the upsert.
145
+ #
146
+ # @return [ true, false ] True is success, false if not.
147
+ def upsert(options = {})
148
+ if new_record?
149
+ insert(options).persisted?
150
+ else
151
+ update(options)
152
+ end
153
+ end
154
+ alias :save :upsert
155
+
156
+ module ClassMethods #:nodoc:
157
+
158
+ # Create a new document. This will instantiate a new document and
159
+ # insert it in a single call. Will always return the document
160
+ # whether save passed or not.
161
+ #
162
+ # @example Create a new document.
163
+ # Person.create(:title => "Mr")
164
+ #
165
+ # @param [ Hash ] attributes The attributes to create with.
166
+ # @param [ Hash ] options A mass-assignment protection options. Supports
167
+ # :as and :without_protection
168
+ #
169
+ # @return [ Document ] The newly created document.
170
+ def create(attributes = {}, options = {}, &block)
171
+ _creating do
172
+ new(attributes, options, &block).tap { |doc| doc.save }
173
+ end
174
+ end
175
+
176
+ # Create a new document. This will instantiate a new document and
177
+ # insert it in a single call. Will always return the document
178
+ # whether save passed or not, and if validation fails an error will be
179
+ # raise.
180
+ #
181
+ # @example Create a new document.
182
+ # Person.create!(:title => "Mr")
183
+ #
184
+ # @param [ Hash ] attributes The attributes to create with.
185
+ # @param [ Hash ] options A mass-assignment protection options. Supports
186
+ # :as and :without_protection
187
+ #
188
+ # @return [ Document ] The newly created document.
189
+ def create!(attributes = {}, options = {}, &block)
190
+ _creating do
191
+ new(attributes, options, &block).tap do |doc|
192
+ fail_validate!(doc) if doc.insert.errors.any?
193
+ fail_callback!(doc, :create!) if doc.new?
194
+ end
195
+ end
196
+ end
197
+
198
+ # Delete all documents given the supplied conditions. If no conditions
199
+ # are passed, the entire collection will be dropped for performance
200
+ # benefits. Does not fire any callbacks.
201
+ #
202
+ # @example Delete matching documents from the collection.
203
+ # Person.delete_all(:conditions => { :title => "Sir" })
204
+ #
205
+ # @example Delete all documents from the collection.
206
+ # Person.delete_all
207
+ #
208
+ # @param [ Hash ] conditions Optional conditions to delete by.
209
+ #
210
+ # @return [ Integer ] The number of documents deleted.
211
+ def delete_all(conditions = nil)
212
+ selector = (conditions || {})[:conditions] || {}
213
+ selector.merge!(:_type => name) if hereditary?
214
+ collection.find(selector).count.tap do
215
+ collection.remove(selector, Safety.merge_safety_options)
216
+ Threaded.clear_options!
217
+ end
218
+ end
219
+
220
+ # Delete all documents given the supplied conditions. If no conditions
221
+ # are passed, the entire collection will be dropped for performance
222
+ # benefits. Fires the destroy callbacks if conditions were passed.
223
+ #
224
+ # @example Destroy matching documents from the collection.
225
+ # Person.destroy_all(:conditions => { :title => "Sir" })
226
+ #
227
+ # @example Destroy all documents from the collection.
228
+ # Person.destroy_all
229
+ #
230
+ # @param [ Hash ] conditions Optional conditions to destroy by.
231
+ #
232
+ # @return [ Integer ] The number of documents destroyed.
233
+ def destroy_all(conditions = {})
234
+ documents = all(conditions)
235
+ documents.count.tap do
236
+ documents.each { |doc| doc.destroy }
237
+ end
238
+ end
239
+
240
+ # Raise an error if validation failed.
241
+ #
242
+ # @example Raise the validation error.
243
+ # Person.fail_validate!(person)
244
+ #
245
+ # @param [ Document ] document The document to fail.
246
+ def fail_validate!(document)
247
+ raise Errors::Validations.new(document)
248
+ end
249
+
250
+ # Raise an error if a callback failed.
251
+ #
252
+ # @example Raise the callback error.
253
+ # Person.fail_callback!(person, :create!)
254
+ #
255
+ # @param [ Document ] document The document to fail.
256
+ # @param [ Symbol ] method The method being called.
257
+ #
258
+ # @since 2.2.0
259
+ def fail_callback!(document, method)
260
+ raise Errors::Callback.new(document.class, method)
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,223 @@
1
+ # encoding: utf-8
2
+ require "mongoid/persistence/atomic/operation"
3
+ require "mongoid/persistence/atomic/add_to_set"
4
+ require "mongoid/persistence/atomic/bit"
5
+ require "mongoid/persistence/atomic/inc"
6
+ require "mongoid/persistence/atomic/pop"
7
+ require "mongoid/persistence/atomic/pull"
8
+ require "mongoid/persistence/atomic/pull_all"
9
+ require "mongoid/persistence/atomic/push"
10
+ require "mongoid/persistence/atomic/push_all"
11
+ require "mongoid/persistence/atomic/rename"
12
+ require "mongoid/persistence/atomic/sets"
13
+ require "mongoid/persistence/atomic/unset"
14
+
15
+ module Mongoid #:nodoc:
16
+ module Persistence #:nodoc:
17
+
18
+ # This module provides the explicit atomic operations helpers on the
19
+ # document itself.
20
+ module Atomic
21
+
22
+ # Performs an atomic $addToSet of the provided value on the supplied field.
23
+ # If the field does not exist it will be initialized as an empty array.
24
+ #
25
+ # If the value already exists on the array it will not be added.
26
+ #
27
+ # @example Add only a unique value on the field.
28
+ # person.add_to_set(:aliases, "Bond")
29
+ #
30
+ # @param [ Symbol ] field The name of the field.
31
+ # @param [ Object ] value The value to add.
32
+ # @param [ Hash ] options The mongo persistence options.
33
+ #
34
+ # @return [ Array<Object> ] The new value of the field.
35
+ #
36
+ # @since 2.0.0
37
+ def add_to_set(field, value, options = {})
38
+ AddToSet.new(self, field, value, options).persist
39
+ end
40
+
41
+ # Performs an atomic $bit operation on the field with the provided hash
42
+ # of bitwise ops to execute in order.
43
+ #
44
+ # @example Execute a bitwise and on the field.
45
+ # person.bit(:age, { :and => 12 })
46
+ #
47
+ # @example Execute a bitwise or on the field.
48
+ # person.bit(:age, { :or => 12 })
49
+ #
50
+ # @example Execute a chain of bitwise operations.
51
+ # person.bit(:age, { :and => 10, :or => 12 })
52
+ #
53
+ # @param [ Symbol ] field The name of the field.
54
+ # @param [ Hash ] value The bitwise operations to perform.
55
+ # @param [ Hash ] options The mongo persistence options.
56
+ #
57
+ # @return [ Integer ] The new value of the field.
58
+ #
59
+ # @since 2.1.0
60
+ def bit(field, value, options = {})
61
+ Bit.new(self, field, value, options).persist
62
+ end
63
+
64
+ # Performs an atomic $inc of the provided value on the supplied
65
+ # field. If the field does not exist it will be initialized as
66
+ # the provided value.
67
+ #
68
+ # @example Increment a field.
69
+ # person.inc(:score, 2)
70
+ #
71
+ # @param [ Symbol ] field The name of the field.
72
+ # @param [ Integer ] value The value to increment.
73
+ # @param [ Hash ] options The mongo persistence options.
74
+ #
75
+ # @return [ Array<Object> ] The new value of the field.
76
+ #
77
+ # @since 2.0.0
78
+ def inc(field, value, options = {})
79
+ Inc.new(self, field, value, options).persist
80
+ end
81
+
82
+ # Performs an atomic $pop of the provided value on the supplied
83
+ # field.
84
+ #
85
+ # @example Pop the last value from the array.
86
+ # person.pop(:aliases, 1)
87
+ #
88
+ # @example Pop the first value from the array.
89
+ # person.pop(:aliases, -1)
90
+ #
91
+ # @param [ Symbol ] field The name of the field.
92
+ # @param [ Integer ] value Whether to pop the first or last.
93
+ # @param [ Hash ] options The mongo persistence options.
94
+ #
95
+ # @return [ Array<Object> ] The new value of the field.
96
+ #
97
+ # @since 2.1.0
98
+ def pop(field, value, options = {})
99
+ Pop.new(self, field, value, options).persist
100
+ end
101
+
102
+ # Performs an atomic $pull of the provided value on the supplied
103
+ # field.
104
+ #
105
+ # @note Support for a $pull with an expression is not yet supported.
106
+ #
107
+ # @example Pull the value from the field.
108
+ # person.pull(:aliases, "Bond")
109
+ #
110
+ # @param [ Symbol ] field The name of the field.
111
+ # @param [ Object ] value The value to pull.
112
+ # @param [ Hash ] options The mongo persistence options.
113
+ #
114
+ # @return [ Array<Object> ] The new value of the field.
115
+ #
116
+ # @since 2.1.0
117
+ def pull(field, value, options = {})
118
+ Pull.new(self, field, value, options).persist
119
+ end
120
+
121
+ # Performs an atomic $pullAll of the provided value on the supplied
122
+ # field. If the field does not exist it will be initialized as an
123
+ # empty array.
124
+ #
125
+ # @example Pull the values from the field.
126
+ # person.pull_all(:aliases, [ "Bond", "James" ])
127
+ #
128
+ # @param [ Symbol ] field The name of the field.
129
+ # @param [ Array<Object> ] value The values to pull.
130
+ # @param [ Hash ] options The mongo persistence options.
131
+ #
132
+ # @return [ Array<Object> ] The new value of the field.
133
+ #
134
+ # @since 2.0.0
135
+ def pull_all(field, value, options = {})
136
+ PullAll.new(self, field, value, options).persist
137
+ end
138
+
139
+ # Performs an atomic $push of the provided value on the supplied field. If
140
+ # the field does not exist it will be initialized as an empty array.
141
+ #
142
+ # @example Push a value on the field.
143
+ # person.push(:aliases, "Bond")
144
+ #
145
+ # @param [ Symbol ] field The name of the field.
146
+ # @param [ Object ] value The value to push.
147
+ # @param [ Hash ] options The mongo persistence options.
148
+ #
149
+ # @return [ Array<Object> ] The new value of the field.
150
+ #
151
+ # @since 2.0.0
152
+ def push(field, value, options = {})
153
+ Push.new(self, field, value, options).persist
154
+ end
155
+
156
+ # Performs an atomic $pushAll of the provided value on the supplied field. If
157
+ # the field does not exist it will be initialized as an empty array.
158
+ #
159
+ # @example Push the values onto the field.
160
+ # person.push_all(:aliases, [ "Bond", "James" ])
161
+ #
162
+ # @param [ Symbol ] field The name of the field.
163
+ # @param [ Array<Object> ] value The values to push.
164
+ # @param [ Hash ] options The mongo persistence options.
165
+ #
166
+ # @return [ Array<Object> ] The new value of the field.
167
+ #
168
+ # @since 2.1.0
169
+ def push_all(field, value, options = {})
170
+ PushAll.new(self, field, value, options).persist
171
+ end
172
+
173
+ # Performs the atomic $rename from the old field to the new field name.
174
+ #
175
+ # @example Rename the field.
176
+ # person.rename(:age, :years)
177
+ #
178
+ # @param [ Symbol ] field The old field name.
179
+ # @param [ Symbol ] value The new field name.
180
+ # @param [ Hash ] options The mongo persistence options.
181
+ #
182
+ # @return [ Object ] The value of the new field.
183
+ #
184
+ # @since 2.1.0
185
+ def rename(field, value, options = {})
186
+ Rename.new(self, field, value, options).persist
187
+ end
188
+
189
+ # Performs an atomic $set of the provided value on the supplied
190
+ # field. If the field does not exist it will be initialized as
191
+ # the provided value.
192
+ #
193
+ # @example Set a field.
194
+ # person.set(:score, 2)
195
+ #
196
+ # @param [ Symbol ] field The name of the field.
197
+ # @param [ Integer ] value The value to set.
198
+ # @param [ Hash ] options The mongo persistence options.
199
+ #
200
+ # @return [ Array<Object> ] The new value of the field.
201
+ #
202
+ # @since 2.1.0
203
+ def set(field, value = nil, options = {})
204
+ Sets.new(self, field, value, options).persist
205
+ end
206
+
207
+ # Performs the atomic $unset on the supplied field.
208
+ #
209
+ # @example Remove the field.
210
+ # person.unset(:age)
211
+ #
212
+ # @param [ Symbol ] field The field name.
213
+ # @param [ Hash ] options The mongo persistence options.
214
+ #
215
+ # @return [ nil ] Always nil.
216
+ #
217
+ # @since 2.1.0
218
+ def unset(field, options = {})
219
+ Unset.new(self, field, 1, options).persist
220
+ end
221
+ end
222
+ end
223
+ end