mongoid-locomotive 2.0.0.beta9

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 (274) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.rdoc +47 -0
  3. data/lib/mongoid.rb +141 -0
  4. data/lib/mongoid/associations.rb +306 -0
  5. data/lib/mongoid/associations/embedded_in.rb +74 -0
  6. data/lib/mongoid/associations/embeds_many.rb +280 -0
  7. data/lib/mongoid/associations/embeds_one.rb +97 -0
  8. data/lib/mongoid/associations/foreign_key.rb +35 -0
  9. data/lib/mongoid/associations/meta_data.rb +38 -0
  10. data/lib/mongoid/associations/options.rb +62 -0
  11. data/lib/mongoid/associations/proxy.rb +33 -0
  12. data/lib/mongoid/associations/referenced_in.rb +59 -0
  13. data/lib/mongoid/associations/references_many.rb +245 -0
  14. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  15. data/lib/mongoid/associations/references_one.rb +99 -0
  16. data/lib/mongoid/atomicity.rb +55 -0
  17. data/lib/mongoid/attributes.rb +242 -0
  18. data/lib/mongoid/callbacks.rb +21 -0
  19. data/lib/mongoid/collection.rb +120 -0
  20. data/lib/mongoid/collections.rb +71 -0
  21. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  22. data/lib/mongoid/collections/master.rb +29 -0
  23. data/lib/mongoid/collections/operations.rb +41 -0
  24. data/lib/mongoid/collections/slaves.rb +45 -0
  25. data/lib/mongoid/components.rb +34 -0
  26. data/lib/mongoid/config.rb +263 -0
  27. data/lib/mongoid/contexts.rb +24 -0
  28. data/lib/mongoid/contexts/enumerable.rb +156 -0
  29. data/lib/mongoid/contexts/ids.rb +25 -0
  30. data/lib/mongoid/contexts/mongo.rb +285 -0
  31. data/lib/mongoid/contexts/paging.rb +50 -0
  32. data/lib/mongoid/criteria.rb +248 -0
  33. data/lib/mongoid/criterion/complex.rb +21 -0
  34. data/lib/mongoid/criterion/exclusion.rb +65 -0
  35. data/lib/mongoid/criterion/inclusion.rb +110 -0
  36. data/lib/mongoid/criterion/optional.rb +189 -0
  37. data/lib/mongoid/cursor.rb +81 -0
  38. data/lib/mongoid/deprecation.rb +21 -0
  39. data/lib/mongoid/dirty.rb +252 -0
  40. data/lib/mongoid/document.rb +210 -0
  41. data/lib/mongoid/errors.rb +131 -0
  42. data/lib/mongoid/extensions.rb +115 -0
  43. data/lib/mongoid/extensions/array/accessors.rb +17 -0
  44. data/lib/mongoid/extensions/array/assimilation.rb +26 -0
  45. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  46. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  47. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  48. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  49. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  50. data/lib/mongoid/extensions/date/conversions.rb +24 -0
  51. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  52. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  53. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  54. data/lib/mongoid/extensions/hash/accessors.rb +42 -0
  55. data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
  56. data/lib/mongoid/extensions/hash/conversions.rb +42 -0
  57. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  58. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  59. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  60. data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
  61. data/lib/mongoid/extensions/object/conversions.rb +21 -0
  62. data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
  63. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  64. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  65. data/lib/mongoid/extensions/string/conversions.rb +15 -0
  66. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  67. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  68. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  69. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  70. data/lib/mongoid/extras.rb +61 -0
  71. data/lib/mongoid/factory.rb +20 -0
  72. data/lib/mongoid/field.rb +83 -0
  73. data/lib/mongoid/fields.rb +62 -0
  74. data/lib/mongoid/finders.rb +145 -0
  75. data/lib/mongoid/hierarchy.rb +74 -0
  76. data/lib/mongoid/identity.rb +47 -0
  77. data/lib/mongoid/indexes.rb +27 -0
  78. data/lib/mongoid/javascript.rb +21 -0
  79. data/lib/mongoid/javascript/functions.yml +37 -0
  80. data/lib/mongoid/logger.rb +19 -0
  81. data/lib/mongoid/matchers.rb +35 -0
  82. data/lib/mongoid/matchers/all.rb +11 -0
  83. data/lib/mongoid/matchers/default.rb +26 -0
  84. data/lib/mongoid/matchers/exists.rb +13 -0
  85. data/lib/mongoid/matchers/gt.rb +11 -0
  86. data/lib/mongoid/matchers/gte.rb +11 -0
  87. data/lib/mongoid/matchers/in.rb +11 -0
  88. data/lib/mongoid/matchers/lt.rb +11 -0
  89. data/lib/mongoid/matchers/lte.rb +11 -0
  90. data/lib/mongoid/matchers/ne.rb +11 -0
  91. data/lib/mongoid/matchers/nin.rb +11 -0
  92. data/lib/mongoid/matchers/size.rb +11 -0
  93. data/lib/mongoid/memoization.rb +33 -0
  94. data/lib/mongoid/named_scope.rb +37 -0
  95. data/lib/mongoid/paranoia.rb +106 -0
  96. data/lib/mongoid/paths.rb +61 -0
  97. data/lib/mongoid/persistence.rb +216 -0
  98. data/lib/mongoid/persistence/command.rb +39 -0
  99. data/lib/mongoid/persistence/insert.rb +48 -0
  100. data/lib/mongoid/persistence/insert_embedded.rb +44 -0
  101. data/lib/mongoid/persistence/remove.rb +39 -0
  102. data/lib/mongoid/persistence/remove_all.rb +38 -0
  103. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  104. data/lib/mongoid/persistence/update.rb +71 -0
  105. data/lib/mongoid/railtie.rb +67 -0
  106. data/lib/mongoid/railties/database.rake +60 -0
  107. data/lib/mongoid/scope.rb +75 -0
  108. data/lib/mongoid/state.rb +32 -0
  109. data/lib/mongoid/timestamps.rb +27 -0
  110. data/lib/mongoid/validations.rb +51 -0
  111. data/lib/mongoid/validations/associated.rb +32 -0
  112. data/lib/mongoid/validations/locale/en.yml +5 -0
  113. data/lib/mongoid/validations/uniqueness.rb +56 -0
  114. data/lib/mongoid/version.rb +4 -0
  115. data/lib/mongoid/versioning.rb +26 -0
  116. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  117. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  118. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  119. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  120. data/lib/rails/generators/mongoid_generator.rb +61 -0
  121. data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
  122. data/spec/integration/mongoid/associations_spec.rb +768 -0
  123. data/spec/integration/mongoid/attributes_spec.rb +59 -0
  124. data/spec/integration/mongoid/callback_spec.rb +33 -0
  125. data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
  126. data/spec/integration/mongoid/criteria_spec.rb +281 -0
  127. data/spec/integration/mongoid/dirty_spec.rb +85 -0
  128. data/spec/integration/mongoid/document_spec.rb +741 -0
  129. data/spec/integration/mongoid/extensions_spec.rb +22 -0
  130. data/spec/integration/mongoid/finders_spec.rb +119 -0
  131. data/spec/integration/mongoid/inheritance_spec.rb +171 -0
  132. data/spec/integration/mongoid/named_scope_spec.rb +58 -0
  133. data/spec/integration/mongoid/paranoia_spec.rb +44 -0
  134. data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
  135. data/spec/integration/mongoid/persistence_spec.rb +311 -0
  136. data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
  137. data/spec/models/account.rb +5 -0
  138. data/spec/models/address.rb +40 -0
  139. data/spec/models/agent.rb +7 -0
  140. data/spec/models/animal.rb +15 -0
  141. data/spec/models/answer.rb +4 -0
  142. data/spec/models/callbacks.rb +47 -0
  143. data/spec/models/category.rb +13 -0
  144. data/spec/models/comment.rb +10 -0
  145. data/spec/models/country_code.rb +6 -0
  146. data/spec/models/employer.rb +5 -0
  147. data/spec/models/favorite.rb +8 -0
  148. data/spec/models/game.rb +9 -0
  149. data/spec/models/inheritance.rb +72 -0
  150. data/spec/models/location.rb +5 -0
  151. data/spec/models/login.rb +6 -0
  152. data/spec/models/mixed_drink.rb +4 -0
  153. data/spec/models/name.rb +13 -0
  154. data/spec/models/namespacing.rb +11 -0
  155. data/spec/models/paranoid_post.rb +18 -0
  156. data/spec/models/parents.rb +32 -0
  157. data/spec/models/patient.rb +15 -0
  158. data/spec/models/person.rb +106 -0
  159. data/spec/models/pet.rb +7 -0
  160. data/spec/models/pet_owner.rb +6 -0
  161. data/spec/models/phone.rb +7 -0
  162. data/spec/models/post.rb +25 -0
  163. data/spec/models/preference.rb +7 -0
  164. data/spec/models/question.rb +8 -0
  165. data/spec/models/survey.rb +6 -0
  166. data/spec/models/translation.rb +5 -0
  167. data/spec/models/user.rb +6 -0
  168. data/spec/models/user_accout.rb +5 -0
  169. data/spec/models/vet_visit.rb +5 -0
  170. data/spec/models/video.rb +5 -0
  171. data/spec/spec_helper.rb +33 -0
  172. data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
  173. data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
  174. data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
  175. data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
  176. data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
  177. data/spec/unit/mongoid/associations/options_spec.rb +215 -0
  178. data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
  179. data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
  180. data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
  181. data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
  182. data/spec/unit/mongoid/associations_spec.rb +688 -0
  183. data/spec/unit/mongoid/atomicity_spec.rb +164 -0
  184. data/spec/unit/mongoid/attributes_spec.rb +646 -0
  185. data/spec/unit/mongoid/callbacks_spec.rb +85 -0
  186. data/spec/unit/mongoid/collection_spec.rb +187 -0
  187. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  188. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  189. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  190. data/spec/unit/mongoid/collections_spec.rb +98 -0
  191. data/spec/unit/mongoid/config_spec.rb +298 -0
  192. data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
  193. data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
  194. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  195. data/spec/unit/mongoid/criteria_spec.rb +873 -0
  196. data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
  197. data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
  198. data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
  199. data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
  200. data/spec/unit/mongoid/cursor_spec.rb +80 -0
  201. data/spec/unit/mongoid/deprecation_spec.rb +24 -0
  202. data/spec/unit/mongoid/dirty_spec.rb +430 -0
  203. data/spec/unit/mongoid/document_spec.rb +623 -0
  204. data/spec/unit/mongoid/errors_spec.rb +154 -0
  205. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  206. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  207. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
  208. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  209. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
  210. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  211. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  212. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
  213. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
  214. data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
  215. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  216. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  217. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
  218. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
  219. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  220. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  221. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  222. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
  223. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
  224. data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
  225. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  226. data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
  227. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
  228. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  229. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
  230. data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
  231. data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
  232. data/spec/unit/mongoid/extras_spec.rb +102 -0
  233. data/spec/unit/mongoid/factory_spec.rb +31 -0
  234. data/spec/unit/mongoid/field_spec.rb +169 -0
  235. data/spec/unit/mongoid/fields_spec.rb +181 -0
  236. data/spec/unit/mongoid/finders_spec.rb +439 -0
  237. data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
  238. data/spec/unit/mongoid/identity_spec.rb +109 -0
  239. data/spec/unit/mongoid/indexes_spec.rb +99 -0
  240. data/spec/unit/mongoid/javascript_spec.rb +48 -0
  241. data/spec/unit/mongoid/logger_spec.rb +38 -0
  242. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  243. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  244. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  245. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  246. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  247. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  248. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  249. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  250. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  251. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  252. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  253. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  254. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  255. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  256. data/spec/unit/mongoid/paranoia_spec.rb +108 -0
  257. data/spec/unit/mongoid/paths_spec.rb +272 -0
  258. data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
  259. data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
  260. data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
  261. data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
  262. data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
  263. data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
  264. data/spec/unit/mongoid/persistence_spec.rb +452 -0
  265. data/spec/unit/mongoid/scope_spec.rb +240 -0
  266. data/spec/unit/mongoid/serialization_spec.rb +43 -0
  267. data/spec/unit/mongoid/state_spec.rb +94 -0
  268. data/spec/unit/mongoid/timestamps_spec.rb +30 -0
  269. data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
  270. data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
  271. data/spec/unit/mongoid/validations_spec.rb +43 -0
  272. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  273. data/spec/unit/mongoid_spec.rb +46 -0
  274. metadata +433 -0
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Contexts #:nodoc:
4
+ module Paging
5
+ # Paginates the documents.
6
+ #
7
+ # Example:
8
+ #
9
+ # <tt>context.paginate(:page => 6, :per_page => 25)</tt>
10
+ #
11
+ # Returns:
12
+ #
13
+ # A collection of documents paginated.
14
+ # All previous <tt>limit</tt> and <tt>skip</tt> call will be ignored.
15
+ def paginate(pager_options={})
16
+ if pager_options[:per_page]
17
+ options[:limit] = pager_options[:per_page].to_i
18
+ if pager_options[:page]
19
+ options[:skip] = (pager_options[:page].to_i - 1) * pager_options[:per_page].to_i
20
+ end
21
+ end
22
+
23
+ @collection ||= execute(true)
24
+ WillPaginate::Collection.create(page, per_page, count) do |pager|
25
+ pager.replace(@collection.to_a)
26
+ end
27
+ end
28
+
29
+ # Either returns the page option and removes it from the options, or
30
+ # returns a default value of 1.
31
+ #
32
+ # Returns:
33
+ #
34
+ # An +Integer+ page number.
35
+ def page
36
+ skips, limits = options[:skip], options[:limit]
37
+ (skips && limits) ? (skips + limits) / limits : 1
38
+ end
39
+
40
+ # Get the number of results per page or the default of 20.
41
+ #
42
+ # Returns:
43
+ #
44
+ # The +Integer+ number of documents in each page.
45
+ def per_page
46
+ (options[:limit] || 20).to_i
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,248 @@
1
+ # encoding: utf-8
2
+ require "mongoid/criterion/complex"
3
+ require "mongoid/criterion/exclusion"
4
+ require "mongoid/criterion/inclusion"
5
+ require "mongoid/criterion/optional"
6
+
7
+ module Mongoid #:nodoc:
8
+ # The +Criteria+ class is the core object needed in Mongoid to retrieve
9
+ # objects from the database. It is a DSL that essentially sets up the
10
+ # selector and options arguments that get passed on to a <tt>Mongo::Collection</tt>
11
+ # in the Ruby driver. Each method on the +Criteria+ returns self to they
12
+ # can be chained in order to create a readable criterion to be executed
13
+ # against the database.
14
+ #
15
+ # Example setup:
16
+ #
17
+ # <tt>criteria = Criteria.new</tt>
18
+ #
19
+ # <tt>criteria.only(:field).where(:field => "value").skip(20).limit(20)</tt>
20
+ #
21
+ # <tt>criteria.execute</tt>
22
+ class Criteria
23
+ include Criterion::Exclusion
24
+ include Criterion::Inclusion
25
+ include Criterion::Optional
26
+ include Enumerable
27
+
28
+ attr_reader :collection, :ids, :klass, :options, :selector
29
+ attr_accessor :documents
30
+
31
+ delegate :aggregate, :avg, :blank?, :count, :distinct, :empty?,
32
+ :execute, :first, :group, :id_criteria, :last, :max,
33
+ :min, :one, :page, :paginate, :per_page, :sum, :to => :context
34
+
35
+ # Concatinate the criteria with another enumerable. If the other is a
36
+ # +Criteria+ then it needs to get the collection from it.
37
+ def +(other)
38
+ entries + comparable(other)
39
+ end
40
+
41
+ # Returns the difference between the criteria and another enumerable. If
42
+ # the other is a +Criteria+ then it needs to get the collection from it.
43
+ def -(other)
44
+ entries - comparable(other)
45
+ end
46
+
47
+ # Returns true if the supplied +Enumerable+ or +Criteria+ is equal to the results
48
+ # of this +Criteria+ or the criteria itself.
49
+ #
50
+ # This will force a database load when called if an enumerable is passed.
51
+ #
52
+ # Options:
53
+ #
54
+ # other: The other +Enumerable+ or +Criteria+ to compare to.
55
+ def ==(other)
56
+ case other
57
+ when Criteria
58
+ self.selector == other.selector && self.options == other.options
59
+ when Enumerable
60
+ return (execute.entries == other)
61
+ else
62
+ return false
63
+ end
64
+ end
65
+
66
+ # Returns true if the supplied +Object+ is an instance of +Criteria+ or
67
+ # +Scope+.
68
+ def self.===(other)
69
+ super || Scope === other
70
+ end
71
+
72
+ # Return or create the context in which this criteria should be executed.
73
+ #
74
+ # This will return an Enumerable context if the class is embedded,
75
+ # otherwise it will return a Mongo context for root classes.
76
+ def context
77
+ @context ||= Contexts.context_for(self)
78
+ end
79
+
80
+ # Iterate over each +Document+ in the results. This can take an optional
81
+ # block to pass to each argument in the results.
82
+ #
83
+ # Example:
84
+ #
85
+ # <tt>criteria.each { |doc| p doc }</tt>
86
+ def each(&block)
87
+ context.iterate(&block)
88
+ self
89
+ end
90
+
91
+ # Return true if the criteria has some Document or not
92
+ #
93
+ # Example:
94
+ #
95
+ # <tt>criteria.exists?</tt>
96
+ def exists?
97
+ context.count > 0
98
+ end
99
+
100
+ # Merges the supplied argument hash into a single criteria
101
+ #
102
+ # Options:
103
+ #
104
+ # criteria_conditions: Hash of criteria keys, and parameter values
105
+ #
106
+ # Example:
107
+ #
108
+ # <tt>criteria.fuse(:where => { :field => "value"}, :limit => 20)</tt>
109
+ #
110
+ # Returns <tt>self</tt>
111
+ def fuse(criteria_conditions = {})
112
+ criteria_conditions.inject(self) do |criteria, (key, value)|
113
+ criteria.send(key, value)
114
+ end
115
+ end
116
+
117
+ # Create the new +Criteria+ object. This will initialize the selector
118
+ # and options hashes, as well as the type of criteria.
119
+ #
120
+ # Options:
121
+ #
122
+ # type: One of :all, :first:, or :last
123
+ # klass: The class to execute on.
124
+ def initialize(klass)
125
+ @selector, @options, @klass, @documents = {}, {}, klass, []
126
+ end
127
+
128
+ # Merges another object into this +Criteria+. The other object may be a
129
+ # +Criteria+ or a +Hash+. This is used to combine multiple scopes together,
130
+ # where a chained scope situation may be desired.
131
+ #
132
+ # Options:
133
+ #
134
+ # other: The +Criteria+ or +Hash+ to merge with.
135
+ #
136
+ # Example:
137
+ #
138
+ # <tt>criteria.merge({ :conditions => { :title => "Sir" } })</tt>
139
+ def merge(other)
140
+ @selector.update(other.selector)
141
+ @options.update(other.options)
142
+ @documents = other.documents
143
+ end
144
+
145
+ # Used for chaining +Criteria+ scopes together in the for of class methods
146
+ # on the +Document+ the criteria is for.
147
+ #
148
+ # Options:
149
+ #
150
+ # name: The name of the class method on the +Document+ to chain.
151
+ # args: The arguments passed to the method.
152
+ #
153
+ # Returns: <tt>Criteria</tt>
154
+ def method_missing(name, *args)
155
+ if @klass.respond_to?(name)
156
+ new_scope = @klass.send(name, *args)
157
+ new_scope.merge(self) if Criteria === new_scope
158
+ return new_scope
159
+ else
160
+ return entries.send(name, *args)
161
+ end
162
+ end
163
+
164
+ alias :to_ary :to_a
165
+
166
+ # Returns the selector and options as a +Hash+ that would be passed to a
167
+ # scope for use with named scopes.
168
+ def scoped
169
+ scope_options = @options.dup
170
+ sorting = scope_options.delete(:sort)
171
+ scope_options[:order_by] = sorting if sorting
172
+ { :where => @selector }.merge(scope_options)
173
+ end
174
+
175
+ # Translate the supplied arguments into a +Criteria+ object.
176
+ #
177
+ # If the passed in args is a single +String+, then it will
178
+ # construct an id +Criteria+ from it.
179
+ #
180
+ # If the passed in args are a type and a hash, then it will construct
181
+ # the +Criteria+ with the proper selector, options, and type.
182
+ #
183
+ # Options:
184
+ #
185
+ # args: either a +String+ or a +Symbol+, +Hash combination.
186
+ #
187
+ # Example:
188
+ #
189
+ # <tt>Criteria.translate(Person, "4ab2bc4b8ad548971900005c")</tt>
190
+ # <tt>Criteria.translate(Person, :conditions => { :field => "value"}, :limit => 20)</tt>
191
+ def self.translate(*args)
192
+ klass = args[0]
193
+ params = args[1] || {}
194
+ unless params.is_a?(Hash)
195
+ return klass.criteria.id_criteria(params)
196
+ end
197
+ conditions = params.delete(:conditions) || {}
198
+ if conditions.include?(:id)
199
+ conditions[:_id] = conditions[:id]
200
+ conditions.delete(:id)
201
+ end
202
+ return klass.criteria.where(conditions).extras(params)
203
+ end
204
+
205
+ protected
206
+
207
+ # Filters the unused options out of the options +Hash+. Currently this
208
+ # takes into account the "page" and "per_page" options that would be passed
209
+ # in if using will_paginate.
210
+ #
211
+ # Example:
212
+ #
213
+ # Given a criteria with a selector of { :page => 1, :per_page => 40 }
214
+ #
215
+ # <tt>criteria.filter_options</tt> # selector: { :skip => 0, :limit => 40 }
216
+ def filter_options
217
+ page_num = @options.delete(:page)
218
+ per_page_num = @options.delete(:per_page)
219
+ if (page_num || per_page_num)
220
+ @options[:limit] = limits = (per_page_num || 20).to_i
221
+ @options[:skip] = (page_num || 1).to_i * limits - limits
222
+ end
223
+ end
224
+
225
+ # Return the entries of the other criteria or the object. Used for
226
+ # comparing criteria or an enumerable.
227
+ def comparable(other)
228
+ other.is_a?(Criteria) ? other.entries : other
229
+ end
230
+
231
+ # Update the selector setting the operator on the value for each key in the
232
+ # supplied attributes +Hash+.
233
+ #
234
+ # Example:
235
+ #
236
+ # <tt>criteria.update_selector({ :field => "value" }, "$in")</tt>
237
+ def update_selector(attributes, operator)
238
+ attributes.each do |key, value|
239
+ unless @selector[key]
240
+ @selector[key] = { operator => value }
241
+ else
242
+ new_value = @selector[key].values.first + value
243
+ @selector[key] = { operator => new_value }
244
+ end
245
+ end; self
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ # Complex criterion are used when performing operations on symbols to get
5
+ # get a shorthand syntax for where clauses.
6
+ #
7
+ # Example:
8
+ #
9
+ # <tt>{ :field => { "$lt" => "value" } }</tt>
10
+ # becomes:
11
+ # <tt> { :field.lt => "value }</tt>
12
+ class Complex
13
+ attr_accessor :key, :operator
14
+
15
+ # Create the new complex criterion.
16
+ def initialize(opts = {})
17
+ @key, @operator = opts[:key], opts[:operator]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Exclusion
5
+ # Adds a criterion to the +Criteria+ that specifies values that are not allowed
6
+ # to match any document in the database. The MongoDB conditional operator that
7
+ # will be used is "$ne".
8
+ #
9
+ # Options:
10
+ #
11
+ # attributes: A +Hash+ where the key is the field name and the value is a
12
+ # value that must not be equal to the corresponding field value in the database.
13
+ #
14
+ # Example:
15
+ #
16
+ # <tt>criteria.excludes(:field => "value1")</tt>
17
+ #
18
+ # <tt>criteria.excludes(:field1 => "value1", :field2 => "value1")</tt>
19
+ #
20
+ # Returns: <tt>self</tt>
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
+ # Adds a criterion to the +Criteria+ that specifies values where none
28
+ # should match in order to return results. This is similar to an SQL "NOT IN"
29
+ # clause. The MongoDB conditional operator that will be used is "$nin".
30
+ #
31
+ # Options:
32
+ #
33
+ # attributes: A +Hash+ where the key is the field name and the value is an
34
+ # +Array+ of values that none can match.
35
+ #
36
+ # Example:
37
+ #
38
+ # <tt>criteria.not_in(:field => ["value1", "value2"])</tt>
39
+ #
40
+ # <tt>criteria.not_in(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
41
+ #
42
+ # Returns: <tt>self</tt>
43
+ def not_in(attributes)
44
+ update_selector(attributes, "$nin")
45
+ end
46
+
47
+ # Adds a criterion to the +Criteria+ that specifies the fields that will
48
+ # get returned from the Document. Used mainly for list views that do not
49
+ # require all fields to be present. This is similar to SQL "SELECT" values.
50
+ #
51
+ # Options:
52
+ #
53
+ # args: A list of field names to retrict the returned fields to.
54
+ #
55
+ # Example:
56
+ #
57
+ # <tt>criteria.only(:field1, :field2, :field3)</tt>
58
+ #
59
+ # Returns: <tt>self</tt>
60
+ def only(*args)
61
+ @options[:fields] = args.flatten if args.any?; self
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Inclusion
5
+ # Adds a criterion to the +Criteria+ that specifies values that must all
6
+ # be matched in order to return results. Similar to an "in" clause but the
7
+ # underlying conditional logic is an "AND" and not an "OR". The MongoDB
8
+ # conditional operator that will be used is "$all".
9
+ #
10
+ # Options:
11
+ #
12
+ # attributes: A +Hash+ where the key is the field name and the value is an
13
+ # +Array+ of values that must all match.
14
+ #
15
+ # Example:
16
+ #
17
+ # <tt>criteria.all(:field => ["value1", "value2"])</tt>
18
+ #
19
+ # <tt>criteria.all(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
20
+ #
21
+ # Returns: <tt>self</tt>
22
+ def all(attributes = {})
23
+ update_selector(attributes, "$all")
24
+ end
25
+ alias :all_in :all
26
+
27
+ # Adds a criterion to the +Criteria+ that specifies values that must
28
+ # be matched in order to return results. This is similar to a SQL "WHERE"
29
+ # clause. This is the actual selector that will be provided to MongoDB,
30
+ # similar to the Javascript object that is used when performing a find()
31
+ # in the MongoDB console.
32
+ #
33
+ # Options:
34
+ #
35
+ # selectior: A +Hash+ that must match the attributes of the +Document+.
36
+ #
37
+ # Example:
38
+ #
39
+ # <tt>criteria.and(:field1 => "value1", :field2 => 15)</tt>
40
+ #
41
+ # Returns: <tt>self</tt>
42
+ def and(selector = nil)
43
+ where(selector)
44
+ end
45
+
46
+ # Adds a criterion to the +Criteria+ that specifies values where any can
47
+ # be matched in order to return results. This is similar to an SQL "IN"
48
+ # clause. The MongoDB conditional operator that will be used is "$in".
49
+ #
50
+ # Options:
51
+ #
52
+ # attributes: A +Hash+ where the key is the field name and the value is an
53
+ # +Array+ of values that any can match.
54
+ #
55
+ # Example:
56
+ #
57
+ # <tt>criteria.in(:field => ["value1", "value2"])</tt>
58
+ #
59
+ # <tt>criteria.in(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
60
+ #
61
+ # Returns: <tt>self</tt>
62
+ def in(attributes = {})
63
+ update_selector(attributes, "$in")
64
+ end
65
+ alias :any_in :in
66
+
67
+ # Adds a criterion to the +Criteria+ that specifies values to do
68
+ # geospacial searches by. The field must be indexed with the "2d" option.
69
+ #
70
+ # Options:
71
+ #
72
+ # attributes: A +Hash+ where the keys are the field names and the values are
73
+ # +Arrays+ of [latitude, longitude] pairs.
74
+ #
75
+ # Example:
76
+ #
77
+ # <tt>criteria.near(:field1 => [30, -44])</tt>
78
+ #
79
+ # Returns: <tt>self</tt>
80
+ def near(attributes = {})
81
+ update_selector(attributes, "$near")
82
+ end
83
+
84
+ # Adds a criterion to the +Criteria+ that specifies values that must
85
+ # be matched in order to return results. This is similar to a SQL "WHERE"
86
+ # clause. This is the actual selector that will be provided to MongoDB,
87
+ # similar to the Javascript object that is used when performing a find()
88
+ # in the MongoDB console.
89
+ #
90
+ # Options:
91
+ #
92
+ # selectior: A +Hash+ that must match the attributes of the +Document+.
93
+ #
94
+ # Example:
95
+ #
96
+ # <tt>criteria.where(:field1 => "value1", :field2 => 15)</tt>
97
+ #
98
+ # Returns: <tt>self</tt>
99
+ def where(selector = nil)
100
+ case selector
101
+ when String
102
+ @selector.update("$where" => selector)
103
+ else
104
+ @selector.update(selector ? selector.expand_complex_criteria : {})
105
+ end
106
+ self
107
+ end
108
+ end
109
+ end
110
+ end