mongoid 5.4.1 → 6.0.0.beta

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