orchestrate 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7d5c6bc09a49e08d464387e25b98ae9777bbf93
4
- data.tar.gz: 72a68c6e456c4920c9875e7e3f7108b29bd59d12
3
+ metadata.gz: 052b46ffb077d9256c3626b2d2fe1d6618c0f3c9
4
+ data.tar.gz: 34375247e7fc3ce08d2f836df6e0df7f778273f7
5
5
  SHA512:
6
- metadata.gz: a8a2a5f7124cd557dc4a3ed3a4fc9d71064494e8241ae87409c8fcfd2fe40236eaebd0171e54c5c2ab22bcba03a1e33bb8a81171681a205edb4c153f747ef2a9
7
- data.tar.gz: 753527cab83aac5537fd178ac976cf704f6c173c63b0b64a2f9c9fdd859c30d18e6d8cd34cb92bcc4b6bb2aa3643e66f47918193d561c65e88b2f591b82f802e
6
+ metadata.gz: 99d0edff2baf770cf3c2173c9245bb42957dee1a92c1d4abca2c24bc8b510569bf6bda09159c2761bbd64d9631cdfd1d2273166597dccb11a12f85c1a110fb3d
7
+ data.tar.gz: 6afa7091564272f7f22d0b4d173b03cd76815a63992876aaccadd3b1c08ab11a38a6c20e884e2feafcf8e339651f0bf0b623339927de6a7e6b1e8c5fd27f39a3
data/README.md CHANGED
@@ -65,20 +65,20 @@ jill.add('favorite_food', 'Pizza').remove('years_to_live').update()
65
65
 
66
66
  #### Searching, Sorting for KeyValues
67
67
  ```ruby
68
- users.search("name:Jill") # returns users with name "Jill"
69
- users.search("name:Jill").order(:created_at) # returns users with name "Jill" in ascending order
68
+ users.search("name:Jill").find # returns users with name "Jill"
69
+ users.search("name:Jill").order(:created_at).find # returns users with name "Jill" in ascending order
70
70
  ```
71
71
 
72
72
  The `order` method accepts multiple arguments, allowing you to sort search results based multiple parameters. When providing multiple field names to sort by each even-numbered argument must be either `:asc` or `:desc`.
73
73
 
74
74
  ```ruby
75
- users.search("location: Portland").order(:name, :asc, :rank, :desc)
75
+ users.search("location: Portland").order(:name, :asc, :rank, :desc).find
76
76
  ```
77
77
 
78
78
  By default, odd-numbered arguments will be sorted in ascending order.
79
79
  ```ruby
80
- users.search("location: Portland").order(:name) # returns users in ascending order by name
81
- users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at) # :created_at argument defaults to :asc
80
+ users.search("location: Portland").order(:name).find # returns users in ascending order by name
81
+ users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at).find # :created_at argument defaults to :asc
82
82
  ```
83
83
 
84
84
  ### Geo Queries
@@ -87,13 +87,56 @@ users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at)
87
87
  cafes = app[:cafes]
88
88
 
89
89
  # Find cafes near a given geographic point
90
- cafes.near(:location, 12.56, 19.443, 4, 'mi') # returns cafes in a 4 mile radius of given latitude, longitude
90
+ cafes.near(:location, 12.56, 19.443, 4, 'mi').find # returns cafes in a 4 mile radius of given latitude, longitude
91
91
 
92
92
  # Sort nearby cafes by distance
93
- cafes.near(:location, 12.56, 19.443, 4, 'mi').order(:distance) # returns nearby cafes in ascending order (closest to farthest)
93
+ cafes.near(:location, 12.56, 19.443, 4, 'mi').order(:distance).find # returns nearby cafes in ascending order (closest to farthest)
94
94
 
95
95
  # Find cafes in a given area using a bounding box
