origin 0.0.0.alpha → 1.0.0.alpha
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.
- data/Rakefile +3 -0
- data/lib/origin.rb +3 -4
- data/lib/origin/extensions.rb +25 -0
- data/lib/origin/extensions/array.rb +153 -0
- data/lib/origin/extensions/big_decimal.rb +33 -0
- data/lib/origin/extensions/boolean.rb +30 -0
- data/lib/origin/extensions/date.rb +59 -0
- data/lib/origin/extensions/date_time.rb +44 -0
- data/lib/origin/extensions/hash.rb +180 -0
- data/lib/origin/extensions/nil_class.rb +82 -0
- data/lib/origin/extensions/numeric.rb +86 -0
- data/lib/origin/extensions/object.rb +182 -0
- data/lib/origin/extensions/range.rb +66 -0
- data/lib/origin/extensions/regexp.rb +41 -0
- data/lib/origin/extensions/set.rb +28 -0
- data/lib/origin/extensions/string.rb +100 -0
- data/lib/origin/extensions/symbol.rb +74 -0
- data/lib/origin/extensions/time.rb +44 -0
- data/lib/origin/extensions/time_with_zone.rb +50 -0
- data/lib/origin/forwardable.rb +57 -0
- data/lib/origin/key.rb +74 -0
- data/lib/origin/macroable.rb +23 -0
- data/lib/origin/mergeable.rb +226 -0
- data/lib/origin/optional.rb +314 -29
- data/lib/origin/options.rb +64 -1
- data/lib/origin/queryable.rb +55 -12
- data/lib/origin/selectable.rb +613 -0
- data/lib/origin/selector.rb +140 -1
- data/lib/origin/smash.rb +85 -0
- data/lib/origin/version.rb +1 -1
- metadata +94 -62
- data/lib/origin/ext.rb +0 -5
- data/lib/origin/ext/array.rb +0 -21
- data/lib/origin/ext/hash.rb +0 -38
- data/lib/origin/ext/nil.rb +0 -9
- data/lib/origin/ext/object.rb +0 -25
- data/lib/origin/optional/batch_size.rb +0 -11
- data/lib/origin/optional/hint.rb +0 -15
- data/lib/origin/optional/limit.rb +0 -11
- data/lib/origin/optional/max_scan.rb +0 -11
- data/lib/origin/optional/no_timeout.rb +0 -11
- data/lib/origin/optional/only.rb +0 -15
- data/lib/origin/optional/read.rb +0 -11
- data/lib/origin/optional/return_key.rb +0 -11
- data/lib/origin/optional/show_disk_loc.rb +0 -11
- data/lib/origin/optional/skip.rb +0 -11
- data/lib/origin/optional/slice.rb +0 -17
- data/lib/origin/optional/snapshot.rb +0 -13
- data/lib/origin/optional/transformer.rb +0 -11
- data/lib/origin/optional/without.rb +0 -15
- data/lib/origin/selection.rb +0 -59
- data/lib/origin/selection/all.rb +0 -18
- data/lib/origin/selection/and.rb +0 -11
- data/lib/origin/selection/between.rb +0 -16
- data/lib/origin/selection/elem_match.rb +0 -18
- data/lib/origin/selection/exists.rb +0 -18
- data/lib/origin/selection/gt.rb +0 -18
- data/lib/origin/selection/gte.rb +0 -18
- data/lib/origin/selection/in.rb +0 -18
- data/lib/origin/selection/key.rb +0 -20
- data/lib/origin/selection/lt.rb +0 -18
- data/lib/origin/selection/lte.rb +0 -18
- data/lib/origin/selection/max_distance.rb +0 -11
- data/lib/origin/selection/mod.rb +0 -18
- data/lib/origin/selection/ne.rb +0 -18
- data/lib/origin/selection/near.rb +0 -18
- data/lib/origin/selection/near_sphere.rb +0 -18
- data/lib/origin/selection/nin.rb +0 -18
- data/lib/origin/selection/nor.rb +0 -11
- data/lib/origin/selection/or.rb +0 -11
- data/lib/origin/selection/size.rb +0 -18
- data/lib/origin/selection/strategies.rb +0 -40
- data/lib/origin/selection/strategies/add.rb +0 -18
- data/lib/origin/selection/strategies/expanded.rb +0 -15
- data/lib/origin/selection/strategies/intersect.rb +0 -22
- data/lib/origin/selection/strategies/multi.rb +0 -21
- data/lib/origin/selection/strategies/override.rb +0 -19
- data/lib/origin/selection/strategies/union.rb +0 -22
- data/lib/origin/selection/type.rb +0 -18
- data/lib/origin/selection/where.rb +0 -29
- data/lib/origin/selection/within_box.rb +0 -18
- data/lib/origin/selection/within_circle.rb +0 -18
- data/lib/origin/selection/within_spherical_circle.rb +0 -18
data/lib/origin/options.rb
CHANGED
@@ -1,5 +1,68 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Origin
|
3
|
-
|
3
|
+
|
4
|
+
# The options is a hash representation of options passed to MongoDB queries,
|
5
|
+
# such as skip, limit, and sorting criteria.
|
6
|
+
class Options < Smash
|
7
|
+
|
8
|
+
# Store the value in the options for the provided key. The options will
|
9
|
+
# handle all necessary serialization and localization in this step.
|
10
|
+
#
|
11
|
+
# @example Store a value in the options.
|
12
|
+
# options.store(:key, "testing")
|
13
|
+
#
|
14
|
+
# @param [ String, Symbol ] key The name of the attribute.
|
15
|
+
# @param [ Object ] value The value to add.
|
16
|
+
#
|
17
|
+
# @return [ Object ] The stored object.
|
18
|
+
#
|
19
|
+
# @since 1.0.0
|
20
|
+
def store(key, value)
|
21
|
+
super(key, evolve(value))
|
22
|
+
end
|
23
|
+
alias :[]= :store
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Evolve a single key selection with various types of values.
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
# @example Evolve a simple selection.
|
32
|
+
# options.evolve(field, 5)
|
33
|
+
#
|
34
|
+
# @param [ Object ] value The value to serialize.
|
35
|
+
#
|
36
|
+
# @return [ Object ] The serialized object.
|
37
|
+
#
|
38
|
+
# @since 1.0.0
|
39
|
+
def evolve(value)
|
40
|
+
case value
|
41
|
+
when Hash
|
42
|
+
evolve_hash(value)
|
43
|
+
else
|
44
|
+
value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Evolve a single key selection with hash values.
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
#
|
52
|
+
# @example Evolve a simple selection.
|
53
|
+
# options.evolve(field, { "$gt" => 5 })
|
54
|
+
#
|
55
|
+
# @param [ Hash ] value The hash to serialize.
|
56
|
+
#
|
57
|
+
# @return [ Object ] The serialized hash.
|
58
|
+
#
|
59
|
+
# @since 1.0.0
|
60
|
+
def evolve_hash(value)
|
61
|
+
value.inject({}) do |hash, (field, _value)|
|
62
|
+
name, serializer = storage_pair(field)
|
63
|
+
hash[normalized_key(name, serializer)] = _value
|
64
|
+
hash
|
65
|
+
end
|
66
|
+
end
|
4
67
|
end
|
5
68
|
end
|
data/lib/origin/queryable.rb
CHANGED
@@ -1,31 +1,74 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "origin/
|
2
|
+
require "origin/extensions"
|
3
|
+
require "origin/key"
|
4
|
+
require "origin/macroable"
|
5
|
+
require "origin/mergeable"
|
6
|
+
require "origin/smash"
|
7
|
+
require "origin/optional"
|
8
|
+
require "origin/options"
|
9
|
+
require "origin/selectable"
|
10
|
+
require "origin/selector"
|
3
11
|
|
4
12
|
module Origin
|
5
13
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
14
|
+
# A queryable is any object that needs origin's dsl injected into it to build
|
15
|
+
# MongoDB queries. For example, a Mongoid::Criteria is an Origin::Queryable.
|
16
|
+
#
|
17
|
+
# @example Include queryable functionality.
|
18
|
+
# class Criteria
|
19
|
+
# include Origin::Queryable
|
20
|
+
# end
|
11
21
|
module Queryable
|
22
|
+
include Selectable
|
12
23
|
include Optional
|
13
|
-
include Selection
|
14
24
|
|
15
|
-
|
25
|
+
# @attribute [r] aliases The aliases.
|
26
|
+
# @attribute [r] serializers The serializers.
|
27
|
+
attr_reader :aliases, :serializers
|
16
28
|
|
29
|
+
# Is this queryable equal to another object? Is true if the selector and
|
30
|
+
# options are equal.
|
31
|
+
#
|
32
|
+
# @example Are the objects equal?
|
33
|
+
# queryable == criteria
|
34
|
+
#
|
35
|
+
# @param [ Object ] other The object to compare against.
|
36
|
+
#
|
37
|
+
# @return [ true, false ] If the objects are equal.
|
38
|
+
#
|
39
|
+
# @since 1.0.0
|
17
40
|
def ==(other)
|
18
|
-
return false unless other.is_a?(
|
41
|
+
return false unless other.is_a?(Queryable)
|
19
42
|
selector == other.selector && options == other.options
|
20
43
|
end
|
21
44
|
|
22
|
-
|
23
|
-
|
45
|
+
# Initialize the new queryable. Will yield itself to the block if a block
|
46
|
+
# is provided for objects that need additional behaviour.
|
47
|
+
#
|
48
|
+
# @example Initialize the queryable.
|
49
|
+
# Origin::Queryable.new
|
50
|
+
#
|
51
|
+
# @param [ Hash ] serializers The optional field serializers.
|
52
|
+
#
|
53
|
+
# @since 1.0.0
|
54
|
+
def initialize(aliases = {}, serializers = {})
|
55
|
+
@aliases, @serializers = aliases, serializers
|
56
|
+
@options, @selector =
|
57
|
+
Options.new(aliases, serializers), Selector.new(aliases, serializers)
|
24
58
|
yield(self) if block_given?
|
25
59
|
end
|
26
60
|
|
61
|
+
# Handle the creation of a copy via #clone or #dup.
|
62
|
+
#
|
63
|
+
# @example Handle copy initialization.
|
64
|
+
# queryable.initialize_copy(criteria)
|
65
|
+
#
|
66
|
+
# @param [ Queryable ] other The original copy.
|
67
|
+
#
|
68
|
+
# @since 1.0.0
|
27
69
|
def initialize_copy(other)
|
28
|
-
@options
|
70
|
+
@options = other.options.__deep_copy__
|
71
|
+
@selector = other.selector.__deep_copy__
|
29
72
|
end
|
30
73
|
end
|
31
74
|
end
|
@@ -0,0 +1,613 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Origin
|
3
|
+
|
4
|
+
# An origin queryable is selectable, in that it has the ability to select
|
5
|
+
# document from the database. The selectable module brings all functionality
|
6
|
+
# to the queryable that has to do with building MongoDB selectors.
|
7
|
+
module Selectable
|
8
|
+
include Mergeable
|
9
|
+
extend Macroable
|
10
|
+
|
11
|
+
# @attribute [rw] selector The query selector.
|
12
|
+
attr_accessor :selector
|
13
|
+
|
14
|
+
# Add the $all criterion.
|
15
|
+
#
|
16
|
+
# @example Add the criterion.
|
17
|
+
# queryable.all(field: [ 1, 2 ])
|
18
|
+
#
|
19
|
+
# @example Execute an $all in a where query.
|
20
|
+
# queryable.where(:field.all => [ 1, 2 ])
|
21
|
+
#
|
22
|
+
# @param [ Hash ] criterion The key value pairs for $all matching.
|
23
|
+
#
|
24
|
+
# @return [ Selectable ] The cloned queryable.
|
25
|
+
#
|
26
|
+
# @since 1.0.0
|
27
|
+
def all(criterion = nil)
|
28
|
+
send(strategy || :__union__, with_array_values(criterion), "$all")
|
29
|
+
end
|
30
|
+
alias :all_in :all
|
31
|
+
key :all, :union, "$all"
|
32
|
+
|
33
|
+
# Add the $and criterion.
|
34
|
+
#
|
35
|
+
# @example Add the criterion.
|
36
|
+
# queryable.and({ field: value }, { other: value })
|
37
|
+
#
|
38
|
+
# @param [ Array<Hash> ] criterion Multiple key/value pair matches that
|
39
|
+
# all must match to return results.
|
40
|
+
#
|
41
|
+
# @return [ Selectable ] The cloned queryable.
|
42
|
+
#
|
43
|
+
# @since 1.0.0
|
44
|
+
def and(*criterion)
|
45
|
+
__multi__(criterion, "$and")
|
46
|
+
end
|
47
|
+
alias :all_of :and
|
48
|
+
|
49
|
+
# Add the range selection.
|
50
|
+
#
|
51
|
+
# @example Match on results within a single range.
|
52
|
+
# queryable.between(field: 1..2)
|
53
|
+
#
|
54
|
+
# @example Match on results between multiple ranges.
|
55
|
+
# queryable.between(field: 1..2, other: 5..7)
|
56
|
+
#
|
57
|
+
# @param [ Hash ] criterion Multiple key/range pairs.
|
58
|
+
#
|
59
|
+
# @return [ Selectable ] The cloned queryable.
|
60
|
+
#
|
61
|
+
# @since 1.0.0
|
62
|
+
def between(criterion = nil)
|
63
|
+
selection(criterion) do |selector, field, value|
|
64
|
+
selector.store(
|
65
|
+
field,
|
66
|
+
{ "$gte" => value.min, "$lte" => value.max }
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Select with an $elemMatch.
|
72
|
+
#
|
73
|
+
# @example Add criterion for a single match.
|
74
|
+
# queryable.elem_match(field: { name: "value" })
|
75
|
+
#
|
76
|
+
# @example Add criterion for multiple matches.
|
77
|
+
# queryable.elem_match(
|
78
|
+
# field: { name: "value" },
|
79
|
+
# other: { name: "value"}
|
80
|
+
# )
|
81
|
+
#
|
82
|
+
# @example Execute an $elemMatch in a where query.
|
83
|
+
# queryable.where(:field.elem_match => { name: "value" })
|
84
|
+
#
|
85
|
+
# @param [ Hash ] criterion The field/match pairs.
|
86
|
+
#
|
87
|
+
# @return [ Selectable ] The cloned queryable.
|
88
|
+
#
|
89
|
+
# @since 1.0.0
|
90
|
+
def elem_match(criterion = nil)
|
91
|
+
__override__(criterion, "$elemMatch")
|
92
|
+
end
|
93
|
+
key :elem_match, :override, "$elemMatch"
|
94
|
+
|
95
|
+
# Add the $exists selection.
|
96
|
+
#
|
97
|
+
# @example Add a single selection.
|
98
|
+
# queryable.exists(field: true)
|
99
|
+
#
|
100
|
+
# @example Add multiple selections.
|
101
|
+
# queryable.exists(field: true, other: false)
|
102
|
+
#
|
103
|
+
# @example Execute an $exists in a where query.
|
104
|
+
# queryable.where(:field.exists => true)
|
105
|
+
#
|
106
|
+
# @param [ Hash ] criterion The field/boolean existence checks.
|
107
|
+
#
|
108
|
+
# @return [ Selectable ] The cloned queryable.
|
109
|
+
#
|
110
|
+
# @since 1.0.0
|
111
|
+
def exists(criterion = nil)
|
112
|
+
typed_override(criterion, "$exists") do |value|
|
113
|
+
::Boolean.evolve(value)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
key :exists, :override, "$exists" do |value|
|
117
|
+
::Boolean.evolve(value)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add the $gt criterion to the selector.
|
121
|
+
#
|
122
|
+
# @example Add the $gt criterion.
|
123
|
+
# queryable.gt(age: 60)
|
124
|
+
#
|
125
|
+
# @example Execute an $gt in a where query.
|
126
|
+
# queryable.where(:field.gt => 10)
|
127
|
+
#
|
128
|
+
# @param [ Hash ] criterion The field/value pairs to check.
|
129
|
+
#
|
130
|
+
# @return [ Selectable ] The cloned queryable.
|
131
|
+
#
|
132
|
+
# @since 1.0.0
|
133
|
+
def gt(criterion = nil)
|
134
|
+
__override__(criterion, "$gt")
|
135
|
+
end
|
136
|
+
key :gt, :override, "$gt"
|
137
|
+
|
138
|
+
# Add the $gte criterion to the selector.
|
139
|
+
#
|
140
|
+
# @example Add the $gte criterion.
|
141
|
+
# queryable.gte(age: 60)
|
142
|
+
#
|
143
|
+
# @example Execute an $gte in a where query.
|
144
|
+
# queryable.where(:field.gte => 10)
|
145
|
+
#
|
146
|
+
# @param [ Hash ] criterion The field/value pairs to check.
|
147
|
+
#
|
148
|
+
# @return [ Selectable ] The cloned queryable.
|
149
|
+
#
|
150
|
+
# @since 1.0.0
|
151
|
+
def gte(criterion = nil)
|
152
|
+
__override__(criterion, "$gte")
|
153
|
+
end
|
154
|
+
key :gte, :override, "$gte"
|
155
|
+
|
156
|
+
# Adds the $in selection to the queryable.
|
157
|
+
#
|
158
|
+
# @example Add $in selection on an array.
|
159
|
+
# queryable.in(age: [ 1, 2, 3 ])
|
160
|
+
#
|
161
|
+
# @example Add $in selection on a range.
|
162
|
+
# queryable.in(age: 18..24)
|
163
|
+
#
|
164
|
+
# @example Execute an $in in a where query.
|
165
|
+
# queryable.where(:field.in => [ 1, 2, 3 ])
|
166
|
+
#
|
167
|
+
# @param [ Hash ] criterion The field/value criterion pairs.
|
168
|
+
#
|
169
|
+
# @return [ Selectable ] The cloned queryable.
|
170
|
+
#
|
171
|
+
# @since 1.0.0
|
172
|
+
def in(criterion = nil)
|
173
|
+
send(strategy || :__intersect__, with_array_values(criterion), "$in")
|
174
|
+
end
|
175
|
+
alias :any_in :in
|
176
|
+
key :in, :intersect, "$in"
|
177
|
+
|
178
|
+
# Add the $lt criterion to the selector.
|
179
|
+
#
|
180
|
+
# @example Add the $lt criterion.
|
181
|
+
# queryable.lt(age: 60)
|
182
|
+
#
|
183
|
+
# @example Execute an $lt in a where query.
|
184
|
+
# queryable.where(:field.lt => 10)
|
185
|
+
#
|
186
|
+
# @param [ Hash ] criterion The field/value pairs to check.
|
187
|
+
#
|
188
|
+
# @return [ Selectable ] The cloned queryable.
|
189
|
+
#
|
190
|
+
# @since 1.0.0
|
191
|
+
def lt(criterion = nil)
|
192
|
+
__override__(criterion, "$lt")
|
193
|
+
end
|
194
|
+
key :lt, :override, "$lt"
|
195
|
+
|
196
|
+
# Add the $lte criterion to the selector.
|
197
|
+
#
|
198
|
+
# @example Add the $lte criterion.
|
199
|
+
# queryable.lte(age: 60)
|
200
|
+
#
|
201
|
+
# @example Execute an $lte in a where query.
|
202
|
+
# queryable.where(:field.lte => 10)
|
203
|
+
#
|
204
|
+
# @param [ Hash ] criterion The field/value pairs to check.
|
205
|
+
#
|
206
|
+
# @return [ Selectable ] The cloned queryable.
|
207
|
+
#
|
208
|
+
# @since 1.0.0
|
209
|
+
def lte(criterion = nil)
|
210
|
+
__override__(criterion, "$lte")
|
211
|
+
end
|
212
|
+
key :lte, :override, "$lte"
|
213
|
+
|
214
|
+
# Add a $maxDistance selection to the queryable.
|
215
|
+
#
|
216
|
+
# @example Add the $maxDistance selection.
|
217
|
+
# queryable.max_distance(location: 10)
|
218
|
+
#
|
219
|
+
# @param [ Hash ] criterion The field/distance pairs.
|
220
|
+
#
|
221
|
+
# @return [ Selectable ] The cloned queryable.
|
222
|
+
#
|
223
|
+
# @since 1.0.0
|
224
|
+
def max_distance(criterion = nil)
|
225
|
+
__add__(criterion, "$maxDistance")
|
226
|
+
end
|
227
|
+
|
228
|
+
# Adds $mod selection to the queryable.
|
229
|
+
#
|
230
|
+
# @example Add the $mod selection.
|
231
|
+
# queryable.mod(field: [ 10, 1 ])
|
232
|
+
#
|
233
|
+
# @example Execute an $mod in a where query.
|
234
|
+
# queryable.where(:field.mod => [ 10, 1 ])
|
235
|
+
#
|
236
|
+
# @param [ Hash ] criterion The field/mod selections.
|
237
|
+
#
|
238
|
+
# @return [ Selectable ] The cloned queryable.
|
239
|
+
#
|
240
|
+
# @since 1.0.0
|
241
|
+
def mod(criterion = nil)
|
242
|
+
__override__(criterion, "$mod")
|
243
|
+
end
|
244
|
+
key :mod, :override, "$mod"
|
245
|
+
|
246
|
+
# Adds $ne selection to the queryable.
|
247
|
+
#
|
248
|
+
# @example Query for a value $ne to something.
|
249
|
+
# queryable.ne(field: 10)
|
250
|
+
#
|
251
|
+
# @example Execute an $ne in a where query.
|
252
|
+
# queryable.where(:field.ne => "value")
|
253
|
+
#
|
254
|
+
# @param [ Hash ] criterion The field/ne selections.
|
255
|
+
#
|
256
|
+
# @return [ Selectable ] The cloned queryable.
|
257
|
+
#
|
258
|
+
# @since 1.0.0
|
259
|
+
def ne(criterion = nil)
|
260
|
+
__override__(criterion, "$ne")
|
261
|
+
end
|
262
|
+
alias :excludes :ne
|
263
|
+
key :ne, :override, "$ne"
|
264
|
+
|
265
|
+
# Adds a $near criterion to a geo selection.
|
266
|
+
#
|
267
|
+
# @example Add the $near selection.
|
268
|
+
# queryable.near(location: [ 23.1, 12.1 ])
|
269
|
+
#
|
270
|
+
# @example Execute an $near in a where query.
|
271
|
+
# queryable.where(:field.near => [ 23.2, 12.1 ])
|
272
|
+
#
|
273
|
+
# @param [ Hash ] criterion The field/location pair.
|
274
|
+
#
|
275
|
+
# @return [ Selectable ] The cloned queryable.
|
276
|
+
#
|
277
|
+
# @since 1.0.0
|
278
|
+
def near(criterion = nil)
|
279
|
+
__override__(criterion, "$near")
|
280
|
+
end
|
281
|
+
key :near, :override, "$near"
|
282
|
+
|
283
|
+
# Adds a $nearSphere criterion to a geo selection.
|
284
|
+
#
|
285
|
+
# @example Add the $nearSphere selection.
|
286
|
+
# queryable.near_sphere(location: [ 23.1, 12.1 ])
|
287
|
+
#
|
288
|
+
# @example Execute an $nearSphere in a where query.
|
289
|
+
# queryable.where(:field.near_sphere => [ 10.11, 3.22 ])
|
290
|
+
#
|
291
|
+
# @param [ Hash ] criterion The field/location pair.
|
292
|
+
#
|
293
|
+
# @return [ Selectable ] The cloned queryable.
|
294
|
+
#
|
295
|
+
# @since 1.0.0
|
296
|
+
def near_sphere(criterion = nil)
|
297
|
+
__override__(criterion, "$nearSphere")
|
298
|
+
end
|
299
|
+
key :near_sphere, :override, "$nearSphere"
|
300
|
+
|
301
|
+
# Adds the $nin selection to the queryable.
|
302
|
+
#
|
303
|
+
# @example Add $nin selection on an array.
|
304
|
+
# queryable.nin(age: [ 1, 2, 3 ])
|
305
|
+
#
|
306
|
+
# @example Add $nin selection on a range.
|
307
|
+
# queryable.nin(age: 18..24)
|
308
|
+
#
|
309
|
+
# @example Execute an $nin in a where query.
|
310
|
+
# queryable.where(:field.nin => [ 1, 2, 3 ])
|
311
|
+
#
|
312
|
+
# @param [ Hash ] criterion The field/value criterion pairs.
|
313
|
+
#
|
314
|
+
# @return [ Selectable ] The cloned queryable.
|
315
|
+
#
|
316
|
+
# @since 1.0.0
|
317
|
+
def nin(criterion = nil)
|
318
|
+
send(strategy || :__intersect__, with_array_values(criterion), "$nin")
|
319
|
+
end
|
320
|
+
alias :not_in :nin
|
321
|
+
key :nin, :intersect, "$nin"
|
322
|
+
|
323
|
+
# Adds $nor selection to the queryable.
|
324
|
+
#
|
325
|
+
# @example Add the $nor selection.
|
326
|
+
# queryable.nor(field: 1, field: 2)
|
327
|
+
#
|
328
|
+
# @param [ Array ] criterion An array of hash criterion.
|
329
|
+
#
|
330
|
+
# @return [ Selectable ] The cloned queryable.
|
331
|
+
#
|
332
|
+
# @since 1.0.0
|
333
|
+
def nor(*criterion)
|
334
|
+
__multi__(criterion, "$nor")
|
335
|
+
end
|
336
|
+
|
337
|
+
# Adds $or selection to the queryable.
|
338
|
+
#
|
339
|
+
# @example Add the $or selection.
|
340
|
+
# queryable.or(field: 1, field: 2)
|
341
|
+
#
|
342
|
+
# @param [ Array ] criterion An array of hash criterion.
|
343
|
+
#
|
344
|
+
# @return [ Selectable ] The cloned queryable.
|
345
|
+
#
|
346
|
+
# @since 1.0.0
|
347
|
+
def or(*criterion)
|
348
|
+
__multi__(criterion, "$or")
|
349
|
+
end
|
350
|
+
alias :any_of :or
|
351
|
+
|
352
|
+
# Add a $size selection for array fields.
|
353
|
+
#
|
354
|
+
# @example Add the $size selection.
|
355
|
+
# queryable.with_size(field: 5)
|
356
|
+
#
|
357
|
+
# @note This method is named #with_size not to conflict with any existing
|
358
|
+
# #size method on enumerables or symbols.
|
359
|
+
#
|
360
|
+
# @example Execute an $size in a where query.
|
361
|
+
# queryable.where(:field.with_size => 10)
|
362
|
+
#
|
363
|
+
# @param [ Hash ] criterion The field/size pairs criterion.
|
364
|
+
#
|
365
|
+
# @return [ Selectable ] The cloned queryable.
|
366
|
+
#
|
367
|
+
# @since 1.0.0
|
368
|
+
def with_size(criterion = nil)
|
369
|
+
typed_override(criterion, "$size") do |value|
|
370
|
+
::Integer.evolve(value)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
key :with_size, :override, "$size" do |value|
|
374
|
+
::Integer.evolve(value)
|
375
|
+
end
|
376
|
+
|
377
|
+
# Adds a $type selection to the queryable.
|
378
|
+
#
|
379
|
+
# @example Add the $type selection.
|
380
|
+
# queryable.with_type(field: 15)
|
381
|
+
#
|
382
|
+
# @example Execute an $type in a where query.
|
383
|
+
# queryable.where(:field.with_type => 15)
|
384
|
+
#
|
385
|
+
# @note http://vurl.me/PGOU contains a list of all types.
|
386
|
+
#
|
387
|
+
# @param [ Hash ] criterion The field/type pairs.
|
388
|
+
#
|
389
|
+
# @return [ Selectable ] The cloned queryable.
|
390
|
+
#
|
391
|
+
# @since 1.0.0
|
392
|
+
def with_type(criterion = nil)
|
393
|
+
typed_override(criterion, "$type") do |value|
|
394
|
+
::Integer.evolve(value)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
key :with_type, :override, "$type" do |value|
|
398
|
+
::Integer.evolve(value)
|
399
|
+
end
|
400
|
+
|
401
|
+
# This is the general entry point for most MongoDB queries. This either
|
402
|
+
# creates a standard field: value selection, and expanded selection with
|
403
|
+
# the use of hash methods, or a $where selection if a string is provided.
|
404
|
+
#
|
405
|
+
# @example Add a standard selection.
|
406
|
+
# queryable.where(name: "syd")
|
407
|
+
#
|
408
|
+
# @example Add a javascript selection.
|
409
|
+
# queryable.where("this.name == 'syd'")
|
410
|
+
#
|
411
|
+
# @param [ String, Hash ] criterion The javascript or standard selection.
|
412
|
+
#
|
413
|
+
# @return [ Selectable ] The cloned queryable.
|
414
|
+
#
|
415
|
+
# @since 1.0.0
|
416
|
+
def where(criterion = nil)
|
417
|
+
criterion.is_a?(String) ? js_query(criterion) : expr_query(criterion)
|
418
|
+
end
|
419
|
+
|
420
|
+
# Adds the $within/$box selection to the queryable.
|
421
|
+
#
|
422
|
+
# @example Add the selection.
|
423
|
+
# queryable.within_box(location: [[ 1, 10 ], [ 10, 1 ]])
|
424
|
+
#
|
425
|
+
# @example Execute an $within/$box in a where query.
|
426
|
+
# queryable.where(:field.within_box => [[ 1, 10 ], [ 10, 1 ]])
|
427
|
+
#
|
428
|
+
# @param [ Hash ] criterion The field/box corner criterion.
|
429
|
+
#
|
430
|
+
# @return [ Selectable ] The cloned queryable.
|
431
|
+
#
|
432
|
+
# @since 1.0.0
|
433
|
+
def within_box(criterion = nil)
|
434
|
+
__expanded__(criterion, "$within", "$box")
|
435
|
+
end
|
436
|
+
key :within_box, :expanded, "$within", "$box"
|
437
|
+
|
438
|
+
# Adds the $within/$center selection to the queryable.
|
439
|
+
#
|
440
|
+
# @example Add the selection.
|
441
|
+
# queryable.within_circle(location: [[ 1, 10 ], 25 ])
|
442
|
+
#
|
443
|
+
# @example Execute an $within/$center in a where query.
|
444
|
+
# queryable.where(:field.within_circle => [[ 1, 10 ], 25 ])
|
445
|
+
#
|
446
|
+
# @param [ Hash ] criterion The field/radius criterion.
|
447
|
+
#
|
448
|
+
# @return [ Selectable ] The cloned queryable.
|
449
|
+
#
|
450
|
+
# @since 1.0.0
|
451
|
+
def within_circle(criterion = nil)
|
452
|
+
__expanded__(criterion, "$within", "$center")
|
453
|
+
end
|
454
|
+
key :within_circle, :expanded, "$within", "$center"
|
455
|
+
|
456
|
+
# Adds the $within/$polygon selection to the queryable.
|
457
|
+
#
|
458
|
+
# @example Add the selection.
|
459
|
+
# queryable.within_polygon(
|
460
|
+
# location: [[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]
|
461
|
+
# )
|
462
|
+
#
|
463
|
+
# @example Execute an $within/$polygon in a where query.
|
464
|
+
# queryable.where(
|
465
|
+
# :field.within_polygon => [[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]
|
466
|
+
# )
|
467
|
+
#
|
468
|
+
# @param [ Hash ] criterion The field/polygon points criterion.
|
469
|
+
#
|
470
|
+
# @return [ Selectable ] The cloned queryable.
|
471
|
+
#
|
472
|
+
# @since 1.0.0
|
473
|
+
def within_polygon(criterion = nil)
|
474
|
+
__expanded__(criterion, "$within", "$polygon")
|
475
|
+
end
|
476
|
+
key :within_polygon, :expanded, "$within", "$polygon"
|
477
|
+
|
478
|
+
# Adds the $within/$centerSphere selection to the queryable.
|
479
|
+
#
|
480
|
+
# @example Add the selection.
|
481
|
+
# queryable.within_spherical_circle(location: [[ 1, 10 ], 25 ])
|
482
|
+
#
|
483
|
+
# @example Execute an $within/$centerSphere in a where query.
|
484
|
+
# queryable.where(:field.within_spherical_circle => [[ 1, 10 ], 25 ])
|
485
|
+
#
|
486
|
+
# @param [ Hash ] criterion The field/distance criterion.
|
487
|
+
#
|
488
|
+
# @return [ Selectable ] The cloned queryable.
|
489
|
+
#
|
490
|
+
# @since 1.0.0
|
491
|
+
def within_spherical_circle(criterion = nil)
|
492
|
+
__expanded__(criterion, "$within", "$centerSphere")
|
493
|
+
end
|
494
|
+
key :within_spherical_circle, :expanded, "$within", "$centerSphere"
|
495
|
+
|
496
|
+
private
|
497
|
+
|
498
|
+
# Create the standard expression query.
|
499
|
+
#
|
500
|
+
# @api private
|
501
|
+
#
|
502
|
+
# @example Create the selection.
|
503
|
+
# queryable.expr_query(age: 50)
|
504
|
+
#
|
505
|
+
# @param [ Hash ] criterion The field/value pairs.
|
506
|
+
#
|
507
|
+
# @return [ Selectable ] The cloned queryable.
|
508
|
+
#
|
509
|
+
# @since 1.0.0
|
510
|
+
def expr_query(criterion)
|
511
|
+
selection(criterion) do |selector, field, value|
|
512
|
+
selector.merge!(field.specify(value))
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
# Force the values of the criterion to be evolved.
|
517
|
+
#
|
518
|
+
# @api private
|
519
|
+
#
|
520
|
+
# @example Force values to booleans.
|
521
|
+
# queryable.force_typing(criterion) do |val|
|
522
|
+
# Boolean.evolve(val)
|
523
|
+
# end
|
524
|
+
#
|
525
|
+
# @param [ Hash ] criterion The criterion.
|
526
|
+
#
|
527
|
+
# @since 1.0.0
|
528
|
+
def typed_override(criterion, operator)
|
529
|
+
if criterion
|
530
|
+
criterion.update_values do |value|
|
531
|
+
yield(value)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
__override__(criterion, operator)
|
535
|
+
end
|
536
|
+
|
537
|
+
# Create a javascript selection.
|
538
|
+
#
|
539
|
+
# @api private
|
540
|
+
#
|
541
|
+
# @example Create the javascript selection.
|
542
|
+
# queryable.js_query("this.age == 50")
|
543
|
+
#
|
544
|
+
# @param [ String ] criterion The javascript as a string.
|
545
|
+
#
|
546
|
+
# @return [ Selectable ] The cloned queryable
|
547
|
+
#
|
548
|
+
# @since 1.0.0
|
549
|
+
def js_query(criterion)
|
550
|
+
clone.tap do |query|
|
551
|
+
query.selector.merge!("$where" => criterion)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
# Take the provided criterion and store it as a selection in the query
|
556
|
+
# selector.
|
557
|
+
#
|
558
|
+
# @api private
|
559
|
+
#
|
560
|
+
# @example Store the selection.
|
561
|
+
# selectable.selection({ field: "value" })
|
562
|
+
#
|
563
|
+
# @param [ Hash ] criterion The selection to store.
|
564
|
+
#
|
565
|
+
# @return [ Selectable ] The cloned queryable.
|
566
|
+
#
|
567
|
+
# @since 1.0.0
|
568
|
+
def selection(criterion = nil)
|
569
|
+
clone.tap do |query|
|
570
|
+
if criterion
|
571
|
+
criterion.each_pair do |field, value|
|
572
|
+
yield(query.selector, field.is_a?(Key) ? field : field.to_s, value)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
# Convert the criterion values to $in friendly values. This means you,
|
579
|
+
# array.
|
580
|
+
#
|
581
|
+
# @api private
|
582
|
+
#
|
583
|
+
# @example Convert all the values to arrays.
|
584
|
+
# queryable.with_array_values({ key: 1...4 })
|
585
|
+
#
|
586
|
+
# @param [ Hash ] criterion The criterion.
|
587
|
+
#
|
588
|
+
# @return [ Hash ] The $in friendly criterion (array values).
|
589
|
+
#
|
590
|
+
# @since 1.0.0
|
591
|
+
def with_array_values(criterion)
|
592
|
+
return nil unless criterion
|
593
|
+
criterion.each_pair do |key, value|
|
594
|
+
criterion[key] = value.__array__
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
class << self
|
599
|
+
|
600
|
+
# Get the methods on the selectable that can be forwarded to from a model.
|
601
|
+
#
|
602
|
+
# @example Get the forwardable methods.
|
603
|
+
# Selectable.forwardables
|
604
|
+
#
|
605
|
+
# @return [ Array<Symbol> ] The names of the forwardable methods.
|
606
|
+
#
|
607
|
+
# @since 1.0.0
|
608
|
+
def forwardables
|
609
|
+
public_instance_methods(false) - [ :selector, :selector= ]
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
end
|