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,186 @@
1
+ require 'mongoid/connection_proxy'
2
+
3
+ # encoding: utf-8
4
+ module Mongoid #:nodoc:
5
+ module Config #:nodoc:
6
+
7
+ # This class handles the configuration and initialization of a mongodb
8
+ # database from options.
9
+ class Database < Hash
10
+
11
+ # keys to remove from self to not pass through to Mongo::Connection
12
+ PRIVATE_OPTIONS = %w(uri database username password logger)
13
+
14
+ # Configure the database connections. This will return an array
15
+ # containing the master and an array of slaves.
16
+ #
17
+ # @example Configure the connection.
18
+ # db.configure
19
+ #
20
+ # @return [ Array<Mongo::DB, Array<Mongo:DB>> ] The Mongo databases.
21
+ #
22
+ # @since 2.0.0.rc.1
23
+ def configure
24
+ [ master.db(name), slaves.map { |slave| slave.db(name) } ]
25
+ end
26
+
27
+ # Create the new db configuration class.
28
+ #
29
+ # @example Initialize the class.
30
+ # Config::Database.new(
31
+ # false, "uri" => { "mongodb://durran:password@localhost:27017/mongoid" }
32
+ # )
33
+ #
34
+ # @param [ Hash ] options The configuration options.
35
+ #
36
+ # @option options [ String ] :database The database name.
37
+ # @option options [ String ] :host The database host.
38
+ # @option options [ String ] :password The password for authentication.
39
+ # @option options [ Integer ] :port The port for the database.
40
+ # @option options [ String ] :uri The uri for the database.
41
+ # @option options [ String ] :username The user for authentication.
42
+ #
43
+ # @since 2.0.0.rc.1
44
+ def initialize(options = {})
45
+ merge!(options)
46
+ end
47
+
48
+ private
49
+
50
+ # Do we need to authenticate against the database?
51
+ #
52
+ # @example Are we authenticating?
53
+ # db.authenticating?
54
+ #
55
+ # @return [ true, false ] True if auth is needed, false if not.
56
+ #
57
+ # @since 2.0.0.rc.1
58
+ def authenticating?
59
+ username || password
60
+ end
61
+
62
+ # Takes the supplied options in the hash and created a URI from them to
63
+ # pass to the Mongo connection object.
64
+ #
65
+ # @example Build the URI.
66
+ # db.build_uri
67
+ #
68
+ # @param [ Hash ] options The options to build with.
69
+ #
70
+ # @return [ String ] A mongo compliant URI string.
71
+ #
72
+ # @since 2.0.0.rc.1
73
+ def build_uri(options = {})
74
+ "mongodb://".tap do |base|
75
+ base << "#{username}:#{password}@" if authenticating?
76
+ base << "#{options["host"] || "localhost"}:#{options["port"] || 27017}"
77
+ base << "/#{self["database"]}" if authenticating?
78
+ end
79
+ end
80
+
81
+ # Create the mongo master connection from either the supplied URI
82
+ # or a generated one, while setting pool size and logging.
83
+ #
84
+ # @example Create the connection.
85
+ # db.connection
86
+ #
87
+ # @return [ Mongo::Connection ] The mongo connection.
88
+ #
89
+ # @since 2.0.0.rc.1
90
+ def master
91
+ ConnectionProxy.from_uri(uri(self), optional).tap do |conn|
92
+ conn.apply_saved_authentication
93
+ end
94
+ end
95
+
96
+ # Create the mongo slave connections from either the supplied URI
97
+ # or a generated one, while setting pool size and logging.
98
+ #
99
+ # @example Create the connection.
100
+ # db.connection
101
+ #
102
+ # @return [ Array<Mongo::Connection> ] The mongo slave connections.
103
+ #
104
+ # @since 2.0.0.rc.1
105
+ def slaves
106
+ (self["slaves"] || []).map do |options|
107
+ ConnectionProxy.from_uri(uri(options), optional(true)).tap do |conn|
108
+ conn.apply_saved_authentication
109
+ end
110
+ end
111
+ end
112
+
113
+ # Should we use a logger?
114
+ #
115
+ # @example Should we use a logger?
116
+ # database.logger?
117
+ #
118
+ # @return [ true, false ] Defaults to true, false if specifically
119
+ # defined.
120
+ #
121
+ # @since 2.2.0
122
+ def logger?
123
+ self[:logger].nil? || self[:logger] ? true : false
124
+ end
125
+
126
+ # Convenience for accessing the hash via dot notation.
127
+ #
128
+ # @example Access a value in alternate syntax.
129
+ # db.host
130
+ #
131
+ # @return [ Object ] The value in the hash.
132
+ #
133
+ # @since 2.0.0.rc.1
134
+ def method_missing(name, *args, &block)
135
+ self[name.to_s]
136
+ end
137
+
138
+ # Get the name of the database, from either the URI supplied or the
139
+ # database value in the options.
140
+ #
141
+ # @example Get the database name.
142
+ # db.name
143
+ #
144
+ # @return [ String ] The database name.
145
+ #
146
+ # @since 2.0.0.rc.1
147
+ def name
148
+ db_name = URI.parse(uri(self)).path.to_s.sub("/", "")
149
+ db_name.blank? ? database : db_name
150
+ end
151
+
152
+ # Get the options used in creating the database connection.
153
+ #
154
+ # @example Get the options.
155
+ # db.options
156
+ #
157
+ # @param [ true, false ] slave Are the options for a slave db?
158
+ #
159
+ # @return [ Hash ] The hash of configuration options.
160
+ #
161
+ # @since 2.0.0.rc.1
162
+ def optional(slave = false)
163
+ ({
164
+ :pool_size => pool_size,
165
+ :logger => logger? ? Mongoid::Logger.new : nil,
166
+ :slave_ok => slave
167
+ }).merge(self).reject { |k,v| PRIVATE_OPTIONS.include? k }.
168
+ inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo} # mongo likes symbols
169
+ end
170
+
171
+ # Get a Mongo compliant URI for the database connection.
172
+ #
173
+ # @example Get the URI.
174
+ # db.uri
175
+ #
176
+ # @param [ Hash ] options The options hash.
177
+ #
178
+ # @return [ String ] The URI for the connection.
179
+ #
180
+ # @since 2.0.0.rc.1
181
+ def uri(options = {})
182
+ options["uri"] || build_uri(options)
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Config #:nodoc:
4
+ class ReplsetDatabase < Hash
5
+
6
+ # Configure the database connections. This will return an array
7
+ # containing one Mongo::DB and nil (to keep compatibility with Mongoid::Config::Database)
8
+ # If you want the reads to go to a secondary node use the :read_secondary(true): option
9
+ #
10
+ # @example Configure the connection.
11
+ # db.configure
12
+ #
13
+ # @return [ Array<Mongo::DB, nil ] The Mongo databases.
14
+ #
15
+ # @since 2.0.0.rc.5
16
+ def configure
17
+ # yes, construction is weird but the driver wants
18
+ # "A list of host-port pairs ending with a hash containing any options"
19
+ # mongo likes symbols
20
+ options = self.inject({ :logger => Mongoid::Logger.new }) do |memo, (k, v)|
21
+ memo[k.to_sym] = v
22
+ memo
23
+ end
24
+ connection = Mongo::ReplSetConnection.new(*(hosts.clone << options))
25
+
26
+ if authenticating?
27
+ connection.add_auth(database, username, password)
28
+ connection.apply_saved_authentication
29
+ end
30
+
31
+ [ DatabaseProxy.new(connection, database), nil ]
32
+ end
33
+
34
+ # Do we need to authenticate against the database?
35
+ #
36
+ # @example Are we authenticating?
37
+ # db.authenticating?
38
+ #
39
+ # @return [ true, false ] True if auth is needed, false if not.
40
+ #
41
+ # @since 2.0.2
42
+ def authenticating?
43
+ username || password
44
+ end
45
+
46
+ # Convenience for accessing the hash via dot notation.
47
+ #
48
+ # @example Access a value in alternate syntax.
49
+ # db.host
50
+ #
51
+ # @return [ Object ] The value in the hash.
52
+ #
53
+ # @since 2.0.2
54
+ def method_missing(name, *args, &block)
55
+ self[name.to_s]
56
+ end
57
+
58
+ # Create the new db configuration class.
59
+ #
60
+ # @example Initialize the class.
61
+ # Config::ReplsetDatabase.new(
62
+ # "hosts" => [[host1,port1],[host2,port2]]
63
+ # )
64
+ #
65
+ # replSet does not supports auth
66
+ #
67
+ # @param [ Hash ] options The configuration options.
68
+ #
69
+ # @option options [ Array ] :hosts The database host.
70
+ # @option options [ String ] :database The database name.
71
+ # @option options [ Boolean ] :read_secondary Tells the driver to read from secondaries.
72
+ # ...
73
+ #
74
+ # @see Mongo::ReplSetConnection for all options
75
+ #
76
+ # @since 2.0.0.rc.5
77
+ def initialize(options = {})
78
+ merge!(options)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,30 @@
1
+ require 'mongoid/database_proxy'
2
+
3
+ #
4
+ # Proxy that enables runtime swapping of the MongoDB connection. This is
5
+ # not an ideal-solution, performance-wise, as a quick check shows that
6
+ # method invocation via method_missing is about three times as slow as
7
+ # direct invocation on the object.
8
+ #
9
+ # What this does allow us to do, however, is very transparently swap out
10
+ # Mongo::Connection instances underneath Mongoid, without having to
11
+ # rewrite large portions of the codebase. In theory, this should result
12
+ # in a relatively painless connection-swapping system.
13
+ #
14
+ class ConnectionProxy
15
+ def ConnectionProxy.from_uri(*args)
16
+ new(*args)
17
+ end
18
+
19
+ def initialize(*args)
20
+ @connection = Mongo::Connection.from_uri(*args)
21
+ end
22
+
23
+ def db(name)
24
+ @database ||= DatabaseProxy.new(@connection, name)
25
+ end
26
+
27
+ def method_missing(*args, &block)
28
+ @connection.send(*args, &block)
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require "mongoid/contexts/enumerable"
3
+ require "mongoid/contexts/mongo"
4
+
5
+ module Mongoid
6
+ module Contexts
7
+ extend self
8
+
9
+ # Determines the context to be used for this criteria. If the class is an
10
+ # embedded document, then the context will be the array in the has_many
11
+ # association it is in. If the class is a root, then the database itself
12
+ # will be the context.
13
+ #
14
+ # @example Get the context for the criteria.
15
+ # Contexts.context_for(criteria)
16
+ #
17
+ # @param [ Criteria ] criteria The criteria to use.
18
+ # @param [ true, false ] embedded Whether this is on embedded documents.
19
+ #
20
+ # @return [ Enumerable, Mongo ] The appropriate context.
21
+ def context_for(criteria, embedded = false)
22
+ embedded ? Enumerable.new(criteria) : Mongo.new(criteria)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,288 @@
1
+ # encoding: utf-8
2
+ require 'mongoid/contexts/enumerable/sort'
3
+
4
+ module Mongoid #:nodoc:
5
+ module Contexts #:nodoc:
6
+ class Enumerable
7
+ include Relations::Embedded::Atomic
8
+
9
+ attr_accessor :collection, :criteria
10
+
11
+ delegate :blank?, :empty?, :first, :last, :to => :execute
12
+ delegate :klass, :documents, :options, :field_list, :selector, :to => :criteria
13
+
14
+ # Return aggregation counts of the grouped documents. This will count by
15
+ # the first field provided in the fields array.
16
+ #
17
+ # @example Aggregate on a field.
18
+ # person.addresses.only(:street).aggregate
19
+ #
20
+ # @return [ Hash ] Field values as keys, count as values
21
+ def aggregate
22
+ {}.tap do |counts|
23
+ group.each_pair { |key, value| counts[key] = value.size }
24
+ end
25
+ end
26
+
27
+ # Get the average value for the supplied field.
28
+ #
29
+ # @example Get the average.
30
+ # context.avg(:age)
31
+ #
32
+ # @return [ Numeric ] A numeric value that is the average.
33
+ def avg(field)
34
+ total = sum(field)
35
+ total ? (total.to_f / count) : nil
36
+ end
37
+
38
+ # Gets the number of documents in the array. Delegates to size.
39
+ #
40
+ # @example Get the count.
41
+ # context.count
42
+ #
43
+ # @return [ Integer ] The count of documents.
44
+ def count
45
+ @count ||= execute.size
46
+ end
47
+ alias :length :count
48
+ alias :size :count
49
+
50
+ # Delete all the documents in the database matching the selector.
51
+ #
52
+ # @example Delete the documents.
53
+ # context.delete_all
54
+ #
55
+ # @return [ Integer ] The number of documents deleted.
56
+ #
57
+ # @since 2.0.0.rc.1
58
+ def delete_all
59
+ atomically(:$pull) do
60
+ set_collection
61
+ count.tap do
62
+ filter.each { |doc| doc.delete }
63
+ end
64
+ end
65
+ end
66
+ alias :delete :delete_all
67
+
68
+ # Destroy all the documents in the database matching the selector.
69
+ #
70
+ # @example Destroy the documents.
71
+ # context.destroy_all
72
+ #
73
+ # @return [ Integer ] The number of documents destroyed.
74
+ #
75
+ # @since 2.0.0.rc.1
76
+ def destroy_all
77
+ atomically(:$pull) do
78
+ set_collection
79
+ count.tap do
80
+ filter.each { |doc| doc.destroy }
81
+ end
82
+ end
83
+ end
84
+ alias :destroy :destroy_all
85
+
86
+ # Gets an array of distinct values for the supplied field across the
87
+ # entire array or the susbset given the criteria.
88
+ #
89
+ # @example Get the list of distinct values.
90
+ # context.distinct(:title)
91
+ #
92
+ # @return [ Array<String> ] The distinct values.
93
+ def distinct(field)
94
+ execute.collect { |doc| doc.send(field) }.uniq
95
+ end
96
+
97
+ # Enumerable implementation of execute. Returns matching documents for
98
+ # the selector, and adds options if supplied.
99
+ #
100
+ # @example Execute the context.
101
+ # context.execute
102
+ #
103
+ # @return [ Array<Document> ] Documents that matched the selector.
104
+ def execute
105
+ limit(sort(filter)) || []
106
+ end
107
+
108
+ # Groups the documents by the first field supplied in the field options.
109
+ #
110
+ # @example Group the context.
111
+ # context.group
112
+ #
113
+ # @return [ Hash ] Field values as keys, arrays of documents as values.
114
+ def group
115
+ field = field_list.first
116
+ execute.group_by { |doc| doc.send(field) }
117
+ end
118
+
119
+ # Create the new enumerable context. This will need the selector and
120
+ # options from a +Criteria+ and a documents array that is the underlying
121
+ # array of embedded documents from a has many association.
122
+ #
123
+ # @example Create a new context.
124
+ # Mongoid::Contexts::Enumerable.new(criteria)
125
+ #
126
+ # @param [ Criteria ] criteria The criteria for the context.
127
+ def initialize(criteria)
128
+ @criteria = criteria
129
+ end
130
+
131
+ # Iterate over each +Document+ in the results. This can take an optional
132
+ # block to pass to each argument in the results.
133
+ #
134
+ # @example Iterate over the documents.
135
+ # context.iterate { |doc| p doc }
136
+ def iterate(&block)
137
+ execute.each(&block)
138
+ end
139
+
140
+ # Get the largest value for the field in all the documents.
141
+ #
142
+ # @example Get the max value.
143
+ # context.max(:age)
144
+ #
145
+ # @return [ Numeric ] The numerical largest value.
146
+ def max(field)
147
+ determine(field, :>=)
148
+ end
149
+
150
+ # Get the smallest value for the field in all the documents.
151
+ #
152
+ # @example Get the minimum value.
153
+ # context.min(:age)
154
+ #
155
+ # @return [ Numeric ] The numerical smallest value.
156
+ def min(field)
157
+ determine(field, :<=)
158
+ end
159
+
160
+ # Get one document.
161
+ #
162
+ # @example Get one document.
163
+ # context.one
164
+ #
165
+ # @return [ Document ] The first document in the array.
166
+ alias :one :first
167
+
168
+ # Get one document and tell the criteria to skip this record on
169
+ # successive calls.
170
+ #
171
+ # @example Shift the documents.
172
+ # context.shift
173
+ #
174
+ # @return [ Document ] The first document in the array.
175
+ def shift
176
+ first.tap do |document|
177
+ self.criteria = criteria.skip((options[:skip] || 0) + 1)
178
+ end
179
+ end
180
+
181
+ # Get the sum of the field values for all the documents.
182
+ #
183
+ # @example Get the sum of the field.
184
+ # context.sum(:cost)
185
+ #
186
+ # @return [ Numeric ] The numerical sum of all the document field values.
187
+ def sum(field)
188
+ sum = execute.inject(nil) do |memo, doc|
189
+ value = doc.send(field) || 0
190
+ memo ? memo += value : value
191
+ end
192
+ end
193
+
194
+ # Very basic update that will perform a simple atomic $set of the
195
+ # attributes provided in the hash. Can be expanded to later for more
196
+ # robust functionality.
197
+ #
198
+ # @example Update all matching documents.
199
+ # context.update_all(:title => "Sir")
200
+ #
201
+ # @param [ Hash ] attributes The sets to perform.
202
+ #
203
+ # @since 2.0.0.rc.6
204
+ def update_all(attributes = nil)
205
+ iterate do |doc|
206
+ doc.update_attributes(attributes || {})
207
+ end
208
+ end
209
+ alias :update :update_all
210
+
211
+ protected
212
+
213
+ # Filters the documents against the criteria's selector
214
+ #
215
+ # @example Filter the documents.
216
+ # context.filter
217
+ #
218
+ # @return [ Array ] The documents filtered.
219
+ def filter
220
+ documents.select { |document| document.matches?(selector) }
221
+ end
222
+
223
+ # If the field exists, perform the comparison and set if true.
224
+ #
225
+ # @example Compare.
226
+ # context.determine
227
+ #
228
+ # @return [ Array<Document> ] The matching documents.
229
+ def determine(field, operator)
230
+ matching = documents.inject(nil) do |memo, doc|
231
+ value = doc.send(field) || 0
232
+ (memo && memo.send(operator, value)) ? memo : value
233
+ end
234
+ end
235
+
236
+ # Limits the result set if skip and limit options.
237
+ #
238
+ # @example Limit the results.
239
+ # context.limit(documents)
240
+ #
241
+ # @return [ Array<Document> ] The limited documents.
242
+ def limit(documents)
243
+ skip, limit = options[:skip], options[:limit]
244
+ if skip && limit
245
+ return documents.slice(skip, limit)
246
+ elsif limit
247
+ return documents.first(limit)
248
+ elsif skip
249
+ return documents.slice(skip..-1)
250
+ end
251
+ documents
252
+ end
253
+
254
+ def root
255
+ @root ||= documents.first.try(:_root)
256
+ end
257
+
258
+ def root_class
259
+ @root_class ||= root ? root.class : nil
260
+ end
261
+
262
+ # Set the collection to the collection of the root document.
263
+ #
264
+ # @example Set the collection.
265
+ # context.set_collection
266
+ #
267
+ # @return [ Collection ] The root collection.
268
+ def set_collection
269
+ @collection = root.collection if root && !root.embedded?
270
+ end
271
+
272
+ # Sorts the result set if sort options have been set.
273
+ #
274
+ # @example Sort the documents.
275
+ # context.sort(documents)
276
+ #
277
+ # @return [ Array<Document> ] The sorted documents.
278
+ def sort(documents)
279
+ return documents if options[:sort].blank?
280
+ documents.sort_by do |document|
281
+ options[:sort].map do |key, direction|
282
+ Sort.new(document.read_attribute(key), direction)
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end