mongoid 5.4.0 → 6.4.8

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 (301) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +26 -0
  5. data/lib/config/locales/en.yml +40 -0
  6. data/lib/mongoid/atomic/modifiers.rb +2 -2
  7. data/lib/mongoid/atomic.rb +5 -5
  8. data/lib/mongoid/attributes/readonly.rb +22 -0
  9. data/lib/mongoid/attributes.rb +22 -21
  10. data/lib/mongoid/cacheable.rb +36 -0
  11. data/lib/mongoid/changeable.rb +36 -0
  12. data/lib/mongoid/clients/options.rb +55 -250
  13. data/lib/mongoid/clients/sessions.rb +113 -0
  14. data/lib/mongoid/clients/storage_options.rb +2 -69
  15. data/lib/mongoid/clients.rb +10 -63
  16. data/lib/mongoid/composable.rb +29 -2
  17. data/lib/mongoid/config.rb +1 -0
  18. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  19. data/lib/mongoid/contextual/atomic.rb +4 -4
  20. data/lib/mongoid/contextual/map_reduce.rb +7 -3
  21. data/lib/mongoid/contextual/memory.rb +9 -4
  22. data/lib/mongoid/contextual/mongo.rb +65 -30
  23. data/lib/mongoid/contextual/none.rb +12 -0
  24. data/lib/mongoid/copyable.rb +13 -6
  25. data/lib/mongoid/criteria/marshalable.rb +2 -2
  26. data/lib/mongoid/criteria/modifiable.rb +29 -3
  27. data/lib/mongoid/criteria/options.rb +25 -0
  28. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  29. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  30. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  31. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  32. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  33. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  34. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  35. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  36. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  37. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  38. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  39. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +79 -0
  40. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  41. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  42. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  43. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  44. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  45. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  46. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  47. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  48. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  49. data/lib/mongoid/criteria/queryable/mergeable.rb +273 -0
  50. data/lib/mongoid/criteria/queryable/optional.rb +429 -0
  51. data/lib/mongoid/criteria/queryable/options.rb +153 -0
  52. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  53. data/lib/mongoid/criteria/queryable/selectable.rb +689 -0
  54. data/lib/mongoid/criteria/queryable/selector.rb +212 -0
  55. data/lib/mongoid/criteria/queryable/smash.rb +104 -0
  56. data/lib/mongoid/criteria/queryable.rb +87 -0
  57. data/lib/mongoid/criteria.rb +6 -2
  58. data/lib/mongoid/document.rb +34 -41
  59. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  60. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
  61. data/lib/mongoid/errors/invalid_field.rb +2 -2
  62. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  63. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  64. data/lib/mongoid/errors/invalid_session_use.rb +24 -0
  65. data/lib/mongoid/errors.rb +3 -0
  66. data/lib/mongoid/evolvable.rb +1 -1
  67. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  68. data/lib/mongoid/extensions/date.rb +4 -1
  69. data/lib/mongoid/extensions/decimal128.rb +3 -3
  70. data/lib/mongoid/extensions/hash.rb +1 -0
  71. data/lib/mongoid/extensions/regexp.rb +1 -0
  72. data/lib/mongoid/extensions/string.rb +6 -3
  73. data/lib/mongoid/extensions/time.rb +4 -1
  74. data/lib/mongoid/extensions.rb +0 -4
  75. data/lib/mongoid/factory.rb +2 -1
  76. data/lib/mongoid/fields/validators/macro.rb +18 -0
  77. data/lib/mongoid/findable.rb +2 -2
  78. data/lib/mongoid/indexable.rb +16 -14
  79. data/lib/mongoid/interceptable.rb +9 -22
  80. data/lib/mongoid/matchable/all.rb +2 -2
  81. data/lib/mongoid/matchable/and.rb +3 -3
  82. data/lib/mongoid/matchable/default.rb +2 -2
  83. data/lib/mongoid/matchable/elem_match.rb +28 -0
  84. data/lib/mongoid/matchable/exists.rb +2 -2
  85. data/lib/mongoid/matchable/gt.rb +4 -2
  86. data/lib/mongoid/matchable/gte.rb +4 -2
  87. data/lib/mongoid/matchable/in.rb +2 -2
  88. data/lib/mongoid/matchable/lt.rb +4 -2
  89. data/lib/mongoid/matchable/lte.rb +4 -2
  90. data/lib/mongoid/matchable/ne.rb +2 -2
  91. data/lib/mongoid/matchable/nin.rb +2 -2
  92. data/lib/mongoid/matchable/nor.rb +37 -0
  93. data/lib/mongoid/matchable/or.rb +3 -3
  94. data/lib/mongoid/matchable/regexp.rb +3 -3
  95. data/lib/mongoid/matchable/size.rb +2 -2
  96. data/lib/mongoid/matchable.rb +16 -7
  97. data/lib/mongoid/persistable/creatable.rb +5 -3
  98. data/lib/mongoid/persistable/deletable.rb +5 -3
  99. data/lib/mongoid/persistable/destroyable.rb +1 -5
  100. data/lib/mongoid/persistable/settable.rb +5 -5
  101. data/lib/mongoid/persistable/updatable.rb +7 -14
  102. data/lib/mongoid/persistable/upsertable.rb +2 -1
  103. data/lib/mongoid/persistable.rb +4 -6
  104. data/lib/mongoid/persistence_context.rb +220 -0
  105. data/lib/mongoid/query_cache.rb +67 -23
  106. data/lib/mongoid/railtie.rb +17 -1
  107. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  108. data/lib/mongoid/relations/accessors.rb +3 -0
  109. data/lib/mongoid/relations/auto_save.rb +12 -4
  110. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  111. data/lib/mongoid/relations/counter_cache.rb +15 -5
  112. data/lib/mongoid/relations/eager/base.rb +3 -3
  113. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
  114. data/lib/mongoid/relations/eager/has_many.rb +1 -1
  115. data/lib/mongoid/relations/eager.rb +6 -11
  116. data/lib/mongoid/relations/embedded/batchable.rb +20 -18
  117. data/lib/mongoid/relations/embedded/in.rb +13 -1
  118. data/lib/mongoid/relations/embedded/many.rb +51 -10
  119. data/lib/mongoid/relations/embedded/one.rb +14 -1
  120. data/lib/mongoid/relations/macros.rb +9 -1
  121. data/lib/mongoid/relations/many.rb +4 -0
  122. data/lib/mongoid/relations/metadata.rb +3 -3
  123. data/lib/mongoid/relations/options.rb +2 -2
  124. data/lib/mongoid/relations/proxy.rb +1 -31
  125. data/lib/mongoid/relations/referenced/in.rb +19 -10
  126. data/lib/mongoid/relations/referenced/many.rb +30 -26
  127. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  128. data/lib/mongoid/relations/referenced/one.rb +15 -1
  129. data/lib/mongoid/relations/synchronization.rb +12 -12
  130. data/lib/mongoid/relations/targets/enumerable.rb +24 -4
  131. data/lib/mongoid/relations/touchable.rb +7 -4
  132. data/lib/mongoid/reloadable.rb +2 -2
  133. data/lib/mongoid/scopable.rb +3 -3
  134. data/lib/mongoid/serializable.rb +1 -1
  135. data/lib/mongoid/stateful.rb +1 -0
  136. data/lib/mongoid/tasks/database.rb +3 -2
  137. data/lib/mongoid/threaded.rb +74 -0
  138. data/lib/mongoid/traversable.rb +1 -1
  139. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  140. data/lib/mongoid/version.rb +1 -1
  141. data/lib/mongoid.rb +6 -6
  142. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +18 -3
  143. data/spec/app/models/agent.rb +2 -0
  144. data/spec/app/models/album.rb +5 -1
  145. data/spec/app/models/array_field.rb +7 -0
  146. data/spec/app/models/artist.rb +21 -0
  147. data/spec/app/models/band.rb +3 -0
  148. data/spec/app/models/book.rb +2 -1
  149. data/spec/app/models/delegating_patient.rb +16 -0
  150. data/spec/app/models/dokument.rb +1 -0
  151. data/spec/app/models/ordered_post.rb +5 -0
  152. data/spec/app/models/oscar.rb +1 -2
  153. data/spec/app/models/page.rb +1 -1
  154. data/spec/app/models/person.rb +3 -3
  155. data/spec/app/models/princess.rb +2 -0
  156. data/spec/app/models/record.rb +1 -0
  157. data/spec/app/models/subscription.rb +1 -0
  158. data/spec/app/models/thing.rb +1 -1
  159. data/spec/config/mongoid.yml +15 -0
  160. data/spec/integration/document_spec.rb +22 -0
  161. data/spec/mongoid/atomic/modifiers_spec.rb +3 -3
  162. data/spec/mongoid/atomic_spec.rb +5 -5
  163. data/spec/mongoid/attributes/nested_spec.rb +18 -14
  164. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  165. data/spec/mongoid/attributes_spec.rb +90 -5
  166. data/spec/mongoid/cacheable_spec.rb +112 -0
  167. data/spec/mongoid/changeable_spec.rb +58 -0
  168. data/spec/mongoid/clients/factory_spec.rb +80 -28
  169. data/spec/mongoid/clients/options_spec.rb +396 -95
  170. data/spec/mongoid/clients/sessions_spec.rb +334 -0
  171. data/spec/mongoid/clients_spec.rb +243 -101
  172. data/spec/mongoid/composable_spec.rb +7 -0
  173. data/spec/mongoid/config_spec.rb +67 -11
  174. data/spec/mongoid/contextual/atomic_spec.rb +3 -3
  175. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  176. data/spec/mongoid/contextual/mongo_spec.rb +275 -22
  177. data/spec/mongoid/contextual/none_spec.rb +15 -0
  178. data/spec/mongoid/copyable_spec.rb +13 -4
  179. data/spec/mongoid/criteria/modifiable_spec.rb +297 -16
  180. data/spec/mongoid/criteria/options_spec.rb +29 -0
  181. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  182. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  183. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  184. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  185. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  186. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  187. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  188. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  189. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  190. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  191. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  192. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  193. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  194. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  195. data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
  196. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
  197. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  198. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  199. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  200. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  201. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  202. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  203. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  204. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  205. data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
  206. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  207. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  208. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  209. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4242 -0
  210. data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
  211. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  212. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  213. data/spec/mongoid/criteria_spec.rb +156 -22
  214. data/spec/mongoid/document_spec.rb +100 -90
  215. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  216. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  217. data/spec/mongoid/extensions/big_decimal_spec.rb +321 -19
  218. data/spec/mongoid/extensions/boolean_spec.rb +14 -0
  219. data/spec/mongoid/extensions/date_spec.rb +2 -6
  220. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  221. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  222. data/spec/mongoid/extensions/float_spec.rb +8 -1
  223. data/spec/mongoid/extensions/hash_spec.rb +15 -0
  224. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  225. data/spec/mongoid/extensions/object_spec.rb +11 -0
  226. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  227. data/spec/mongoid/extensions/string_spec.rb +53 -4
  228. data/spec/mongoid/extensions/time_spec.rb +2 -6
  229. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  230. data/spec/mongoid/factory_spec.rb +11 -0
  231. data/spec/mongoid/fields_spec.rb +1 -1
  232. data/spec/mongoid/findable_spec.rb +47 -2
  233. data/spec/mongoid/indexable_spec.rb +15 -3
  234. data/spec/mongoid/interceptable_spec.rb +85 -19
  235. data/spec/mongoid/matchable/all_spec.rb +4 -4
  236. data/spec/mongoid/matchable/and_spec.rb +10 -10
  237. data/spec/mongoid/matchable/default_spec.rb +12 -12
  238. data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
  239. data/spec/mongoid/matchable/exists_spec.rb +5 -5
  240. data/spec/mongoid/matchable/gt_spec.rb +18 -7
  241. data/spec/mongoid/matchable/gte_spec.rb +17 -7
  242. data/spec/mongoid/matchable/in_spec.rb +5 -5
  243. data/spec/mongoid/matchable/lt_spec.rb +18 -7
  244. data/spec/mongoid/matchable/lte_spec.rb +18 -7
  245. data/spec/mongoid/matchable/ne_spec.rb +5 -5
  246. data/spec/mongoid/matchable/nin_spec.rb +5 -5
  247. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  248. data/spec/mongoid/matchable/or_spec.rb +7 -7
  249. data/spec/mongoid/matchable/regexp_spec.rb +5 -5
  250. data/spec/mongoid/matchable/size_spec.rb +3 -3
  251. data/spec/mongoid/matchable_spec.rb +199 -54
  252. data/spec/mongoid/persistable/creatable_spec.rb +7 -2
  253. data/spec/mongoid/persistable/deletable_spec.rb +35 -1
  254. data/spec/mongoid/persistable/destroyable_spec.rb +25 -2
  255. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  256. data/spec/mongoid/persistable/savable_spec.rb +34 -29
  257. data/spec/mongoid/persistable/settable_spec.rb +77 -27
  258. data/spec/mongoid/persistable/updatable_spec.rb +182 -3
  259. data/spec/mongoid/persistable_spec.rb +16 -16
  260. data/spec/mongoid/persistence_context_spec.rb +694 -0
  261. data/spec/mongoid/positional_spec.rb +1 -1
  262. data/spec/mongoid/query_cache_spec.rb +170 -12
  263. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  264. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  265. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
  266. data/spec/mongoid/relations/builders_spec.rb +37 -10
  267. data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
  268. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
  269. data/spec/mongoid/relations/eager_spec.rb +40 -0
  270. data/spec/mongoid/relations/embedded/many_spec.rb +305 -59
  271. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  272. data/spec/mongoid/relations/macros_spec.rb +415 -7
  273. data/spec/mongoid/relations/metadata_spec.rb +15 -1
  274. data/spec/mongoid/relations/proxy_spec.rb +27 -1
  275. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  276. data/spec/mongoid/relations/referenced/many_spec.rb +35 -25
  277. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
  278. data/spec/mongoid/relations/synchronization_spec.rb +48 -2
  279. data/spec/mongoid/relations/targets/enumerable_spec.rb +108 -0
  280. data/spec/mongoid/relations/touchable_spec.rb +40 -0
  281. data/spec/mongoid/reloadable_spec.rb +51 -0
  282. data/spec/mongoid/scopable_spec.rb +13 -0
  283. data/spec/mongoid/serializable_spec.rb +0 -50
  284. data/spec/mongoid/threaded_spec.rb +68 -0
  285. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  286. data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
  287. data/spec/mongoid/validatable_spec.rb +16 -0
  288. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  289. data/spec/spec_helper.rb +101 -8
  290. data/spec/support/cluster_config.rb +158 -0
  291. data/spec/support/constraints.rb +101 -0
  292. data/spec/support/macros.rb +20 -0
  293. data/spec/support/session_registry.rb +50 -0
  294. data/spec/support/spec_config.rb +42 -0
  295. data.tar.gz.sig +0 -0
  296. metadata +163 -61
  297. metadata.gz.sig +0 -0
  298. data/lib/mongoid/clients/thread_options.rb +0 -19
  299. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  300. data/lib/mongoid/railties/document.rb +0 -12
  301. data/spec/mongoid/railties/document_spec.rb +0 -24