96
- cafes.in(:location, {north:12.5, east:57, south:12, west:56}) # returns all cafes within specified bounding box
96
+ cafes.in(:location, {north:12.5, east:57, south:12, west:56}).find # returns all cafes within specified bounding box
97
+ ```
98
+
99
+ ### Aggregate Functions
100
+
101
+ ```ruby
102
+ # Statistical Aggregate
103
+ products.search("*").aggregate # Start the search query and aggregate param builder
104
+ .stats("price") # statistics on the price field for products matching the query
105
+ .find # return SearchResults object to execute our query
106
+ .each_aggregate # return enumerator for iterating over each aggregate result
107
+
108
+ # Range Aggregate
109
+ products.search("*").aggregate # Start the search query and aggregate param builder
110
+ .range("num_sold") # set field for range function
111
+ .below(99) # count items with num_sold value below 99
112
+ .between(1, 10) # count items with num_sold value between 1 & 10
113
+ .above(5) # count items with num_sold value above 5
114
+ .find # return SearchResults object to execute our query
115
+ .each_aggregate # return enumerator for iterating over each aggregate result
116
+
117
+ # Distance Aggregate
118
+ cafes.near(:location, 12, 19, 4, 'mi').aggregate # Start the near search query and aggregate param builder
119
+ .distance("location") # set field for distance function
120
+ .below(3) # count cafes within 3 miles of given geographic point
121
+ .between(3, 4) # count cafes between 3 and 4 miles of given geographic point
122
+ .above(1) # count cafes beyond 1 mile of given geographic point
123
+ .find # return SearchResults object to execute our query
124
+ .each_aggregate # return enumerator for iterating over each aggregate result
125
+
126
+ # Time-Series Aggregate
127
+ # Accepted intervals are: year, quarter, month, week, day, and hour
128
+ comments.search("*").aggregate # Start the near search query and aggregate param builder
129
+ .time_series("posted", "day") # get count of comments posted by day
130
+ .find # return SearchResults object to execute our query
131
+ .each_aggregate # return enumerator for iterating over each aggregate result
132
+
133
+ # Multiple Aggregate Functions
134
+ products.search("*").aggregate # Start the search query and aggregate param builder
135
+ .stats("price") # statistics on the price field for products matching the query
136
+ .range("num_sold") # set field for range function
137
+ .below(99) # count items with num_sold value below 99
138
+ .find # return SearchResults object to execute our query
139
+ .each_aggregate # return enumerator for iterating over each aggregate result
97
140
  ```
98
141
 
99
142
  ### Method Client use
@@ -173,6 +216,82 @@ query = "value:IN:{ north:12.5 east:57 south:12 west:56 }"
173
216
  client.search(:cafes, query)
174
217
  ```
175
218
 
219
+ ### Aggregate Functions
220
+
221
+ ```ruby
222
+ # Statistical Aggregate
223
+ query = "*"
224
+
225
+ options = {
226
+ aggregate: "value.price:stats" # get statistics for price across all items in the collection
227
+ }
228
+
229
+ response = client.search(:products, query, options)
230
+
231
+ response.aggregates # return aggregate results
232
+
233
+
234
+ # Range Aggregate
235
+ query = "*"
236
+
237
+ options = {
238
+ # count items with num_sold below 99, in between 1 & 10, and above 5
239
+ aggregate: "value.num_sold:range:*~99:1~10:5~*"
240
+ }
241
+
242
+ response = client.search(:products, query, options)
243
+
244
+ response.aggregates # return aggregate results
245
+
246
+
247
+ # Distance Aggregate
248
+ coords = {
249
+ lat: 12.56,
250
+ lon: 19.443,
251
+ dist: '4mi' # Define size of search radius for NEAR query
252
+ }
253
+
254
+ options = {
255
+ # count cafes near give geographic point within 3 miles, between 3 and 4 miles, and beyond 1 mile
256
+ aggregate: "value.location:distance:*~3:3~4:1~*"
257
+ }
258
+
259
+ # Distance Aggregates require a near clause in the search query
260
+ query = "value.location:NEAR:{lat:#{coords.lat} lon:#{coords.lon} dist:#{coords.dist}}"
261
+
262
+ response = client.search(:cafes, query, options)
263
+
264
+ response.aggregates # return aggregate results
265
+
266
+
267
+ # Time-Series Aggregate
268
+ # Accepted intervals are: year, quarter, month, week, day, and hour
269
+
270
+ options = {
271
+ # get count of comments posted by day
272
+ aggregate: "value.posted:time_series:day"
273
+ }
274
+
275
+ query = "*"
276
+
277
+ response = client.search(:comments, query, options)
278
+
279
+ response.aggregates # return aggregate results
280
+
281
+
282
+ # Multiple Aggregate Functions
283
+ options = {
284
+ # multiple aggregate params are separated by commas
285
+ aggregate: "value.price:stats,value.num_sold:stats,value.num_sold:range:*~99:1~10:5~*"
286
+ }
287
+
288
+ query = "*"
289
+
290
+ response = client.search(:products, query, options)
291
+
292
+ response.aggregates # return aggregate results
293
+ ```
294
+
176
295
  ### Examples and Documentation
