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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/config/locales/en.yml +23 -16
- data/lib/mongoid.rb +4 -9
- data/lib/mongoid/atomic.rb +1 -1
- data/lib/mongoid/atomic/modifiers.rb +8 -12
- data/lib/mongoid/attributes.rb +9 -11
- data/lib/mongoid/attributes/dynamic.rb +5 -6
- data/lib/mongoid/attributes/nested.rb +1 -1
- data/lib/mongoid/attributes/processing.rb +4 -0
- data/lib/mongoid/attributes/readonly.rb +22 -0
- data/lib/mongoid/cacheable.rb +36 -0
- data/lib/mongoid/changeable.rb +37 -1
- data/lib/mongoid/clients.rb +0 -63
- data/lib/mongoid/clients/factory.rb +0 -2
- data/lib/mongoid/clients/options.rb +54 -249
- data/lib/mongoid/clients/storage_options.rb +1 -69
- data/lib/mongoid/composable.rb +26 -2
- data/lib/mongoid/config.rb +1 -1
- data/lib/mongoid/config/options.rb +1 -1
- data/lib/mongoid/contextual/aggregable/mongo.rb +1 -0
- data/lib/mongoid/contextual/atomic.rb +6 -9
- data/lib/mongoid/contextual/geo_near.rb +2 -3
- data/lib/mongoid/contextual/map_reduce.rb +97 -24
- data/lib/mongoid/contextual/memory.rb +7 -4
- data/lib/mongoid/contextual/mongo.rb +63 -54
- data/lib/mongoid/contextual/none.rb +2 -2
- data/lib/mongoid/copyable.rb +19 -19
- data/lib/mongoid/criteria.rb +5 -4
- data/lib/mongoid/criteria/findable.rb +2 -3
- data/lib/mongoid/criteria/includable.rb +63 -16
- data/lib/mongoid/criteria/marshalable.rb +2 -2
- data/lib/mongoid/criteria/modifiable.rb +17 -1
- data/lib/mongoid/criteria/options.rb +25 -0
- data/lib/mongoid/criteria/queryable.rb +86 -0
- data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
- data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
- data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
- data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
- data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
- data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
- data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
- data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
- data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +45 -0
- data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
- data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
- data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
- data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
- data/lib/mongoid/criteria/queryable/key.rb +103 -0
- data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
- data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
- data/lib/mongoid/criteria/queryable/optional.rb +411 -0
- data/lib/mongoid/criteria/queryable/options.rb +136 -0
- data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
- data/lib/mongoid/criteria/queryable/selector.rb +196 -0
- data/lib/mongoid/criteria/queryable/smash.rb +103 -0
- data/lib/mongoid/document.rb +9 -23
- data/lib/mongoid/errors.rb +2 -1
- data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
- data/lib/mongoid/errors/delete_restriction.rb +2 -2
- data/lib/mongoid/errors/invalid_field.rb +2 -2
- data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
- data/lib/mongoid/errors/invalid_relation.rb +66 -0
- data/lib/mongoid/errors/inverse_not_found.rb +1 -1
- data/lib/mongoid/errors/mongoid_error.rb +1 -1
- data/lib/mongoid/evolvable.rb +1 -1
- data/lib/mongoid/extensions.rb +0 -5
- data/lib/mongoid/extensions/big_decimal.rb +17 -8
- data/lib/mongoid/extensions/date.rb +4 -1
- data/lib/mongoid/extensions/hash.rb +2 -3
- data/lib/mongoid/extensions/object.rb +2 -2
- data/lib/mongoid/extensions/string.rb +4 -3
- data/lib/mongoid/extensions/time.rb +5 -2
- data/lib/mongoid/factory.rb +1 -0
- data/lib/mongoid/fields/foreign_key.rb +2 -2
- data/lib/mongoid/fields/localized.rb +3 -8
- data/lib/mongoid/fields/validators/macro.rb +18 -0
- data/lib/mongoid/findable.rb +3 -3
- data/lib/mongoid/indexable.rb +17 -16
- data/lib/mongoid/indexable/specification.rb +1 -1
- data/lib/mongoid/indexable/validators/options.rb +1 -2
- data/lib/mongoid/interceptable.rb +6 -17
- data/lib/mongoid/loggable.rb +1 -1
- data/lib/mongoid/matchable.rb +3 -10
- data/lib/mongoid/matchable/gt.rb +2 -0
- data/lib/mongoid/matchable/gte.rb +2 -0
- data/lib/mongoid/matchable/lt.rb +2 -0
- data/lib/mongoid/matchable/lte.rb +2 -0
- data/lib/mongoid/persistable.rb +6 -5
- data/lib/mongoid/persistable/creatable.rb +2 -0
- data/lib/mongoid/persistable/deletable.rb +7 -3
- data/lib/mongoid/persistable/settable.rb +3 -16
- data/lib/mongoid/persistable/updatable.rb +10 -12
- data/lib/mongoid/persistence_context.rb +216 -0
- data/lib/mongoid/query_cache.rb +5 -30
- data/lib/mongoid/relations/accessors.rb +6 -2
- data/lib/mongoid/relations/auto_save.rb +12 -4
- data/lib/mongoid/relations/bindings/embedded/in.rb +4 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +8 -1
- data/lib/mongoid/relations/bindings/embedded/one.rb +10 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +4 -0
- data/lib/mongoid/relations/builders.rb +2 -2
- data/lib/mongoid/relations/builders/embedded/one.rb +1 -1
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
- data/lib/mongoid/relations/conversions.rb +1 -1
- data/lib/mongoid/relations/counter_cache.rb +28 -18
- data/lib/mongoid/relations/eager.rb +19 -7
- data/lib/mongoid/relations/eager/base.rb +5 -5
- data/lib/mongoid/relations/embedded/batchable.rb +9 -33
- data/lib/mongoid/relations/embedded/in.rb +16 -2
- data/lib/mongoid/relations/embedded/many.rb +23 -8
- data/lib/mongoid/relations/embedded/one.rb +17 -2
- data/lib/mongoid/relations/macros.rb +9 -2
- data/lib/mongoid/relations/metadata.rb +3 -3
- data/lib/mongoid/relations/nested_builder.rb +1 -1
- data/lib/mongoid/relations/options.rb +2 -2
- data/lib/mongoid/relations/proxy.rb +2 -33
- data/lib/mongoid/relations/referenced/in.rb +23 -11
- data/lib/mongoid/relations/referenced/many.rb +24 -16
- data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
- data/lib/mongoid/relations/referenced/one.rb +17 -1
- data/lib/mongoid/relations/reflections.rb +3 -5
- data/lib/mongoid/relations/touchable.rb +1 -1
- data/lib/mongoid/reloadable.rb +1 -1
- data/lib/mongoid/scopable.rb +3 -3
- data/lib/mongoid/serializable.rb +2 -3
- data/lib/mongoid/tasks/database.rb +1 -2
- data/lib/mongoid/threaded.rb +4 -4
- data/lib/mongoid/traversable.rb +1 -1
- data/lib/mongoid/validatable.rb +1 -1
- data/lib/mongoid/validatable/macros.rb +2 -4
- data/lib/mongoid/validatable/uniqueness.rb +1 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -7
- data/spec/app/models/album.rb +5 -1
- data/spec/app/models/artist.rb +21 -0
- data/spec/app/models/band.rb +0 -1
- data/spec/app/models/church.rb +0 -2
- data/spec/app/models/ordered_post.rb +5 -0
- data/spec/app/models/oscar.rb +1 -2
- data/spec/app/models/person.rb +3 -1
- data/spec/app/models/post.rb +0 -1
- data/spec/app/models/princess.rb +2 -0
- data/spec/app/models/record.rb +1 -0
- data/spec/app/models/thing.rb +1 -1
- data/spec/config/mongoid.yml +1 -5
- data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
- data/spec/mongoid/atomic_spec.rb +17 -17
- data/spec/mongoid/attributes/nested_spec.rb +14 -14
- data/spec/mongoid/attributes/readonly_spec.rb +87 -44
- data/spec/mongoid/attributes_spec.rb +63 -0
- data/spec/mongoid/cacheable_spec.rb +112 -0
- data/spec/mongoid/changeable_spec.rb +58 -0
- data/spec/mongoid/clients/factory_spec.rb +3 -11
- data/spec/mongoid/clients/options_spec.rb +378 -96
- data/spec/mongoid/clients_spec.rb +207 -170
- data/spec/mongoid/composable_spec.rb +7 -0
- data/spec/mongoid/config_spec.rb +41 -21
- data/spec/mongoid/contextual/atomic_spec.rb +77 -343
- data/spec/mongoid/contextual/map_reduce_spec.rb +119 -111
- data/spec/mongoid/contextual/memory_spec.rb +56 -316
- data/spec/mongoid/contextual/mongo_spec.rb +104 -378
- data/spec/mongoid/copyable_spec.rb +8 -15
- data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
- data/spec/mongoid/criteria/options_spec.rb +29 -0
- data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
- data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
- data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
- data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
- data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
- data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
- data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
- data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
- data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
- data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
- data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
- data/spec/mongoid/{extensions/origin/regexp_raw_spec.rb → criteria/queryable/extensions/regexp_spec.rb} +21 -20
- data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
- data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
- data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
- data/spec/mongoid/criteria/queryable/optional_spec.rb +1786 -0
- data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
- data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
- data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +4159 -0
- data/spec/mongoid/criteria/queryable/selector_spec.rb +778 -0
- data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
- data/spec/mongoid/criteria_spec.rb +45 -63
- data/spec/mongoid/document_spec.rb +21 -88
- data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
- data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
- data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
- data/spec/mongoid/extensions/date_spec.rb +2 -6
- data/spec/mongoid/extensions/date_time_spec.rb +2 -6
- data/spec/mongoid/extensions/float_spec.rb +8 -1
- data/spec/mongoid/extensions/integer_spec.rb +8 -1
- data/spec/mongoid/extensions/object_spec.rb +11 -0
- data/spec/mongoid/extensions/string_spec.rb +21 -0
- data/spec/mongoid/extensions/time_spec.rb +4 -8
- data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
- data/spec/mongoid/fields/localized_spec.rb +0 -91
- data/spec/mongoid/findable_spec.rb +46 -1
- data/spec/mongoid/indexable_spec.rb +6 -46
- data/spec/mongoid/interceptable_spec.rb +49 -10
- data/spec/mongoid/matchable/gt_spec.rb +11 -0
- data/spec/mongoid/matchable/gte_spec.rb +10 -0
- data/spec/mongoid/matchable/lt_spec.rb +11 -0
- data/spec/mongoid/matchable/lte_spec.rb +11 -0
- data/spec/mongoid/matchable_spec.rb +1 -51
- data/spec/mongoid/persistable/creatable_spec.rb +2 -2
- data/spec/mongoid/persistable/deletable_spec.rb +1 -1
- data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
- data/spec/mongoid/persistable/savable_spec.rb +30 -30
- data/spec/mongoid/persistable/settable_spec.rb +0 -185
- data/spec/mongoid/persistable/updatable_spec.rb +166 -5
- data/spec/mongoid/persistence_context_spec.rb +654 -0
- data/spec/mongoid/positional_spec.rb +10 -10
- data/spec/mongoid/query_cache_spec.rb +89 -65
- data/spec/mongoid/relations/accessors_spec.rb +1 -1
- data/spec/mongoid/relations/auto_save_spec.rb +39 -6
- data/spec/mongoid/relations/builders_spec.rb +37 -10
- data/spec/mongoid/relations/counter_cache_spec.rb +64 -15
- data/spec/mongoid/relations/cyclic_spec.rb +0 -22
- data/spec/mongoid/relations/embedded/many_spec.rb +9 -41
- data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
- data/spec/mongoid/relations/macros_spec.rb +395 -7
- data/spec/mongoid/relations/proxy_spec.rb +3 -1
- data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
- data/spec/mongoid/relations/referenced/many_spec.rb +6 -29
- data/spec/mongoid/relations/referenced/many_to_many_spec.rb +6 -29
- data/spec/mongoid/relations/reflections_spec.rb +9 -9
- data/spec/mongoid/reloadable_spec.rb +51 -0
- data/spec/mongoid/scopable_spec.rb +0 -12
- data/spec/mongoid/serializable_spec.rb +0 -50
- data/spec/mongoid/validatable/presence_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +16 -9
- data/spec/mongoid/validatable_spec.rb +16 -0
- data/spec/spec_helper.rb +10 -10
- metadata +536 -479
- metadata.gz.sig +0 -0
- data/lib/mongoid/clients/thread_options.rb +0 -19
- data/lib/mongoid/errors/in_memory_collation_not_supported.rb +0 -20
- data/lib/mongoid/extensions/decimal128.rb +0 -39
- data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
- data/lib/mongoid/matchable/regexp.rb +0 -27
- data/spec/app/models/post_genre.rb +0 -6
- data/spec/mongoid/extensions/decimal128_spec.rb +0 -44
- 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
|