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.
Files changed (83) hide show
  1. data/Rakefile +3 -0
  2. data/lib/origin.rb +3 -4
  3. data/lib/origin/extensions.rb +25 -0
  4. data/lib/origin/extensions/array.rb +153 -0
  5. data/lib/origin/extensions/big_decimal.rb +33 -0
  6. data/lib/origin/extensions/boolean.rb +30 -0
  7. data/lib/origin/extensions/date.rb +59 -0
  8. data/lib/origin/extensions/date_time.rb +44 -0
  9. data/lib/origin/extensions/hash.rb +180 -0
  10. data/lib/origin/extensions/nil_class.rb +82 -0
  11. data/lib/origin/extensions/numeric.rb +86 -0
  12. data/lib/origin/extensions/object.rb +182 -0
  13. data/lib/origin/extensions/range.rb +66 -0
  14. data/lib/origin/extensions/regexp.rb +41 -0
  15. data/lib/origin/extensions/set.rb +28 -0
  16. data/lib/origin/extensions/string.rb +100 -0
  17. data/lib/origin/extensions/symbol.rb +74 -0
  18. data/lib/origin/extensions/time.rb +44 -0
  19. data/lib/origin/extensions/time_with_zone.rb +50 -0
  20. data/lib/origin/forwardable.rb +57 -0
  21. data/lib/origin/key.rb +74 -0
  22. data/lib/origin/macroable.rb +23 -0
  23. data/lib/origin/mergeable.rb +226 -0
  24. data/lib/origin/optional.rb +314 -29
  25. data/lib/origin/options.rb +64 -1
  26. data/lib/origin/queryable.rb +55 -12
  27. data/lib/origin/selectable.rb +613 -0
  28. data/lib/origin/selector.rb +140 -1
  29. data/lib/origin/smash.rb +85 -0
  30. data/lib/origin/version.rb +1 -1
  31. metadata +94 -62
  32. data/lib/origin/ext.rb +0 -5
  33. data/lib/origin/ext/array.rb +0 -21
  34. data/lib/origin/ext/hash.rb +0 -38
  35. data/lib/origin/ext/nil.rb +0 -9
  36. data/lib/origin/ext/object.rb +0 -25
  37. data/lib/origin/optional/batch_size.rb +0 -11
  38. data/lib/origin/optional/hint.rb +0 -15
  39. data/lib/origin/optional/limit.rb +0 -11
  40. data/lib/origin/optional/max_scan.rb +0 -11
  41. data/lib/origin/optional/no_timeout.rb +0 -11
  42. data/lib/origin/optional/only.rb +0 -15
  43. data/lib/origin/optional/read.rb +0 -11
  44. data/lib/origin/optional/return_key.rb +0 -11
  45. data/lib/origin/optional/show_disk_loc.rb +0 -11
  46. data/lib/origin/optional/skip.rb +0 -11
  47. data/lib/origin/optional/slice.rb +0 -17
  48. data/lib/origin/optional/snapshot.rb +0 -13
  49. data/lib/origin/optional/transformer.rb +0 -11
  50. data/lib/origin/optional/without.rb +0 -15
  51. data/lib/origin/selection.rb +0 -59
  52. data/lib/origin/selection/all.rb +0 -18
  53. data/lib/origin/selection/and.rb +0 -11
  54. data/lib/origin/selection/between.rb +0 -16
  55. data/lib/origin/selection/elem_match.rb +0 -18
  56. data/lib/origin/selection/exists.rb +0 -18
  57. data/lib/origin/selection/gt.rb +0 -18
  58. data/lib/origin/selection/gte.rb +0 -18
  59. data/lib/origin/selection/in.rb +0 -18
  60. data/lib/origin/selection/key.rb +0 -20
  61. data/lib/origin/selection/lt.rb +0 -18
  62. data/lib/origin/selection/lte.rb +0 -18
  63. data/lib/origin/selection/max_distance.rb +0 -11
  64. data/lib/origin/selection/mod.rb +0 -18
  65. data/lib/origin/selection/ne.rb +0 -18
  66. data/lib/origin/selection/near.rb +0 -18
  67. data/lib/origin/selection/near_sphere.rb +0 -18
  68. data/lib/origin/selection/nin.rb +0 -18
  69. data/lib/origin/selection/nor.rb +0 -11
  70. data/lib/origin/selection/or.rb +0 -11
  71. data/lib/origin/selection/size.rb +0 -18
  72. data/lib/origin/selection/strategies.rb +0 -40
  73. data/lib/origin/selection/strategies/add.rb +0 -18
  74. data/lib/origin/selection/strategies/expanded.rb +0 -15
  75. data/lib/origin/selection/strategies/intersect.rb +0 -22
  76. data/lib/origin/selection/strategies/multi.rb +0 -21
  77. data/lib/origin/selection/strategies/override.rb +0 -19
  78. data/lib/origin/selection/strategies/union.rb +0 -22
  79. data/lib/origin/selection/type.rb +0 -18
  80. data/lib/origin/selection/where.rb +0 -29
  81. data/lib/origin/selection/within_box.rb +0 -18
  82. data/lib/origin/selection/within_circle.rb +0 -18
  83. data/lib/origin/selection/within_spherical_circle.rb +0 -18
@@ -1,5 +1,68 @@
1
1
  # encoding: utf-8
2
2
  module Origin
3
- class Options < Hash
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
@@ -1,31 +1,74 @@
1
1
  # encoding: utf-8
2
- require "origin/ext"
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
- autoload :Optional, "origin/optional"
7
- autoload :Options, "origin/options"
8
- autoload :Selection, "origin/selection"
9
- autoload :Selector, "origin/selector"
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
- attr_reader :options, :selector
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?(Query)
41
+ return false unless other.is_a?(Queryable)
19
42
  selector == other.selector && options == other.options
20
43
  end
21
44
 
22
- def initialize
23
- @options, @selector = Options.new, Selector.new
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, @selector = other.options.deep_copy, other.selector.deep_copy
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