177
296
 
178
297
  There are more examples at [Orchestrate's API Documentation][apidoc] and documentation in the [rdoc][].
@@ -277,10 +396,19 @@ end
277
396
 
278
397
  ## Release Notes
279
398
 
399
+ ### January 7, 2014: release 0.11.0
400
+ - **BACKWARDS-INCOMPATIBLE** `Orchestrate::Collection` searches require `#find` method at the end of the method call/chain. Example: `users.search('foo').find`.
401
+ - Implement `Orchestrate::Search` module, refactor functionality of prior `Orchestrate::Collection::SearchResults`.
402
+ - Implement results enumeration & request firing functionality in prior `Orchestrate::Collection::SearchResults` to `Orchestrate::Search::Results`
403
+ - Implement `Search::QueryBuilder` to construct `Collection` search queries.
404
+ - Implement `Search::AggregateBuilder` to construct aggregate params on `Collection` search queries.
405
+ - Implement `Search::StatsBuilder`, `Search::RangeBuilder`, `Search::DistanceBuilder`, & `Search::TimeSeriesBuilder` to construct aggregate function clauses for aggregate params.
406
+ - Implement `Search::AggregateResult` objects to repesent aggregate results returned from `Collection` search.
407
+
280
408
  ### December 11, 2014: release 0.10.0
281
409
  - **BACKWARDS-INCOMPATIBLE** Prior `KeyValue#update` & `KeyValue#update!` renamed to `KeyValue#set` & `KeyValue#set!`. `KeyValue#update` now used after `PATCH` operations to fire the request.
282
410
  - Implement `Collection#near` & `Collection#in`, allowing `Collection` to perform geo queries.
283
- - Implement `Client#patch`, `Client#patch_merge`, allowing `Client` to perform subdocument updates through `PATCH` requests.
411
+ - Implement `Client#patch`, `Client#patch_merge`, allowing `Client` to perform partial updates through `PATCH` requests.
284
412
  - Implement `KeyValue::OperationSet`, allowing a set of `PATCH` operations to be built by `KeyValue` through `KeyValue#add`, `KeyValue#remove`, `KeyValue#replace`, `KeyValue#move`, `KeyValue#copy`, `KeyValue#increment`, `KeyValue#decrement`, & `KeyValue#test`. The `KeyValue::OperationSet` is fired by ending the chain with `KeyValue#update`.
285
413
  - Implement `KeyValue#merge`, allowing `KeyValue` to merge partial values into existing keys through `PATCH` requests.
286
414
 
@@ -346,4 +474,4 @@ end
346
474
  ### May 21, 2014: release 0.5.0
347
475
  Initial Port from @jimcar
348
476
  - Uses Faraday HTTP Library as backend, with examples of alternate adapters
349
- - Cleanup client method signatures
477
+ - Cleanup client method signatures
@@ -109,6 +109,9 @@ module Orchestrate::API
109
109
  # @return [Array] The items in the response.
110
110
  attr_reader :results
111
111
 
112
+ # @return [Array] The aggregate items in the response.
113
+ attr_reader :aggregates
114
+
112
115
  # @return [String] The location for the next page of results
113
116
  attr_reader :next_link
114
117
 
@@ -122,6 +125,7 @@ module Orchestrate::API
122
125
  @count = body['count']
123
126
  @total_count = body['total_count']
124
127
  @results = body['results']
128
+ @aggregates = body['aggregates']
125
129
  @next_link = body['next']
126
130
  @prev_link = body['prev']
127
131
  end
@@ -345,17 +345,13 @@ module Orchestrate
345
345
  end
346
346
  end
347
347
 
348
- # @!group Searching
349
- # [Search the items in a collection](http://orchestrate.io/docs/api/#search) using a Lucene
350
- # Query Syntax.
351
348
  # @param query [#to_s] The [Lucene Query
352
349
  # String](http://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#Overview)
353
350
  # to query the collection with.
354
- # @return [SearchResults] A loaded SearchResults object ready to enumerate over.
351
+ # @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
355
352
  def search(query)
356
- SearchResults.new(self, query)
353
+ Search::QueryBuilder.new(self, query)
357
354
  end
358
- # @!endgroup
359
355
 
360
356
  # @!group Geo Queries
361
357
  # Performs a search for items near a specified geographic point in a collection.
@@ -366,11 +362,11 @@ module Orchestrate
366
362
  # @param distance [Integer] The number of distance units.
367
363
  # @param units [#to_s] Unit of measurement for distance, default to kilometers (km),
368
364
  # supported units: km, m, cm, mm, mi, yd, ft, in, nmi
369
- # @return [SearchResults] A loaded SearchResults object ready to enumerate over.
365
+ # @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
370
366
  def near(field, latitude, longitude, distance, units=nil)
371
- units ||= 'km'
372
- query = "#{field}:NEAR:{lat:#{latitude} lon:#{longitude} dist:#{distance}#{units}}"
373
- SearchResults.new(self, query)
367
+ units ||= 'km'
368
+ query = "#{field}:NEAR:{lat:#{latitude} lon:#{longitude} dist:#{distance}#{units}}"
369
+ Search::QueryBuilder.new(self, query)
374
370
  end
375
371
 
376
372
  # Performs a search for items within a particular area,
@@ -380,112 +376,14 @@ module Orchestrate
380
376
  # @param box [#to_json] The values to create the bounding box,
381
377
  # @example
382
378
  # collection.in(:field, {north: 12.5, south: 15, east: 14, west: 3})
383
- # @return [SearchResults] A loaded SearchResults object ready to enumerate over.
379
+ # @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
384
380
  def in(field, box={})
385
381
  box = box.flatten.each_slice(2).map {|dir, val| "#{dir}:#{val}" }.join(" ")
386
382
  query = "#{field}:IN:{#{box}}"
387
- SearchResults.new(self, query)
383
+ Search::QueryBuilder.new(self, query)
388
384
  end
389
385
  # @!endgroup
390
386
 
391
- # An enumerator with a query for searching an Orchestrate::Collection
392
- class SearchResults
393
- # @return [Collection] The collection this object will search.
394
- attr_reader :collection
395
-
396
- # @return [#to_s] The Lucene Query String given as the search query.
397
- attr_reader :query
398
-
399
- # @return [#to_s] The sorting parameters.
400
- attr_reader :sort
401
-
402
- # @return [Integer] The number of results to fetch per request.
403
- attr_reader :limit
404
-
405
- # Initialize a new SearchResults object
406
- # @param collection [Orchestrate::Collection] The collection to search.
407
- # @param query [#to_s] The Lucene Query to perform.
408
- def initialize(collection, query, sort=nil)
409
- @collection = collection
410
- @query = query
411
- @sort = sort
412
- @limit = 100
413
- @offset= nil
414
- end
415
-
416
- # Sets the sorting parameters for enumeration over the SearchResults items in the collection.
417
- # #order takes multiple arguments, but each even numbered argument must be either :asc or :desc
418
- # When given a single argument #order defaults to :asc
419
- # @example
420
- # @app[:items].search("location: Portland").order(:name, :asc, :rank, :desc, :created_at)
421
- # the :created_at parameter will default to :asc
422
- def order(*args)
423
- sort = args.each_slice(2).map {|field, dir| dir ||= :asc; "#{field}:#{dir}" }.join(",")
424
- self.class.new(collection, query, sort)
425
- end
426
-
427
- include Enumerable
428
-
429
- # Iterates over each result from the Search. Used as the basis for Enumerable methods. Items are
430
- # provided on the basis of score, with most relevant first.
431
- # @overload each
432
- # @return Enumerator
433
- # @overload each(&block)
434
- # @yieldparam [Array<(Float, Orchestrate::KeyValue)>] score,key_value The item's score and the item.
435
- # @example
436
- # collection.search("trendy").take(5).each do |score, item|
437
- # puts "#{item.key} has a trend score of #{score}"
438
- # end
439
- def each
440
- params = {limit:limit}
441
- params[:offset] = offset if offset
442
- params[:sort] = sort if sort
443
- @response ||= collection.perform(:search, query, params)
444
- return enum_for(:each) unless block_given?
445
- raise ResultsNotReady.new if collection.app.inside_parallel?
446
- loop do
447
- @response.results.each do |listing|
448
- yield [ listing['score'], KeyValue.from_listing(collection, listing, @response) ]
449
- end
450
- break unless @response.next_link
451
- @response = @response.next_results
452
- end
453
- @response = nil
454
- end
455
-
456
- # Creates a Lazy Enumerator for the Search Results. If called inside its
457
- # app's `in_parallel` block, will pre-fetch results.
458
- def lazy
459
- return each.lazy if collection.app.inside_parallel?
460
- super
461
- end
462
-
463
- # Returns the first n items. Equivalent to Enumerable#take. Sets the
464
- # `limit` parameter on the query to Orchestrate, so we don't ask for more than is needed.
465
- # @param count [Integer] The number of items to limit to.
466
- # @return [Array]
467
- def take(count)
468
- @limit = count > 100 ? 100 : count
469
- super(count)
470
- end
471
-
472
- # Sets the offset for the query to Orchestrate, so you can skip items. Does not fire a request.
473
- # Impelemented as separate method from drop, unlike #take, because take is a more common use case.
474
- # @overload offset
475
- # @return [Integer, nil] The number of items to skip. Nil is equivalent to zero.
476
- # @overload offset(conunt)
477
- # @param count [Integer] The number of items to skip.
478
- # @return [SearchResults] self.
479
- def offset(count=nil)
480
- if count
481
- @offset = count
482
- self
483
- else
484
- @offset
485
- end
486
- end
487
- end
488
-
489
387
  # Tells the Applicaiton to perform a request on its client, automatically
490
388
  # providing the collection name.
491
389
  # @param api_method [Symbol] The method on the client to call.
@@ -0,0 +1,290 @@
1
+ module Orchestrate::Search
2
+ # Aggregate Builder object for constructing aggregate params included in a search
3
+ class AggregateBuilder
4
+
5
+ # @return [QueryBuilder]
6
+ attr_reader :builder
7
+
8
+ # @return [Array] Aggregate param arguments
9
+ attr_reader :aggregates
10
+
11
+ extend Forwardable
12
+
13
+ # Initialize a new AggregateBuilder object
14
+ # @param builder [Orchestrate::Search::SearchBuilder] The Search Builder object
15
+ def initialize(builder)
16
+ @builder = builder
17
+ @aggregates = []
18
+ end
19
+
20
+ def_delegator :@builder, :options
21
+ def_delegator :@builder, :order
22
+ def_delegator :@builder, :limit
23
+ def_delegator :@builder, :offset
24
+ def_delegator :@builder, :aggregate
25
+ def_delegator :@builder, :find
26
+ def_delegator :@builder, :collection
27
+
28
+ # @return Pretty-Printed string representation of the AggregateBuilder object
29
+ def to_s
30
+ "#<Orchestrate::Search::AggregateBuilder collection=#{collection.name} query=#{builder.query} aggregate=#{to_param}>"
31
+ end
32
+ alias :inspect :to_s
33
+
34
+ # @return constructed aggregate string parameter for search query
35
+ def to_param
36
+ aggregates.map {|agg| agg.to_param }.join(',')
37
+ end
38
+
39
+ # @!group Aggregate Functions
40
+
41
+ # @param field_name [#to_s]
42
+ # @return [AggregateBuilder]
43
+ def stats(field_name)
44
+ stat = StatsBuilder.new(self, "#{field_name}")
45
+ aggregates << stat
46
+ stat
47
+ end
48
+
49
+ # @param field_name [#to_s]
50
+ # @return [RangeBuilder]
51
+ def range(field_name)
52
+ rng = RangeBuilder.new(self, "#{field_name}")
53
+ aggregates << rng
54
+ rng
55
+ end
56
+
57
+ # @param field_name [#to_s]
58
+ # @return [DistanceBuilder]
59
+ def distance(field_name)
60
+ dist = DistanceBuilder.new(self, "#{field_name}")
61
+ aggregates << dist
62
+ dist
63
+ end
64
+
65
+ # @param field_name [#to_s]
66
+ # @return [TimeSeriesBuilder]
67
+ def time_series(field_name)
68
+ time = TimeSeriesBuilder.new(self, "#{field_name}")
69
+ aggregates << time
70
+ time
71
+ end
72
+ # @!endgroup
73
+ end
74
+
75
+ # Stats Builder object for constructing stats functions to be included in the aggregate param
76
+ class StatsBuilder
77
+
78
+ # @return [AggregateBuilder]
79
+ attr_reader :builder
80
+
81
+ # @return [#to_s] The field to operate over
82
+ attr_reader :field_name
83
+
84
+ extend Forwardable
85
+
86
+ # Initialize a new RangeBuilder object
87
+ # @param builder [AggregateBuilder] The Aggregate Builder object
88
+ # @param field_name [#to_s]
89
+ def initialize(builder, field_name)
90
+ @builder = builder
91
+ @field_name = field_name
92
+ end
93
+
94
+ def_delegator :@builder, :options
95
+ def_delegator :@builder, :order
96
+ def_delegator :@builder, :limit
97
+ def_delegator :@builder, :offset
98
+ def_delegator :@builder, :aggregate
99
+ def_delegator :@builder, :find
100
+ def_delegator :@builder, :stats
101
+ def_delegator :@builder, :range
102
+ def_delegator :@builder, :distance
103
+ def_delegator :@builder, :time_series
104
+ def_delegator :@builder, :collection
105
+
106
+ # @return Pretty-Printed string representation of the StatsBuilder object
107
+ def to_s
108
+ "#<Orchestrate::Search::StatsBuilder collection=#{collection.name} field_name=#{field_name}>"
109
+ end
110
+ alias :inspect :to_s
111
+
112
+ # @return [#to_s] constructed aggregate string clause
113
+ def to_param
114
+ "#{field_name}:stats"
115
+ end
116
+ end
117
+
118
+ # Range Builder object for constructing range functions to be included in the aggregate param
119
+ class RangeBuilder
120
+
121
+ # @return [AggregateBuilder]
122
+ attr_reader :builder
123
+
124
+ # @return [#to_s] The field to operate over
125
+ attr_reader :field_name
126
+
127
+ # @return [#to_s] The range sets
128
+ attr_reader :ranges
129
+
130
+ extend Forwardable
131
+
132
+ # Initialize a new RangeBuilder object
133
+ # @param builder [AggregateBuilder] The Aggregate Builder object
134
+ # @param field_name [#to_s]
135
+ def initialize(builder, field_name)
136
+ @builder = builder
137
+ @field_name = field_name
138
+ @ranges = ''
139
+ end
140
+
141
+ def_delegator :@builder, :options
142
+ def_delegator :@builder, :order
143
+ def_delegator :@builder, :limit
144
+ def_delegator :@builder, :offset
145
+ def_delegator :@builder, :aggregate
146
+ def_delegator :@builder, :find
147
+ def_delegator :@builder, :stats
148
+ def_delegator :@builder, :range
149
+ def_delegator :@builder, :distance
150
+ def_delegator :@builder, :time_series
151
+ def_delegator :@builder, :collection
152
+
153
+ # @return Pretty-Printed string representation of the RangeBuilder object
154
+ def to_s
155
+ "#<Orchestrate::Search::RangeBuilder collection=#{collection.name} field_name=#{field_name} ranges=#{ranges}>"
156
+ end
157
+ alias :inspect :to_s
158
+
159
+ # @return [#to_s] constructed aggregate string clause
160
+ def to_param
161
+ "#{field_name}:range:#{ranges}"
162
+ end
163
+
164
+ # @param x [Integer]
165
+ # @return [RangeBuilder]
166
+ def below(x)
167
+ @ranges << "*~#{x}:"
168
+ self
169
+ end
170
+
171
+ # @param x [Integer]
172
+ # @return [RangeBuilder]
173
+ def above(x)
174
+ @ranges << "#{x}~*:"
175
+ self
176
+ end
177
+
178
+ # @param x [Integer]
179
+ # @param y [Integer]
180
+ # @return [RangeBuilder]
181
+ def between(x, y)
182
+ @ranges << "#{x}~#{y}:"
183
+ self
184
+ end
185
+ end
186
+
187
+ # Distance Builder object for constructing distance functions for the aggregate param
188
+ class DistanceBuilder < RangeBuilder
189
+
190
+ # @return Pretty-Printed string representation of the DistanceBuilder object
191
+ def to_s
192
+ "#<Orchestrate::Search::DistanceBuilder collection=#{collection.name} field_name=#{field_name} ranges=#{ranges}>"
193
+ end
194
+ alias :inspect :to_s
195
+
196
+ # @return [#to_s] constructed aggregate string clause
197
+ def to_param
198
+ "#{field_name}:distance:#{ranges}"
199
+ end
200
+ end
201
+
202
+ # Time Series Builder object for constructing time series functions for the aggregate param
203
+ class TimeSeriesBuilder
204
+
205
+ # @return [AggregateBuilder]
206
+ attr_reader :builder
207
+
208
+ # @return [#to_s] The field to operate over
209
+ attr_reader :field_name
210
+
211
+ # @return [#to_s] The interval of time for the TimeSeries function
212
+ attr_reader :interval
213
+
214
+ extend Forwardable
215
+
216
+ # Initialize a new TimeSeriesBuilder object
217
+ # @param builder [AggregateBuilder] The Aggregate Builder object
218
+ # @param field_name [#to_s] The field to operate over
219
+ def initialize(builder, field_name)
220
+ @builder = builder
221
+ @field_name = field_name
222
+ @interval = nil
223
+ end
224
+
225
+ def_delegator :@builder, :options
226
+ def_delegator :@builder, :order
227
+ def_delegator :@builder, :limit
228
+ def_delegator :@builder, :offset
229
+ def_delegator :@builder, :aggregate
230
+ def_delegator :@builder, :find
231
+ def_delegator :@builder, :stats
232
+ def_delegator :@builder, :range
233
+ def_delegator :@builder, :distance
234
+ def_delegator :@builder, :time_series
235
+ def_delegator :@builder, :collection
236
+
237
+ # @return Pretty-Printed string representation of the TimeSeriesBuilder object
238
+ def to_s
239
+ "#<Orchestrate::Search::TimeSeriesBuilder collection=#{collection.name} field_name=#{field_name} interval=#{interval}>"
240
+ end
241
+ alias :inspect :to_s
242
+
243
+ # @return [#to_s] constructed aggregate string clause
244
+ def to_param
245
+ "#{field_name}:time_series:#{interval}"
246
+ end
247
+
248
+ # Set time series interval to year
249
+ # @return [AggregateBuilder]
250
+ def year
251
+ @interval = 'year'
252
+ self
253
+ end
254
+
255
+ # Set time series interval to quarter
256
+ # @return [AggregateBuilder]
257
+ def quarter
258
+ @interval = 'quarter'
259
+ self
260
+ end
261
+
262
+ # Set time series interval to month
263
+ # @return [AggregateBuilder]
264
+ def month
265
+ @interval = 'month'
266
+ self
267
+ end
268
+
269
+ # Set time series interval to week
270
+ # @return [AggregateBuilder]
271
+ def week
272
+ @interval = 'week'
273
+ self
274
+ end
275
+
276
+ # Set time series interval to day
277
+ # @return [AggregateBuilder]
278
+ def day
279
+ @interval = 'day'
280
+ self
281
+ end
282
+
283
+ # Set time series interval to hour
284
+ # @return [AggregateBuilder]
285
+ def hour
286
+ @interval = 'hour'
287
+ self
288
+ end
289
+ end
290
+ end