@@ -0,0 +1,689 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+ class Criteria
4
+ module Queryable
5
+
6
+ # An queryable selectable is selectable, in that it has the ability to select
7
+ # document from the database. The selectable module brings all functionality
8
+ # to the selectable that has to do with building MongoDB selectors.
9
+ module Selectable
10
+ extend Macroable
11
+
12
+ # Constant for a LineString $geometry.
13
+ #
14
+ # @since 2.0.0
15
+ LINE_STRING = "LineString"
16
+
17
+ # Constant for a Point $geometry.
18
+ #
19
+ # @since 2.0.0
20
+ POINT = "Point"
21
+
22
+ # Constant for a Polygon $geometry.
23
+ #
24
+ # @since 2.0.0
25
+ POLYGON = "Polygon"
26
+
27
+ # @attribute [rw] negating If the next expression is negated.
28
+ # @attribute [rw] selector The query selector.
29
+ attr_accessor :negating, :selector
30
+
31
+ # Add the $all criterion.
32
+ #
33
+ # @example Add the criterion.
34
+ # selectable.all(field: [ 1, 2 ])
35
+ #
36
+ # @example Execute an $all in a where query.
37
+ # selectable.where(:field.all => [ 1, 2 ])
38
+ #
39
+ # @param [ Hash ] criterion The key value pairs for $all matching.
40
+ #
41
+ # @return [ Selectable ] The cloned selectable.
42
+ #
43
+ # @since 1.0.0
44
+ def all(criterion = nil)
45
+ send(strategy || :__union__, with_array_values(criterion), "$all")
46
+ end
47
+ alias :all_in :all
48
+ key :all, :union, "$all"
49
+
50
+ # Add the $and criterion.
51
+ #
52
+ # @example Add the criterion.
53
+ # selectable.and({ field: value }, { other: value })
54
+ #
55
+ # @param [ Array<Hash> ] criterion Multiple key/value pair matches that
56
+ # all must match to return results.
57
+ #
58
+ # @return [ Selectable ] The cloned selectable.
59
+ #
60
+ # @since 1.0.0
61
+ def and(*criterion)
62
+ __multi__(criterion, "$and")
63
+ end
64
+ alias :all_of :and
65
+
66
+ # Add the range selection.
67
+ #
68
+ # @example Match on results within a single range.
69
+ # selectable.between(field: 1..2)
70
+ #
71
+ # @example Match on results between multiple ranges.
72
+ # selectable.between(field: 1..2, other: 5..7)
73
+ #
74
+ # @param [ Hash ] criterion Multiple key/range pairs.
75
+ #
76
+ # @return [ Selectable ] The cloned selectable.
77
+ #
78
+ # @since 1.0.0
79
+ def between(criterion = nil)
80
+ selection(criterion) do |selector, field, value|
81
+ selector.store(
82
+ field,
83
+ { "$gte" => value.min, "$lte" => value.max }
84
+ )
85
+ end
86
+ end
87
+
88
+ # Select with an $elemMatch.
89
+ #
90
+ # @example Add criterion for a single match.
91
+ # selectable.elem_match(field: { name: "value" })
92
+ #
93
+ # @example Add criterion for multiple matches.
94
+ # selectable.elem_match(
95
+ # field: { name: "value" },
96
+ # other: { name: "value"}
97
+ # )
98
+ #
99
+ # @example Execute an $elemMatch in a where query.
100
+ # selectable.where(:field.elem_match => { name: "value" })
101
+ #
102
+ # @param [ Hash ] criterion The field/match pairs.
103
+ #
104
+ # @return [ Selectable ] The cloned selectable.
105
+ #
106
+ # @since 1.0.0
107
+ def elem_match(criterion = nil)
108
+ __override__(criterion, "$elemMatch")
109
+ end
110
+ key :elem_match, :override, "$elemMatch"
111
+
112
+ # Add the $exists selection.
113
+ #
114
+ # @example Add a single selection.
115
+ # selectable.exists(field: true)
116
+ #
117
+ # @example Add multiple selections.
118
+ # selectable.exists(field: true, other: false)
119
+ #
120
+ # @example Execute an $exists in a where query.
121
+ # selectable.where(:field.exists => true)
122
+ #
123
+ # @param [ Hash ] criterion The field/boolean existence checks.
124
+ #
125
+ # @return [ Selectable ] The cloned selectable.
126
+ #
127
+ # @since 1.0.0
128
+ def exists(criterion = nil)
129
+ typed_override(criterion, "$exists") do |value|
130
+ ::Boolean.evolve(value)
131
+ end
132
+ end
133
+ key :exists, :override, "$exists" do |value|
134
+ ::Boolean.evolve(value)
135
+ end
136
+
137
+ # Add a $geoIntersects or $geoWithin selection. Symbol operators must
138
+ # be used as shown in the examples to expand the criteria.
139
+ #
140
+ # @note The only valid geometry shapes for a $geoIntersects are:
141
+ # :intersects_line, :intersects_point, and :intersects_polygon.
142
+ #
143
+ # @note The only valid options for a $geoWithin query are the geometry
144
+ # shape :within_polygon and the operator :within_box.
145
+ #
146
+ # @note The :within_box operator for the $geoWithin query expects the
147
+ # lower left (south west) coordinate pair as the first argument and
148
+ # the upper right (north east) as the second argument.
149
+ # Important: When latitude and longitude are passed, longitude is
150
+ # expected as the first element of the coordinate pair.
151
+ # Source: https://docs.mongodb.com/manual/reference/operator/query/box/
152
+ #
153
+ # @example Add a geo intersect criterion for a line.
154
+ # query.geo_spacial(:location.intersects_line => [[ 1, 10 ], [ 2, 10 ]])
155
+ #
156
+ # @example Add a geo intersect criterion for a point.
157
+ # query.geo_spacial(:location.intersects_point => [[ 1, 10 ]])
158
+ #
159
+ # @example Add a geo intersect criterion for a polygon.
160
+ # query.geo_spacial(:location.intersects_polygon => [[ 1, 10 ], [ 2, 10 ], [ 1, 10 ]])
161
+ #
162
+ # @example Add a geo within criterion for a polygon.
163
+ # query.geo_spacial(:location.within_polygon => [[ 1, 10 ], [ 2, 10 ], [ 1, 10 ]])
164
+ #
165
+ # @example Add a geo within criterion for a box.
166
+ # query.geo_spacial(:location.within_box => [[ 1, 10 ], [ 2, 10 ])
167
+ #
168
+ # @param [ Hash ] criterion The criterion.
169
+ #
170
+ # @return [ Selectable ] The cloned selectable.
171
+ #
172
+ # @since 2.0.0
173
+ def geo_spacial(criterion = nil)
174
+ __merge__(criterion)
175
+ end
176
+ key :intersects_line, :override, "$geoIntersects", "$geometry" do |value|
177
+ { "type" => LINE_STRING, "coordinates" => value }
178
+ end
179
+ key :intersects_point, :override, "$geoIntersects", "$geometry" do |value|
180
+ { "type" => POINT, "coordinates" => value }
181
+ end
182
+ key :intersects_polygon, :override, "$geoIntersects", "$geometry" do |value|
183
+ { "type" => POLYGON, "coordinates" => value }
184
+ end
185
+ key :within_polygon, :override, "$geoWithin", "$geometry" do |value|
186
+ { "type" => POLYGON, "coordinates" => value }
187
+ end
188
+ key :within_box, :override, "$geoWithin", "$box"
189
+
190
+ # Add the $gt criterion to the selector.
191
+ #
192
+ # @example Add the $gt criterion.
193
+ # selectable.gt(age: 60)
194
+ #
195
+ # @example Execute an $gt in a where query.
196
+ # selectable.where(:field.gt => 10)
197
+ #
198
+ # @param [ Hash ] criterion The field/value pairs to check.
199
+ #
200
+ # @return [ Selectable ] The cloned selectable.
201
+ #
202
+ # @since 1.0.0
203
+ def gt(criterion = nil)
204
+ __override__(criterion, "$gt")
205
+ end
206
+ key :gt, :override, "$gt"
207
+
208
+ # Add the $gte criterion to the selector.
209
+ #
210
+ # @example Add the $gte criterion.
211
+ # selectable.gte(age: 60)
212
+ #
213
+ # @example Execute an $gte in a where query.
214
+ # selectable.where(:field.gte => 10)
215
+ #
216
+ # @param [ Hash ] criterion The field/value pairs to check.
217
+ #
218
+ # @return [ Selectable ] The cloned selectable.
219
+ #
220
+ # @since 1.0.0
221
+ def gte(criterion = nil)
222
+ __override__(criterion, "$gte")
223
+ end
224
+ key :gte, :override, "$gte"
225
+
226
+ # Adds the $in selection to the selectable.
227
+ #
228
+ # @example Add $in selection on an array.
229
+ # selectable.in(age: [ 1, 2, 3 ])
230
+ #
231
+ # @example Add $in selection on a range.
232
+ # selectable.in(age: 18..24)
233
+ #
234
+ # @example Execute an $in in a where query.
235
+ # selectable.where(:field.in => [ 1, 2, 3 ])
236
+ #
237
+ # @param [ Hash ] criterion The field/value criterion pairs.
238
+ #
239
+ # @return [ Selectable ] The cloned selectable.
240
+ #
241
+ # @since 1.0.0
242
+ def in(criterion = nil)
243
+ send(strategy || :__intersect__, with_array_values(criterion), "$in")
244
+ end
245
+ alias :any_in :in
246
+ key :in, :intersect, "$in"
247
+
248
+ # Add the $lt criterion to the selector.
249
+ #
250
+ # @example Add the $lt criterion.
251
+ # selectable.lt(age: 60)
252
+ #
253
+ # @example Execute an $lt in a where query.
254
+ # selectable.where(:field.lt => 10)
255
+ #
256
+ # @param [ Hash ] criterion The field/value pairs to check.
257
+ #
258
+ # @return [ Selectable ] The cloned selectable.
259
+ #
260
+ # @since 1.0.0
261
+ def lt(criterion = nil)
262
+ __override__(criterion, "$lt")
263
+ end
264
+ key :lt, :override, "$lt"
265
+
266
+ # Add the $lte criterion to the selector.
267
+ #
268
+ # @example Add the $lte criterion.
269
+ # selectable.lte(age: 60)
270
+ #
271
+ # @example Execute an $lte in a where query.
272
+ # selectable.where(:field.lte => 10)
273
+ #
274
+ # @param [ Hash ] criterion The field/value pairs to check.
275
+ #
276
+ # @return [ Selectable ] The cloned selectable.
277
+ #
278
+ # @since 1.0.0
279
+ def lte(criterion = nil)
280
+ __override__(criterion, "$lte")
281
+ end
282
+ key :lte, :override, "$lte"
283
+
284
+ # Add a $maxDistance selection to the selectable.
285
+ #
286
+ # @example Add the $maxDistance selection.
287
+ # selectable.max_distance(location: 10)
288
+ #
289
+ # @param [ Hash ] criterion The field/distance pairs.
290
+ #
291
+ # @return [ Selectable ] The cloned selectable.
292
+ #
293
+ # @since 1.0.0
294
+ def max_distance(criterion = nil)
295
+ __add__(criterion, "$maxDistance")
296
+ end
297
+
298
+ # Adds $mod selection to the selectable.
299
+ #
300
+ # @example Add the $mod selection.
301
+ # selectable.mod(field: [ 10, 1 ])
302
+ #
303
+ # @example Execute an $mod in a where query.
304
+ # selectable.where(:field.mod => [ 10, 1 ])
305
+ #
306
+ # @param [ Hash ] criterion The field/mod selections.
307
+ #
308
+ # @return [ Selectable ] The cloned selectable.
309
+ #
310
+ # @since 1.0.0
311
+ def mod(criterion = nil)
312
+ __override__(criterion, "$mod")
313
+ end
314
+ key :mod, :override, "$mod"
315
+
316
+ # Adds $ne selection to the selectable.
317
+ #
318
+ # @example Query for a value $ne to something.
319
+ # selectable.ne(field: 10)
320
+ #
321
+ # @example Execute an $ne in a where query.
322
+ # selectable.where(:field.ne => "value")
323
+ #
324
+ # @param [ Hash ] criterion The field/ne selections.
325
+ #
326
+ # @return [ Selectable ] The cloned selectable.
327
+ #
328
+ # @since 1.0.0
329
+ def ne(criterion = nil)
330
+ __override__(criterion, "$ne")
331
+ end
332
+ alias :excludes :ne
333
+ key :ne, :override, "$ne"
334
+
335
+ # Adds a $near criterion to a geo selection.
336
+ #
337
+ # @example Add the $near selection.
338
+ # selectable.near(location: [ 23.1, 12.1 ])
339
+ #
340
+ # @example Execute an $near in a where query.
341
+ # selectable.where(:field.near => [ 23.2, 12.1 ])
342
+ #
343
+ # @param [ Hash ] criterion The field/location pair.
344
+ #
345
+ # @return [ Selectable ] The cloned selectable.
346
+ #
347
+ # @since 1.0.0
348
+ def near(criterion = nil)
349
+ __override__(criterion, "$near")
350
+ end
351
+ key :near, :override, "$near"
352
+
353
+ # Adds a $nearSphere criterion to a geo selection.
354
+ #
355
+ # @example Add the $nearSphere selection.
356
+ # selectable.near_sphere(location: [ 23.1, 12.1 ])
357
+ #
358
+ # @example Execute an $nearSphere in a where query.
359
+ # selectable.where(:field.near_sphere => [ 10.11, 3.22 ])
360
+ #
361
+ # @param [ Hash ] criterion The field/location pair.
362
+ #
363
+ # @return [ Selectable ] The cloned selectable.
364
+ #
365
+ # @since 1.0.0
366
+ def near_sphere(criterion = nil)
367
+ __override__(criterion, "$nearSphere")
368
+ end
369
+ key :near_sphere, :override, "$nearSphere"
370
+
371
+ # Adds the $nin selection to the selectable.
372
+ #
373
+ # @example Add $nin selection on an array.
374
+ # selectable.nin(age: [ 1, 2, 3 ])
375
+ #
376
+ # @example Add $nin selection on a range.
377
+ # selectable.nin(age: 18..24)
378
+ #
379
+ # @example Execute an $nin in a where query.
380
+ # selectable.where(:field.nin => [ 1, 2, 3 ])
381
+ #
382
+ # @param [ Hash ] criterion The field/value criterion pairs.
383
+ #
384
+ # @return [ Selectable ] The cloned selectable.
385
+ #
386
+ # @since 1.0.0
387
+ def nin(criterion = nil)
388
+ send(strategy || :__intersect__, with_array_values(criterion), "$nin")
389
+ end
390
+ alias :not_in :nin
391
+ key :nin, :intersect, "$nin"
392
+
393
+ # Adds $nor selection to the selectable.
394
+ #
395
+ # @example Add the $nor selection.
396
+ # selectable.nor(field: 1, field: 2)
397
+ #
398
+ # @param [ Array ] criterion An array of hash criterion.
399
+ #
400
+ # @return [ Selectable ] The cloned selectable.
401
+ #
402
+ # @since 1.0.0
403
+ def nor(*criterion)
404
+ __multi__(criterion, "$nor")
405
+ end
406
+
407
+ # Is the current selectable negating the next selection?
408
+ #
409
+ # @example Is the selectable negating?
410
+ # selectable.negating?
411
+ #
412
+ # @return [ true, false ] If the selectable is negating.
413
+ #
414
+ # @since 1.0.0
415
+ def negating?
416
+ !!negating
417
+ end
418
+
419
+ # Negate the next selection.
420
+ #
421
+ # @example Negate the selection.
422
+ # selectable.not.in(field: [ 1, 2 ])
423
+ #
424
+ # @example Add the $not criterion.
425
+ # selectable.not(name: /Bob/)
426
+ #
427
+ # @example Execute a $not in a where query.
428
+ # selectable.where(:field.not => /Bob/)
429
+ #
430
+ # @param [ Hash ] criterion The field/value pairs to negate.
431
+ #
432
+ # @return [ Selectable ] The negated selectable.
433
+ #
434
+ # @since 1.0.0
435
+ def not(*criterion)
436
+ if criterion.empty?
437
+ tap { |query| query.negating = true }
438
+ else
439
+ __override__(criterion.first, "$not")
440
+ end
441
+ end
442
+ key :not, :override, "$not"
443
+
444
+ # Adds $or selection to the selectable.
445
+ #
446
+ # @example Add the $or selection.
447
+ # selectable.or(field: 1, field: 2)
448
+ #
449
+ # @param [ Array ] criterion An array of hash criterion.
450
+ #
451
+ # @return [ Selectable ] The cloned selectable.
452
+ #
453
+ # @since 1.0.0
454
+ def or(*criterion)
455
+ __multi__(criterion, "$or")
456
+ end
457
+ alias :any_of :or
458
+
459
+ # Add a $size selection for array fields.
460
+ #
461
+ # @example Add the $size selection.
462
+ # selectable.with_size(field: 5)
463
+ #
464
+ # @note This method is named #with_size not to conflict with any existing
465
+ # #size method on enumerables or symbols.
466
+ #
467
+ # @example Execute an $size in a where query.
468
+ # selectable.where(:field.with_size => 10)
469
+ #
470
+ # @param [ Hash ] criterion The field/size pairs criterion.
471
+ #
472
+ # @return [ Selectable ] The cloned selectable.
473
+ #
474
+ # @since 1.0.0
475
+ def with_size(criterion = nil)
476
+ typed_override(criterion, "$size") do |value|
477
+ ::Integer.evolve(value)
478
+ end
479
+ end
480
+ key :with_size, :override, "$size" do |value|
481
+ ::Integer.evolve(value)
482
+ end
483
+
484
+ # Adds a $type selection to the selectable.
485
+ #
486
+ # @example Add the $type selection.
487
+ # selectable.with_type(field: 15)
488
+ #
489
+ # @example Execute an $type in a where query.
490
+ # selectable.where(:field.with_type => 15)
491
+ #
492
+ # @note http://vurl.me/PGOU contains a list of all types.
493
+ #
494
+ # @param [ Hash ] criterion The field/type pairs.
495
+ #
496
+ # @return [ Selectable ] The cloned selectable.
497
+ #
498
+ # @since 1.0.0
499
+ def with_type(criterion = nil)
500
+ typed_override(criterion, "$type") do |value|
501
+ ::Integer.evolve(value)
502
+ end
503
+ end
504
+ key :with_type, :override, "$type" do |value|
505
+ ::Integer.evolve(value)
506
+ end
507
+
508
+ # Construct a text search selector.
509
+ #
510
+ # @example Construct a text search selector.
511
+ # selectable.text_search("testing")
512
+ #
513
+ # @example Construct a text search selector with options.
514
+ # selectable.text_search("testing", :$language => "fr")
515
+ #
516
+ # @note Per https://docs.mongodb.com/manual/reference/operator/query/text/
517
+ # it is not currently possible to supply multiple text search
518
+ # conditions in a query. Mongoid will build such a query but the
519
+ # server will return an error when trying to execute it.
520
+ #
521
+ # @param [ String, Symbol ] terms A string of terms that MongoDB parses
522
+ # and uses to query the text index.
523
+ # @param [ Hash ] opts Text search options. See MongoDB documentation
524
+ # for options.
525
+ #
526
+ # @return [ Selectable ] The cloned selectable.
527
+ #
528
+ # @since 2.2.0
529
+ def text_search(terms, opts = nil)
530
+ clone.tap do |query|
531
+ if terms
532
+ criterion = {'$text' => { '$search' => terms }}
533
+ criterion['$text'].merge!(opts) if opts
534
+ if query.selector['$text']
535
+ # Per https://docs.mongodb.com/manual/reference/operator/query/text/
536
+ # multiple $text expressions are not currently supported by
537
+ # MongoDB server, but build the query correctly instead of
538
+ # overwriting previous text search condition with the currently
539
+ # given one.
540
+ Mongoid.logger.warn('Multiple $text expressions per query are not currently supported by the server')
541
+ query.selector = {'$and' => [query.selector]}.merge(criterion)
542
+ else
543
+ query.selector = query.selector.merge(criterion)
544
+ end
545
+ end
546
+ end
547
+ end
548
+
549
+ # This is the general entry point for most MongoDB queries. This either
550
+ # creates a standard field: value selection, and expanded selection with
551
+ # the use of hash methods, or a $where selection if a string is provided.
552
+ #
553
+ # @example Add a standard selection.
554
+ # selectable.where(name: "syd")
555
+ #
556
+ # @example Add a javascript selection.
557
+ # selectable.where("this.name == 'syd'")
558
+ #
559
+ # @param [ String, Hash ] criterion The javascript or standard selection.
560
+ #
561
+ # @return [ Selectable ] The cloned selectable.
562
+ #
563
+ # @since 1.0.0
564
+ def where(criterion = nil)
565
+ criterion.is_a?(String) ? js_query(criterion) : expr_query(criterion)
566
+ end
567
+
568
+ private
569
+
570
+ # Create the standard expression query.
571
+ #
572
+ # @api private
573
+ #
574
+ # @example Create the selection.
575
+ # selectable.expr_query(age: 50)
576
+ #
577
+ # @param [ Hash ] criterion The field/value pairs.
578
+ #
579
+ # @return [ Selectable ] The cloned selectable.
580
+ #
581
+ # @since 1.0.0
582
+ def expr_query(criterion)
583
+ selection(criterion) do |selector, field, value|
584
+ selector.merge!(field.__expr_part__(value.__expand_complex__, negating?))
585
+ end
586
+ end
587
+
588
+ # Force the values of the criterion to be evolved.
589
+ #
590
+ # @api private
591
+ #
592
+ # @example Force values to booleans.
593
+ # selectable.force_typing(criterion) do |val|
594
+ # Boolean.evolve(val)
595
+ # end
596
+ #
597
+ # @param [ Hash ] criterion The criterion.
598
+ #
599
+ # @since 1.0.0
600
+ def typed_override(criterion, operator)
601
+ if criterion
602
+ criterion.update_values do |value|
603
+ yield(value)
604
+ end
605
+ end
606
+ __override__(criterion, operator)
607
+ end
608
+
609
+ # Create a javascript selection.
610
+ #
611
+ # @api private
612
+ #
613
+ # @example Create the javascript selection.
614
+ # selectable.js_query("this.age == 50")
615
+ #
616
+ # @param [ String ] criterion The javascript as a string.
617
+ #
618
+ # @return [ Selectable ] The cloned selectable
619
+ #
620
+ # @since 1.0.0
621
+ def js_query(criterion)
622
+ clone.tap do |query|
623
+ query.selector.merge!("$where" => criterion)
624
+ end
625
+ end
626
+
627
+ # Take the provided criterion and store it as a selection in the query
628
+ # selector.
629
+ #
630
+ # @api private
631
+ #
632
+ # @example Store the selection.
633
+ # selectable.selection({ field: "value" })
634
+ #
635
+ # @param [ Hash ] criterion The selection to store.
636
+ #
637
+ # @return [ Selectable ] The cloned selectable.
638
+ #
639
+ # @since 1.0.0
640
+ def selection(criterion = nil)
641
+ clone.tap do |query|
642
+ if criterion
643
+ criterion.each_pair do |field, value|
644
+ yield(query.selector, field.is_a?(Key) ? field : field.to_s, value)
645
+ end
646
+ end
647
+ query.reset_strategies!
648
+ end
649
+ end
650
+
651
+ # Convert the criterion values to $in friendly values. This means you,
652
+ # array.
653
+ #
654
+ # @api private
655
+ #
656
+ # @example Convert all the values to arrays.
657
+ # selectable.with_array_values({ key: 1...4 })
658
+ #
659
+ # @param [ Hash ] criterion The criterion.
660
+ #
661
+ # @return [ Hash ] The $in friendly criterion (array values).
662
+ #
663
+ # @since 1.0.0
664
+ def with_array_values(criterion)
665
+ return nil unless criterion
666
+ criterion.each_pair do |key, value|
667
+ criterion[key] = value.__array__
668
+ end
669
+ end
670
+
671
+ class << self
672
+
673
+ # Get the methods on the selectable that can be forwarded to from a model.
674
+ #
675
+ # @example Get the forwardable methods.
676
+ # Selectable.forwardables
677
+ #
678
+ # @return [ Array<Symbol> ] The names of the forwardable methods.
679
+ #
680
+ # @since 1.0.0
681
+ def forwardables
682
+ public_instance_methods(false) -
683
+ [ :negating, :negating=, :negating?, :selector, :selector= ]
684
+ end
685
+ end
686
+ end
687
+ end
688
+ end
689
+ end