mongoid-braxton 2.0.2

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 (226) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +50 -0
  3. data/Rakefile +51 -0
  4. data/lib/config/locales/bg.yml +41 -0
  5. data/lib/config/locales/de.yml +41 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +41 -0
  8. data/lib/config/locales/fr.yml +42 -0
  9. data/lib/config/locales/hu.yml +44 -0
  10. data/lib/config/locales/id.yml +46 -0
  11. data/lib/config/locales/it.yml +39 -0
  12. data/lib/config/locales/ja.yml +40 -0
  13. data/lib/config/locales/kr.yml +65 -0
  14. data/lib/config/locales/nl.yml +39 -0
  15. data/lib/config/locales/pl.yml +39 -0
  16. data/lib/config/locales/pt-BR.yml +40 -0
  17. data/lib/config/locales/pt.yml +40 -0
  18. data/lib/config/locales/ro.yml +46 -0
  19. data/lib/config/locales/ru.yml +41 -0
  20. data/lib/config/locales/sv.yml +40 -0
  21. data/lib/config/locales/vi.yml +45 -0
  22. data/lib/config/locales/zh-CN.yml +33 -0
  23. data/lib/mongoid.rb +140 -0
  24. data/lib/mongoid/atomicity.rb +111 -0
  25. data/lib/mongoid/attributes.rb +185 -0
  26. data/lib/mongoid/attributes/processing.rb +145 -0
  27. data/lib/mongoid/callbacks.rb +23 -0
  28. data/lib/mongoid/collection.rb +137 -0
  29. data/lib/mongoid/collections.rb +71 -0
  30. data/lib/mongoid/collections/master.rb +37 -0
  31. data/lib/mongoid/collections/operations.rb +42 -0
  32. data/lib/mongoid/collections/retry.rb +39 -0
  33. data/lib/mongoid/components.rb +45 -0
  34. data/lib/mongoid/config.rb +349 -0
  35. data/lib/mongoid/config/database.rb +167 -0
  36. data/lib/mongoid/config/replset_database.rb +78 -0
  37. data/lib/mongoid/contexts.rb +19 -0
  38. data/lib/mongoid/contexts/enumerable.rb +275 -0
  39. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  40. data/lib/mongoid/contexts/mongo.rb +345 -0
  41. data/lib/mongoid/copyable.rb +46 -0
  42. data/lib/mongoid/criteria.rb +357 -0
  43. data/lib/mongoid/criterion/builder.rb +34 -0
  44. data/lib/mongoid/criterion/complex.rb +34 -0
  45. data/lib/mongoid/criterion/creational.rb +34 -0
  46. data/lib/mongoid/criterion/exclusion.rb +108 -0
  47. data/lib/mongoid/criterion/inclusion.rb +198 -0
  48. data/lib/mongoid/criterion/inspection.rb +22 -0
  49. data/lib/mongoid/criterion/optional.rb +193 -0
  50. data/lib/mongoid/criterion/selector.rb +143 -0
  51. data/lib/mongoid/criterion/unconvertable.rb +20 -0
  52. data/lib/mongoid/cursor.rb +86 -0
  53. data/lib/mongoid/default_scope.rb +36 -0
  54. data/lib/mongoid/dirty.rb +253 -0
  55. data/lib/mongoid/document.rb +284 -0
  56. data/lib/mongoid/errors.rb +13 -0
  57. data/lib/mongoid/errors/document_not_found.rb +29 -0
  58. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  59. data/lib/mongoid/errors/invalid_database.rb +20 -0
  60. data/lib/mongoid/errors/invalid_field.rb +19 -0
  61. data/lib/mongoid/errors/invalid_options.rb +16 -0
  62. data/lib/mongoid/errors/invalid_type.rb +26 -0
  63. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  64. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  65. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  66. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  67. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  68. data/lib/mongoid/errors/validations.rb +24 -0
  69. data/lib/mongoid/extensions.rb +123 -0
  70. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  71. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  72. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  74. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  75. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  76. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  77. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  78. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  79. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  80. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  81. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  84. data/lib/mongoid/extensions/object/checks.rb +32 -0
  85. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  86. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  87. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  88. data/lib/mongoid/extensions/object_id/conversions.rb +96 -0
  89. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  90. data/lib/mongoid/extensions/range/conversions.rb +25 -0
  91. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  92. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  93. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  94. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  95. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  96. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  97. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  98. data/lib/mongoid/extras.rb +42 -0
  99. data/lib/mongoid/factory.rb +37 -0
  100. data/lib/mongoid/field.rb +162 -0
  101. data/lib/mongoid/fields.rb +183 -0
  102. data/lib/mongoid/finders.rb +127 -0
  103. data/lib/mongoid/hierarchy.rb +85 -0
  104. data/lib/mongoid/identity.rb +92 -0
  105. data/lib/mongoid/indexes.rb +38 -0
  106. data/lib/mongoid/inspection.rb +54 -0
  107. data/lib/mongoid/javascript.rb +21 -0
  108. data/lib/mongoid/javascript/functions.yml +37 -0
  109. data/lib/mongoid/json.rb +16 -0
  110. data/lib/mongoid/keys.rb +131 -0
  111. data/lib/mongoid/logger.rb +18 -0
  112. data/lib/mongoid/matchers.rb +32 -0
  113. data/lib/mongoid/matchers/all.rb +11 -0
  114. data/lib/mongoid/matchers/default.rb +70 -0
  115. data/lib/mongoid/matchers/exists.rb +13 -0
  116. data/lib/mongoid/matchers/gt.rb +11 -0
  117. data/lib/mongoid/matchers/gte.rb +11 -0
  118. data/lib/mongoid/matchers/in.rb +11 -0
  119. data/lib/mongoid/matchers/lt.rb +11 -0
  120. data/lib/mongoid/matchers/lte.rb +11 -0
  121. data/lib/mongoid/matchers/ne.rb +11 -0
  122. data/lib/mongoid/matchers/nin.rb +11 -0
  123. data/lib/mongoid/matchers/or.rb +30 -0
  124. data/lib/mongoid/matchers/size.rb +11 -0
  125. data/lib/mongoid/matchers/strategies.rb +63 -0
  126. data/lib/mongoid/multi_database.rb +11 -0
  127. data/lib/mongoid/multi_parameter_attributes.rb +82 -0
  128. data/lib/mongoid/named_scope.rb +137 -0
  129. data/lib/mongoid/nested_attributes.rb +51 -0
  130. data/lib/mongoid/observer.rb +67 -0
  131. data/lib/mongoid/paranoia.rb +103 -0
  132. data/lib/mongoid/paths.rb +61 -0
  133. data/lib/mongoid/persistence.rb +240 -0
  134. data/lib/mongoid/persistence/atomic.rb +88 -0
  135. data/lib/mongoid/persistence/atomic/add_to_set.rb +32 -0
  136. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  137. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  139. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  140. data/lib/mongoid/persistence/command.rb +71 -0
  141. data/lib/mongoid/persistence/insert.rb +53 -0
  142. data/lib/mongoid/persistence/insert_embedded.rb +43 -0
  143. data/lib/mongoid/persistence/remove.rb +44 -0
  144. data/lib/mongoid/persistence/remove_all.rb +40 -0
  145. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  146. data/lib/mongoid/persistence/update.rb +77 -0
  147. data/lib/mongoid/railtie.rb +139 -0
  148. data/lib/mongoid/railties/database.rake +171 -0
  149. data/lib/mongoid/railties/document.rb +12 -0
  150. data/lib/mongoid/relations.rb +107 -0
  151. data/lib/mongoid/relations/accessors.rb +175 -0
  152. data/lib/mongoid/relations/auto_save.rb +34 -0
  153. data/lib/mongoid/relations/binding.rb +26 -0
  154. data/lib/mongoid/relations/bindings.rb +9 -0
  155. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  156. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  157. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  158. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  159. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  160. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +103 -0
  161. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  162. data/lib/mongoid/relations/builder.rb +42 -0
  163. data/lib/mongoid/relations/builders.rb +79 -0
  164. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  165. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  166. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  167. data/lib/mongoid/relations/builders/nested_attributes/many.rb +126 -0
  168. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  169. data/lib/mongoid/relations/builders/referenced/in.rb +29 -0
  170. data/lib/mongoid/relations/builders/referenced/many.rb +47 -0
  171. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  172. data/lib/mongoid/relations/builders/referenced/one.rb +27 -0
  173. data/lib/mongoid/relations/cascading.rb +55 -0
  174. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  175. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  176. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  177. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  178. data/lib/mongoid/relations/constraint.rb +42 -0
  179. data/lib/mongoid/relations/cyclic.rb +103 -0
  180. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  181. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  182. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  183. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  184. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  185. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  186. data/lib/mongoid/relations/embedded/in.rb +173 -0
  187. data/lib/mongoid/relations/embedded/many.rb +499 -0
  188. data/lib/mongoid/relations/embedded/one.rb +170 -0
  189. data/lib/mongoid/relations/macros.rb +310 -0
  190. data/lib/mongoid/relations/many.rb +215 -0
  191. data/lib/mongoid/relations/metadata.rb +539 -0
  192. data/lib/mongoid/relations/nested_builder.rb +68 -0
  193. data/lib/mongoid/relations/one.rb +47 -0
  194. data/lib/mongoid/relations/polymorphic.rb +54 -0
  195. data/lib/mongoid/relations/proxy.rb +143 -0
  196. data/lib/mongoid/relations/referenced/batch.rb +71 -0
  197. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  198. data/lib/mongoid/relations/referenced/in.rb +216 -0
  199. data/lib/mongoid/relations/referenced/many.rb +516 -0
  200. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  201. data/lib/mongoid/relations/referenced/one.rb +222 -0
  202. data/lib/mongoid/relations/reflections.rb +45 -0
  203. data/lib/mongoid/safe.rb +23 -0
  204. data/lib/mongoid/safety.rb +207 -0
  205. data/lib/mongoid/scope.rb +31 -0
  206. data/lib/mongoid/serialization.rb +99 -0
  207. data/lib/mongoid/sharding.rb +51 -0
  208. data/lib/mongoid/state.rb +67 -0
  209. data/lib/mongoid/timestamps.rb +14 -0
  210. data/lib/mongoid/timestamps/created.rb +31 -0
  211. data/lib/mongoid/timestamps/updated.rb +33 -0
  212. data/lib/mongoid/validations.rb +124 -0
  213. data/lib/mongoid/validations/associated.rb +44 -0
  214. data/lib/mongoid/validations/referenced.rb +58 -0
  215. data/lib/mongoid/validations/uniqueness.rb +85 -0
  216. data/lib/mongoid/version.rb +4 -0
  217. data/lib/mongoid/versioning.rb +113 -0
  218. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  219. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  220. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  221. data/lib/rails/generators/mongoid/model/templates/model.rb +19 -0
  222. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  223. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  224. data/lib/rails/generators/mongoid_generator.rb +70 -0
  225. data/lib/rails/mongoid.rb +58 -0
  226. metadata +406 -0
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+
5
+ # This module defines criteria behavior for creating documents in the
6
+ # database for specified conditions.
7
+ module Creational
8
+
9
+ # Create a document in the database given the selector and return it.
10
+ # Complex criteria, such as $in and $or operations will get ignored.
11
+ #
12
+ # @example Create the document.
13
+ # Person.where(:title => "Sir").create
14
+ #
15
+ # @example Create with selectors getting ignored.
16
+ # Person.where(:age.gt => 5).create
17
+ #
18
+ # @return [ Document ] A newly created document.
19
+ #
20
+ # @since 2.0.0.rc.1
21
+ def create(attrs = {})
22
+ klass.create(
23
+ selector.inject(attrs) do |hash, (key, value)|
24
+ hash.tap do |attrs|
25
+ unless key.to_s =~ /\$/ || value.is_a?(Hash)
26
+ attrs[key] = value
27
+ end
28
+ end
29
+ end
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,108 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+
5
+ # This module contains criteria behaviour for exclusion of values.
6
+ module Exclusion
7
+
8
+ # Adds a criterion to the +Criteria+ that specifies values that are not
9
+ # allowed to match any document in the database. The MongoDB
10
+ # conditional operator that will be used is "$ne".
11
+ #
12
+ # @example Match documents without these values.
13
+ # criteria.excludes(:field => "value1")
14
+ # criteria.excludes(:field1 => "value1", :field2 => "value1")
15
+ #
16
+ # @param [ Hash ] attributes: A +Hash+ where the key is the field
17
+ # name and the value is a value that must not be equal to the
18
+ # corresponding field value in the database.
19
+ #
20
+ # @return [ Criteria ] A newly cloned copy.
21
+ def excludes(attributes = {})
22
+ mongo_id = attributes.delete(:id)
23
+ attributes = attributes.merge(:_id => mongo_id) if mongo_id
24
+ update_selector(attributes, "$ne")
25
+ end
26
+
27
+ # Used when wanting to set the fields options directly using a hash
28
+ # instead of going through only or without.
29
+ #
30
+ # @example Set the limited fields.
31
+ # criteria.fields(:field => 1)
32
+ #
33
+ # @param [ Hash ] attributes The field options.
34
+ #
35
+ # @return [ Criteria ] A newly cloned copy.
36
+ #
37
+ # @since 2.0.2
38
+ def fields(attributes = nil)
39
+ clone.tap { |crit| crit.options[:fields] = attributes || {} }
40
+ end
41
+
42
+ # Adds a criterion to the +Criteria+ that specifies values where none
43
+ # should match in order to return results. This is similar to an SQL
44
+ # "NOT IN" clause. The MongoDB conditional operator that will be
45
+ # used is "$nin".
46
+ #
47
+ # @example Match documents with values not in the provided.
48
+ # criteria.not_in(:field => ["value1", "value2"])
49
+ # criteria.not_in(:field1 => ["value1", "value2"], :field2 => ["value1"])
50
+ #
51
+ # @param [ Hash ] attributes A +Hash+ where the key is the field name
52
+ # and the value is an +Array+ of values that none can match.
53
+ #
54
+ # @return [ Criteria ] A newly cloned copy.
55
+ def not_in(attributes)
56
+ update_selector(attributes, "$nin")
57
+ end
58
+
59
+ # Adds a criterion to the +Criteria+ that specifies the fields that will
60
+ # get returned from the Document. Used mainly for list views that do not
61
+ # require all fields to be present. This is similar to SQL "SELECT" values.
62
+ #
63
+ # @example Limit the fields to only the specified.
64
+ # criteria.only(:field1, :field2, :field3)
65
+ #
66
+ # @note #only and #without cannot be used together.
67
+ #
68
+ # @param [ Array<Symbol> ] args A list of field names to limit to.
69
+ #
70
+ # @return [ Criteria ] A newly cloned copy.
71
+ def only(*args)
72
+ clone.tap do |crit|
73
+ if args.any?
74
+ crit.options[:fields] = {:_type => 1}
75
+ crit.field_list = args.flatten
76
+ crit.field_list.each do |f|
77
+ crit.options[:fields][f] = 1
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ # Adds a criterion to the +Criteria+ that specifies the fields that will
84
+ # not get returned by the document.
85
+ #
86
+ # @example Filter out specific fields.
87
+ # criteria.without(:field2, :field2)
88
+ #
89
+ # @note #only and #without cannot be used together.
90
+ #
91
+ # @param [ Array<Symbol> args A list of fields to exclude.
92
+ #
93
+ # @return [ Criteria ] A newly cloned copy.
94
+ #
95
+ # @since 2.0.0
96
+ def without(*args)
97
+ clone.tap do |crit|
98
+ if args.any?
99
+ crit.options[:fields] = {}
100
+ args.flatten.each do |f|
101
+ crit.options[:fields][f] = 0
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Inclusion
5
+
6
+ # Adds a criterion to the +Criteria+ that specifies values that must all
7
+ # be matched in order to return results. Similar to an "in" clause but the
8
+ # underlying conditional logic is an "AND" and not an "OR". The MongoDB
9
+ # conditional operator that will be used is "$all".
10
+ #
11
+ # @example Adding the criterion.
12
+ # criteria.all(:field => ["value1", "value2"])
13
+ # criteria.all(:field1 => ["value1", "value2"], :field2 => ["value1"])
14
+ #
15
+ # @param [ Hash ] attributes Name/value pairs that all must match.
16
+ #
17
+ # @return [ Criteria ] A new criteria with the added selector.
18
+ def all(attributes = {})
19
+ update_selector(attributes, "$all")
20
+ end
21
+ alias :all_in :all
22
+
23
+ # Adds a criterion to the +Criteria+ that specifies values where any can
24
+ # be matched in order to return results. This is similar to an SQL "IN"
25
+ # clause. The MongoDB conditional operator that will be used is "$in".
26
+ # Any previously matching "$in" arrays will be unioned with new
27
+ # arguments.
28
+ #
29
+ # @example Adding the criterion.
30
+ # criteria.in(:field => ["value1"]).also_in(:field => ["value2"])
31
+ #
32
+ # @param [ Hash ] attributes Name/value pairs any can match.
33
+ #
34
+ # @return [ Criteria ] A new criteria with the added selector.
35
+ def also_in(attributes = {})
36
+ update_selector(attributes, "$in")
37
+ end
38
+
39
+ # Adds a criterion to the +Criteria+ that specifies values that must
40
+ # be matched in order to return results. This is similar to a SQL "WHERE"
41
+ # clause. This is the actual selector that will be provided to MongoDB,
42
+ # similar to the Javascript object that is used when performing a find()
43
+ # in the MongoDB console.
44
+ #
45
+ # @example Adding the criterion.
46
+ # criteria.and(:field1 => "value1", :field2 => 15)
47
+ #
48
+ # @param [ Hash ] selectior Name/value pairs that all must match.
49
+ #
50
+ # @return [ Criteria ] A new criteria with the added selector.
51
+ def and(selector = nil)
52
+ where(selector)
53
+ end
54
+
55
+ # Adds a criterion to the +Criteria+ that specifies a set of expressions
56
+ # to match if any of them return true. This is a $or query in MongoDB and
57
+ # is similar to a SQL OR. This is named #any_of and aliased "or" for
58
+ # readability.
59
+ #
60
+ # @example Adding the criterion.
61
+ # criteria.any_of({ :field1 => "value" }, { :field2 => "value2" })
62
+ #
63
+ # @param [ Array<Hash> ] args A list of name/value pairs any can match.
64
+ #
65
+ # @return [ Criteria ] A new criteria with the added selector.
66
+ def any_of(*args)
67
+ clone.tap do |crit|
68
+ criterion = @selector["$or"] || []
69
+ converted = BSON::ObjectId.convert(klass, args.flatten)
70
+ expanded = converted.collect(&:expand_complex_criteria)
71
+ crit.selector["$or"] = criterion.concat(expanded)
72
+ end
73
+ end
74
+ alias :or :any_of
75
+
76
+ # Find the matchind document in the criteria, either based on id or
77
+ # conditions.
78
+ #
79
+ # @todo Durran: DRY up duplicated code in a few places.
80
+ #
81
+ # @example Find by an id.
82
+ # criteria.find(BSON::ObjectId.new)
83
+ #
84
+ # @example Find by multiple ids.
85
+ # criteria.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
86
+ #
87
+ # @example Conditionally find all matching documents.
88
+ # criteria.find(:all, :conditions => { :title => "Sir" })
89
+ #
90
+ # @example Conditionally find the first document.
91
+ # criteria.find(:first, :conditions => { :title => "Sir" })
92
+ #
93
+ # @example Conditionally find the last document.
94
+ # criteria.find(:last, :conditions => { :title => "Sir" })
95
+ #
96
+ # @param [ Symbol, BSON::ObjectId, Array<BSON::ObjectId> ] arg The
97
+ # argument to search with.
98
+ # @param [ Hash ] options The options to search with.
99
+ #
100
+ # @return [ Document, Criteria ] The matching document(s).
101
+ def find(*args)
102
+ type, crit = search(*args)
103
+ case type
104
+ when :first then crit.one
105
+ when :last then crit.last
106
+ when :ids then execute_or_raise(args, crit)
107
+ else
108
+ crit
109
+ end
110
+ end
111
+
112
+ # Adds a criterion to the +Criteria+ that specifies values where any can
113
+ # be matched in order to return results. This is similar to an SQL "IN"
114
+ # clause. The MongoDB conditional operator that will be used is "$in".
115
+ #
116
+ # @example Adding the criterion.
117
+ # criteria.in(:field => ["value1", "value2"])
118
+ # criteria.in(:field1 => ["value1", "value2"], :field2 => ["value1"])
119
+ #
120
+ # @param [ Hash ] attributes Name/value pairs any can match.
121
+ #
122
+ # @return [ Criteria ] A new criteria with the added selector.
123
+ def in(attributes = {})
124
+ update_selector(attributes, "$in", :&)
125
+ end
126
+ alias :any_in :in
127
+
128
+ # Adds a criterion to the +Criteria+ that specifies values to do
129
+ # geospacial searches by. The field must be indexed with the "2d" option.
130
+ #
131
+ # @example Adding the criterion.
132
+ # criteria.near(:field1 => [30, -44])
133
+ #
134
+ # @param [ Hash ] attributes The fields with lat/long values.
135
+ #
136
+ # @return [ Criteria ] A new criteria with the added selector.
137
+ def near(attributes = {})
138
+ update_selector(attributes, "$near")
139
+ end
140
+
141
+ # Adds a criterion to the +Criteria+ that specifies values that must
142
+ # be matched in order to return results. This is similar to a SQL "WHERE"
143
+ # clause. This is the actual selector that will be provided to MongoDB,
144
+ # similar to the Javascript object that is used when performing a find()
145
+ # in the MongoDB console.
146
+ #
147
+ # @example Adding the criterion.
148
+ # criteria.where(:field1 => "value1", :field2 => 15)
149
+ #
150
+ # @param [ Hash ] selector Name/value pairs where all must match.
151
+ #
152
+ # @return [ Criteria ] A new criteria with the added selector.
153
+ def where(selector = nil)
154
+ clone.tap do |crit|
155
+ selector = case selector
156
+ when String then {"$where" => selector}
157
+ else
158
+ BSON::ObjectId.convert(klass, selector || {}, false).expand_complex_criteria
159
+ end
160
+
161
+ selector.each_pair do |key, value|
162
+ if crit.selector.has_key?(key) && crit.selector[key].respond_to?(:merge!)
163
+ crit.selector[key] =
164
+ crit.selector[key].merge!(value) do |key, old, new|
165
+ key == '$in' ? old & new : new
166
+ end
167
+ else
168
+ crit.selector[key] = value
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ # Execute the criteria or raise an error if no documents found.
177
+ #
178
+ # @example Execute or raise
179
+ # criteria.execute_or_raise(id, criteria)
180
+ #
181
+ # @param [ Object ] args The arguments passed.
182
+ # @param [ Criteria ] criteria The criteria to execute.
183
+ #
184
+ # @raise [ Errors::DocumentNotFound ] If nothing returned.
185
+ #
186
+ # @return [ Document, Array<Document> ] The document(s).
187
+ #
188
+ # @since 2.0.0
189
+ def execute_or_raise(args, criteria)
190
+ (args[0].is_a?(Array) ? criteria.entries : criteria.one).tap do |result|
191
+ if Mongoid.raise_not_found_error && !args.flatten.blank?
192
+ raise Errors::DocumentNotFound.new(klass, args) if result._vacant?
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Inspection #:nodoc:
5
+
6
+ # Get a pretty string representation of the criteria, including the
7
+ # selector, options, matching count and documents for inspection.
8
+ #
9
+ # @example Inspect the criteria.
10
+ # criteria.inspect
11
+ #
12
+ # @return [ String ] The inspection string.
13
+ def inspect
14
+ "#<Mongoid::Criteria\n" <<
15
+ " selector: #{selector.inspect},\n" <<
16
+ " options: #{options.inspect},\n" <<
17
+ " class: #{klass},\n" <<
18
+ " embedded: #{embedded}>\n"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,193 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Optional
5
+
6
+ # Adds fields to be sorted in ascending order. Will add them in the order
7
+ # they were passed into the method.
8
+ #
9
+ # Example:
10
+ #
11
+ # <tt>criteria.ascending(:title, :dob)</tt>
12
+ def ascending(*fields)
13
+ clone.tap do |crit|
14
+ crit.options[:sort] = [] unless options[:sort] || fields.first.nil?
15
+ fields.flatten.each { |field| crit.options[:sort] << [ field, :asc ] }
16
+ end
17
+ end
18
+ alias :asc :ascending
19
+
20
+ # Tells the criteria that the cursor that gets returned needs to be
21
+ # cached. This is so multiple iterations don't hit the database multiple
22
+ # times, however this is not advisable when working with large data sets
23
+ # as the entire results will get stored in memory.
24
+ #
25
+ # Example:
26
+ #
27
+ # <tt>criteria.cache</tt>
28
+ def cache
29
+ clone.tap { |crit| crit.options.merge!(:cache => true) }
30
+ end
31
+
32
+ # Will return true if the cache option has been set.
33
+ #
34
+ # Example:
35
+ #
36
+ # <tt>criteria.cached?</tt>
37
+ def cached?
38
+ options[:cache] == true
39
+ end
40
+
41
+ # Adds fields to be sorted in descending order. Will add them in the order
42
+ # they were passed into the method.
43
+ #
44
+ # Example:
45
+ #
46
+ # <tt>criteria.descending(:title, :dob)</tt>
47
+ def descending(*fields)
48
+ clone.tap do |crit|
49
+ crit.options[:sort] = [] unless options[:sort] || fields.first.nil?
50
+ fields.flatten.each { |field| crit.options[:sort] << [ field, :desc ] }
51
+ end
52
+ end
53
+ alias :desc :descending
54
+
55
+ # Adds a criterion to the +Criteria+ that specifies additional options
56
+ # to be passed to the Ruby driver, in the exact format for the driver.
57
+ #
58
+ # Options:
59
+ #
60
+ # extras: A +Hash+ that gets set to the driver options.
61
+ #
62
+ # Example:
63
+ #
64
+ # <tt>criteria.extras(:limit => 20, :skip => 40)</tt>
65
+ #
66
+ # Returns: <tt>self</tt>
67
+ def extras(extras)
68
+ clone.tap do |crit|
69
+ crit.options.merge!(extras)
70
+ end
71
+ end
72
+
73
+ # Adds a criterion to the +Criteria+ that specifies an id that must be matched.
74
+ #
75
+ # Options:
76
+ #
77
+ # object_id: A single id or an array of ids in +String+ or <tt>BSON::ObjectId</tt> format
78
+ #
79
+ # Example:
80
+ #
81
+ # <tt>criteria.for_ids("4ab2bc4b8ad548971900005c")</tt>
82
+ # <tt>criteria.for_ids(["4ab2bc4b8ad548971900005c", "4c454e7ebf4b98032d000001"])</tt>
83
+ #
84
+ # Returns: <tt>self</tt>
85
+ def for_ids(*ids)
86
+ ids.flatten!
87
+ if ids.size > 1
88
+ any_in(
89
+ :_id => ::BSON::ObjectId.convert(klass, ids)
90
+ )
91
+ else
92
+ clone.tap do |crit|
93
+ crit.selector[:_id] =
94
+ ::BSON::ObjectId.convert(klass, ids.first)
95
+ end
96
+ end
97
+ end
98
+
99
+ # Adds a criterion to the +Criteria+ that specifies the maximum number of
100
+ # results to return. This is mostly used in conjunction with <tt>skip()</tt>
101
+ # to handle paginated results.
102
+ #
103
+ # Options:
104
+ #
105
+ # value: An +Integer+ specifying the max number of results. Defaults to 20.
106
+ #
107
+ # Example:
108
+ #
109
+ # <tt>criteria.limit(100)</tt>
110
+ #
111
+ # Returns: <tt>self</tt>
112
+ def limit(value = 20)
113
+ clone.tap { |crit| crit.options[:limit] = value }
114
+ end
115
+
116
+ # Returns the offset option. If a per_page option is in the list then it
117
+ # will replace it with a skip parameter and return the same value. Defaults
118
+ # to 20 if nothing was provided.
119
+ def offset(*args)
120
+ args.size > 0 ? skip(args.first) : options[:skip]
121
+ end
122
+
123
+ # Adds a criterion to the +Criteria+ that specifies the sort order of
124
+ # the returned documents in the database. Similar to a SQL "ORDER BY".
125
+ #
126
+ # Options:
127
+ #
128
+ # params: An +Array+ of [field, direction] sorting pairs.
129
+ #
130
+ # Example:
131
+ #
132
+ # <tt>criteria.order_by([[:field1, :asc], [:field2, :desc]])</tt>
133
+ #
134
+ # Returns: <tt>self</tt>
135
+ def order_by(*args)
136
+ clone.tap do |crit|
137
+ crit.options[:sort] = [] unless options[:sort] || args.first.nil?
138
+ arguments = args.first
139
+ case arguments
140
+ when Hash
141
+ arguments.each do |field, direction|
142
+ crit.options[:sort] << [ field, direction ]
143
+ end
144
+ when Array
145
+ crit.options[:sort].concat(arguments)
146
+ when Complex
147
+ args.flatten.each do |complex|
148
+ crit.options[:sort] << [ complex.key, complex.operator.to_sym ]
149
+ end
150
+ end
151
+ end
152
+ end
153
+ alias :order :order_by
154
+
155
+ # Adds a criterion to the +Criteria+ that specifies how many results to skip
156
+ # when returning Documents. This is mostly used in conjunction with
157
+ # <tt>limit()</tt> to handle paginated results, and is similar to the
158
+ # traditional "offset" parameter.
159
+ #
160
+ # Options:
161
+ #
162
+ # value: An +Integer+ specifying the number of results to skip. Defaults to 0.
163
+ #
164
+ # Example:
165
+ #
166
+ # <tt>criteria.skip(20)</tt>
167
+ #
168
+ # Returns: <tt>self</tt>
169
+ def skip(value = 0)
170
+ clone.tap { |crit| crit.options[:skip] = value }
171
+ end
172
+
173
+ # Adds a criterion to the +Criteria+ that specifies a type or an Array of
174
+ # type that must be matched.
175
+ #
176
+ # Options:
177
+ #
178
+ # types : An +Array+ of types of a +String+ representing the Type of you search
179
+ #
180
+ # Example:
181
+ #
182
+ # <tt>criteria.type('Browser')</tt>
183
+ # <tt>criteria.type(['Firefox', 'Browser'])</tt>
184
+ #
185
+ # Returns: <tt>self</tt>
186
+ def type(types)
187
+ types = [types] unless types.is_a?(Array)
188
+ any_in(:_type => types)
189
+ end
190
+
191
+ end
192
+ end
193
+ end