orchestrate 0.10.0 → 0.11.0
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 +4 -4
- data/README.md +138 -10
- data/lib/orchestrate/api/response.rb +4 -0
- data/lib/orchestrate/collection.rb +8 -110
- data/lib/orchestrate/search/aggregate_builder.rb +290 -0
- data/lib/orchestrate/search/query_builder.rb +83 -0
- data/lib/orchestrate/search/results.rb +215 -0
- data/lib/orchestrate/search.rb +10 -0
- data/lib/orchestrate/version.rb +1 -1
- data/lib/orchestrate.rb +1 -0
- data/orchestrate.gemspec +14 -14
- data/test/orchestrate/collection_aggregates_test.rb +118 -0
- data/test/orchestrate/collection_geo_queries_test.rb +5 -5
- data/test/orchestrate/collection_searching_test.rb +9 -10
- data/test/orchestrate/collection_sorting_test.rb +4 -4
- metadata +32 -24
@@ -0,0 +1,83 @@
|
|
1
|
+
module Orchestrate::Search
|
2
|
+
# Query Builder object for constructing search queries
|
3
|
+
class QueryBuilder
|
4
|
+
# @return [Collection] The collection this object will search.
|
5
|
+
attr_reader :collection
|
6
|
+
|
7
|
+
# @return [#to_s] The Lucene Query String given as the search query.
|
8
|
+
attr_reader :query
|
9
|
+
|
10
|
+
# Initialize a new SearchBuilder object
|
11
|
+
# @param collection [Orchestrate::Collection] The collection to search.
|
12
|
+
# @param query [#to_s] The Lucene Query to perform.
|
13
|
+
def initialize(collection, query)
|
14
|
+
@collection = collection
|
15
|
+
@query = query
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return Pretty-Printed string representation of the Search object
|
19
|
+
def to_s
|
20
|
+
"#<Orchestrate::Search::QueryBuilder collection=#{collection.name} query=#{query} options=#{options}>"
|
21
|
+
end
|
22
|
+
alias :inspect :to_s
|
23
|
+
|
24
|
+
# @return [Hash] Optional parameters for the search query.
|
25
|
+
def options
|
26
|
+
@options ||= { limit: 100 }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the sorting parameters for a query's Search Results.
|
30
|
+
# #order takes multiple arguments,
|
31
|
+
# but each even numbered argument must be either :asc or :desc
|
32
|
+
# Odd-numbered arguments defaults to :asc
|
33
|
+
# @example
|
34
|
+
# @app[:items].search("foo").order(:name, :asc, :rank, :desc, :created_at)
|
35
|
+
def order(*args)
|
36
|
+
options[:sort] = args.each_slice(2).map {|field, dir| dir ||= :asc; "#{field}:#{dir}" }.join(',')
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sets the limit for the query to Orchestrate, so we don't ask for more than is needed.
|
41
|
+
# Does not fire a request.
|
42
|
+
# @overload limit
|
43
|
+
# @return [Integer, nil] The number of items to retrieve. Nil is equivalent to zero.
|
44
|
+
# @overload limit(count)
|
45
|
+
# @param count [Integer] The number of items to retrieve.
|
46
|
+
# @return [Search] self.
|
47
|
+
def limit(count=nil)
|
48
|
+
if count
|
49
|
+
options[:limit] = count > 100 ? 100 : count
|
50
|
+
self
|
51
|
+
else
|
52
|
+
options[:limit]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the offset for the query to Orchestrate, so you can skip items. Does not fire a request.
|
57
|
+
# Impelemented as separate method from drop, unlike #take, because take is a more common use case.
|
58
|
+
# @overload offset
|
59
|
+
# @return [Integer, nil] The number of items to skip. Nil is equivalent to zero.
|
60
|
+
# @overload offset(count)
|
61
|
+
# @param count [Integer] The number of items to skip.
|
62
|
+
# @return [Search] self.
|
63
|
+
def offset(count=nil)
|
64
|
+
if count
|
65
|
+
options[:offset] = count
|
66
|
+
self
|
67
|
+
else
|
68
|
+
options[:offset]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [AggregateBuilder] An AggregateBuilder object to construct aggregate search params
|
73
|
+
def aggregate
|
74
|
+
options[:aggregate] ||= AggregateBuilder.new(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Orchestrate::Search::Results] A Results object to enumerate over.
|
78
|
+
def find
|
79
|
+
options[:aggregate] = options[:aggregate].to_param if options[:aggregate]
|
80
|
+
Results.new(collection, query, options)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
module Orchestrate::Search
|
2
|
+
# An enumerator for searching an Orchestrate::Collection
|
3
|
+
class Results
|
4
|
+
# @return [Collection] The collection this object will search.
|
5
|
+
attr_reader :collection
|
6
|
+
|
7
|
+
# @return [#to_s] The Lucene Query String given as the search query.
|
8
|
+
attr_reader :query
|
9
|
+
|
10
|
+
# @return [Hash] The query paramaters.
|
11
|
+
attr_reader :options
|
12
|
+
|
13
|
+
# @return [Orchestrate::API::CollectionResponse] The response object
|
14
|
+
attr_reader :response
|
15
|
+
|
16
|
+
# @return [#to_json] The response object's aggregate results
|
17
|
+
attr_reader :aggregates
|
18
|
+
|
19
|
+
# Initialize a new SearchResults object
|
20
|
+
# @param collection [Orchestrate::Collection] The collection searched.
|
21
|
+
# @param query [#to_s] The Lucene Query performed.
|
22
|
+
# @param options [Hash] The query parameters.
|
23
|
+
def initialize(collection, query, options)
|
24
|
+
@collection = collection
|
25
|
+
@query = query
|
26
|
+
@options = options
|
27
|
+
@response = nil
|
28
|
+
@aggregates = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
include Enumerable
|
32
|
+
|
33
|
+
# Iterates over each result from the Search. Used as the basis for Enumerable methods.
|
34
|
+
# Items are provided on the basis of score, with most relevant first.
|
35
|
+
# @overload each
|
36
|
+
# @return Enumerator
|
37
|
+
# @overload each(&block)
|
38
|
+
# @yieldparam [Array<(Float, Orchestrate::KeyValue)>] score,key_value The item's score and the item.
|
39
|
+
# @example
|
40
|
+
# collection.search("trendy").limit(5).execute.each do |score, item|
|
41
|
+
# puts "#{item.key} has a trend score of #{score}"
|
42
|
+
# end
|
43
|
+
def each
|
44
|
+
@response ||= collection.perform(:search, query, options)
|
45
|
+
@aggregates ||= @response.aggregates
|
46
|
+
return enum_for(:each) unless block_given?
|
47
|
+
raise Orchestrate::ResultsNotReady.new if collection.app.inside_parallel?
|
48
|
+
loop do
|
49
|
+
@response.results.each do |listing|
|
50
|
+
yield [ listing['score'], Orchestrate::KeyValue.from_listing(collection, listing, @response) ]
|
51
|
+
end
|
52
|
+
break unless @response.next_link
|
53
|
+
@response = @response.next_results
|
54
|
+
end
|
55
|
+
@response = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# Iterates over each aggregate result from the Search. Used as the basis for Enumerable methods. Items are
|
59
|
+
# provided on the basis of score, with most relevant first.
|
60
|
+
# @overload each_aggregate
|
61
|
+
# @return Enumerator
|
62
|
+
# @overload each_aggregate(&block)
|
63
|
+
# @yieldparam <(Orchestrate::Collection::AggregateResult)>
|
64
|
+
def each_aggregate
|
65
|
+
@response ||= collection.perform(:search, query, options)
|
66
|
+
@aggregates ||= @response.aggregates
|
67
|
+
return enum_for(:each_aggregate) unless block_given?
|
68
|
+
raise Orchestrate::ResultsNotReady.new if collection.app.inside_parallel?
|
69
|
+
@aggregates.each do |listing|
|
70
|
+
case listing['aggregate_kind']
|
71
|
+
when 'stats'
|
72
|
+
yield StatsResult.new(collection, listing)
|
73
|
+
when 'range'
|
74
|
+
yield RangeResult.new(collection, listing)
|
75
|
+
when 'distance'
|
76
|
+
yield DistanceResult.new(collection, listing)
|
77
|
+
when 'time_series'
|
78
|
+
yield TimeSeriesResult.new(collection, listing)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Creates a Lazy Enumerator for the Search Results. If called inside its
|
84
|
+
# app's `in_parallel` block, will pre-fetch results.
|
85
|
+
def lazy
|
86
|
+
return each.lazy if collection.app.inside_parallel?
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Base object representing an individual Aggregate result
|
92
|
+
class AggregateResult
|
93
|
+
# @return [Collection] The collection searched.
|
94
|
+
attr_reader :collection
|
95
|
+
|
96
|
+
# @return [#to_s] The aggregate kind/type
|
97
|
+
attr_reader :kind
|
98
|
+
|
99
|
+
# @return [#to_s] The field name the aggregate function operated over.
|
100
|
+
attr_reader :field_name
|
101
|
+
|
102
|
+
# @return [Integer] Number of field values included in the aggregate function.
|
103
|
+
attr_reader :count
|
104
|
+
|
105
|
+
# Initialize a new AggregateResult object
|
106
|
+
# @param collection [Orchestrate::Collection] The collection searched.
|
107
|
+
# @param listing [#to_json] The aggregate result returned from the search.
|
108
|
+
def initialize(collection, listing)
|
109
|
+
@collection = collection
|
110
|
+
@kind = listing['aggregate_kind']
|
111
|
+
@field_name = listing['field_name']
|
112
|
+
@count = listing['value_count']
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Stats Aggregate result object
|
117
|
+
class StatsResult < AggregateResult
|
118
|
+
# @return [Hash] The statistics results
|
119
|
+
attr_reader :statistics
|
120
|
+
|
121
|
+
# @return [Float] Lowest numerical value of the statistics result
|
122
|
+
attr_reader :min
|
123
|
+
|
124
|
+
# @return [Float] Highest numerical value of the statistics result
|
125
|
+
attr_reader :max
|
126
|
+
|
127
|
+
# @return [Float] Average of included numerical values
|
128
|
+
attr_reader :mean
|
129
|
+
|
130
|
+
# @return [Float] Total of included numerical values
|
131
|
+
attr_reader :sum
|
132
|
+
|
133
|
+
# @return [Float]
|
134
|
+
attr_reader :sum_of_squares
|
135
|
+
|
136
|
+
# @return [Float]
|
137
|
+
attr_reader :variance
|
138
|
+
|
139
|
+
# @return [Float]
|
140
|
+
attr_reader :std_dev
|
141
|
+
|
142
|
+
# Initialize a new StatsResult object
|
143
|
+
# @param collection [Orchestrate::Collection] The collection searched.
|
144
|
+
# @param listing [#to_json] The aggregate result returned from the search.
|
145
|
+
def initialize(collection, listing)
|
146
|
+
super(collection, listing)
|
147
|
+
if listing['statistics']
|
148
|
+
@statistics = listing['statistics']
|
149
|
+
@min = @statistics['min']
|
150
|
+
@max = @statistics['max']
|
151
|
+
@mean = @statistics['mean']
|
152
|
+
@sum = @statistics['sum']
|
153
|
+
@sum_of_squares = @statistics['sum_of_squares']
|
154
|
+
@variance = @statistics['variance']
|
155
|
+
@std_dev = @statistics['std_dev']
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return Pretty-Printed string representation of the StatsResult object
|
160
|
+
def to_s
|
161
|
+
stats = "statistics={\n min=#{min},\n max=#{max},\n mean=#{mean},\n sum=#{sum},\n sum_of_squares=#{sum_of_squares},\n variance=#{variance},\n std_dev=#{std_dev}\n}"
|
162
|
+
"#<Orchestrate::Search::StatsResult collection=#{collection.name} field_name=#{field_name} count=#{count} #{stats}>"
|
163
|
+
end
|
164
|
+
alias :inspect :to_s
|
165
|
+
end
|
166
|
+
|
167
|
+
# Range Aggregate result object
|
168
|
+
class RangeResult < AggregateResult
|
169
|
+
# @return [Array] Range buckets/sets results
|
170
|
+
attr_reader :buckets
|
171
|
+
|
172
|
+
# Initialize a new RangeResult object
|
173
|
+
# @param collection [Orchestrate::Collection] The collection searched.
|
174
|
+
# @param listing [#to_json] The aggregate result returned from the search.
|
175
|
+
def initialize(collection, listing)
|
176
|
+
super(collection, listing)
|
177
|
+
@buckets = listing['buckets']
|
178
|
+
end
|
179
|
+
|
180
|
+
# @return Pretty-Printed string representation of the RangeResult object
|
181
|
+
def to_s
|
182
|
+
"#<Orchestrate::Search::RangeResult collection=#{collection.name} field_name=#{field_name} buckets=#{buckets}>"
|
183
|
+
end
|
184
|
+
alias :inspect :to_s
|
185
|
+
end
|
186
|
+
|
187
|
+
# Distance Aggregate result object
|
188
|
+
class DistanceResult < RangeResult
|
189
|
+
# @return Pretty-Printed string representation of the DistanceResult object
|
190
|
+
def to_s
|
191
|
+
"#<Orchestrate::Search::DistanceResult collection=#{collection.name} field_name=#{field_name} buckets=#{buckets}>"
|
192
|
+
end
|
193
|
+
alias :inspect :to_s
|
194
|
+
end
|
195
|
+
|
196
|
+
# Time Series Aggregate result object
|
197
|
+
class TimeSeriesResult < RangeResult
|
198
|
+
# @return [#to_s] Time interval
|
199
|
+
attr_reader :interval
|
200
|
+
|
201
|
+
# Initialize a new TimeSeriesResult object
|
202
|
+
# @param collection [Orchestrate::Collection] The collection searched.
|
203
|
+
# @param listing [#to_json] The aggregate result returned from the search.
|
204
|
+
def initialize(collection, listing)
|
205
|
+
super(collection, listing)
|
206
|
+
@interval = listing['interval']
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return Pretty-Printed string representation of the TimeSeriesResult object
|
210
|
+
def to_s
|
211
|
+
"#<Orchestrate::Search::TimeSeriesResult collection=#{collection.name} field_name=#{field_name} interval=#{interval} buckets=#{buckets}>"
|
212
|
+
end
|
213
|
+
alias :inspect :to_s
|
214
|
+
end
|
215
|
+
end
|
data/lib/orchestrate/version.rb
CHANGED
data/lib/orchestrate.rb
CHANGED
data/orchestrate.gemspec
CHANGED
@@ -3,25 +3,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
require 'orchestrate/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
s.name = 'orchestrate'
|
7
|
+
s.version = Orchestrate::VERSION
|
8
|
+
s.authors = ['Matthew Lyon', 'Justin Mecham', 'James Carrasquer', 'Eric Johnson']
|
9
|
+
s.email = ['matthew@lyonheart.us', 'justin@mecham.me', 'jimcar@aracnet.com', 'erjohnson.pdx@gmail.com']
|
10
|
+
s.summary = 'Ruby client for Orchestrate.io'
|
11
|
+
s.description = 'Client for the Orchestrate REST API'
|
12
|
+
s.homepage = 'https://github.com/orchestrate-io/orchestrate-ruby'
|
13
|
+
s.license = 'MIT'
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
s.files = `git ls-files -z`.split("\x0")
|
16
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_dependency "faraday", "
|
20
|
+
s.add_dependency "faraday", "0.9.0"
|
21
21
|
s.add_dependency "net-http-persistent", "~> 2.9"
|
22
22
|
s.add_development_dependency "bundler", "~> 1.6"
|
23
23
|
s.add_development_dependency "rake"
|
24
24
|
s.add_development_dependency "typhoeus"
|
25
25
|
s.add_development_dependency "em-http-request"
|
26
26
|
s.add_development_dependency "em-synchrony"
|
27
|
-
end
|
27
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CollectionAggregates < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@app, @stubs = make_application({parallel:true})
|
6
|
+
@items = @app[:items]
|
7
|
+
|
8
|
+
@query = "foo"
|
9
|
+
@stats = [{
|
10
|
+
"aggregate_kind" => "stats",
|
11
|
+
"field_name" => "value.bar",
|
12
|
+
"value_count" => 100,
|
13
|
+
"statistics" => {
|
14
|
+
"min" => 2.99,
|
15
|
+
"max" => 29.99,
|
16
|
+
"mean" => 11.779370,
|
17
|
+
"sum" => 1495.98,
|
18
|
+
"sum_of_squares" => 32740.05,
|
19
|
+
"variance" => 119.986850,
|
20
|
+
"std_dev" => 10.953851
|
21
|
+
}
|
22
|
+
}]
|
23
|
+
@range = [{
|
24
|
+
"aggregate_kind" => "range",
|
25
|
+
"field_name" => "value.bar",
|
26
|
+
"value_count" => 100,
|
27
|
+
"buckets" => [{
|
28
|
+
"max" => 40,
|
29
|
+
"count" => 42
|
30
|
+
}]
|
31
|
+
}]
|
32
|
+
@distance = [{
|
33
|
+
"aggregate_kind" => "distance",
|
34
|
+
"field_name" => "value.bar",
|
35
|
+
"value_count" => 100,
|
36
|
+
"buckets" => [{
|
37
|
+
"min" => 0,
|
38
|
+
"max" => 1,
|
39
|
+
"count" => 42
|
40
|
+
}]
|
41
|
+
}]
|
42
|
+
@time_series = [{
|
43
|
+
"aggregate_kind" => "time_series",
|
44
|
+
"field_name" => "value.bar",
|
45
|
+
"interval" => "day",
|
46
|
+
"value_count" => 100,
|
47
|
+
"buckets" => [{
|
48
|
+
"bucket" => "2014-11-01",
|
49
|
+
"count" => 17
|
50
|
+
}]
|
51
|
+
}]
|
52
|
+
@limit = 100
|
53
|
+
@total = 110
|
54
|
+
|
55
|
+
@make_listing = lambda{|i| make_kv_listing(:items, key: "item-#{i}", reftime: nil, score: @total-i/@total*5.0) }
|
56
|
+
@handle_aggregate = lambda do |aggregate|
|
57
|
+
case aggregate
|
58
|
+
when 'bar:stats'
|
59
|
+
{ "results" => 100.times.map{|i| @make_listing.call(i)}, "count" => 100, "total_count" => @total,
|
60
|
+
"aggregates" => @stats }
|
61
|
+
when 'bar:range:*~40:'
|
62
|
+
{ "results" => 100.times.map{|i| @make_listing.call(i)}, "count" => 100, "total_count" => @total,
|
63
|
+
"aggregates" => @range }
|
64
|
+
when 'bar:distance:0~1:'
|
65
|
+
{ "results" => 100.times.map{|i| @make_listing.call(i)}, "count" => 100, "total_count" => @total,
|
66
|
+
"aggregates" => @distance }
|
67
|
+
when 'bar:time_series:day'
|
68
|
+
{ "results" => 100.times.map{|i| @make_listing.call(i)}, "count" => 100, "total_count" => @total,
|
69
|
+
"aggregates" => @time_series }
|
70
|
+
else
|
71
|
+
raise ArgumentError.new("unexpected aggregate: #{aggregate}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@called = false
|
76
|
+
@stubs.get("/v0/items") do |env|
|
77
|
+
@called = true
|
78
|
+
assert_equal @query, env.params['query']
|
79
|
+
assert_equal @limit, env.params['limit'].to_i
|
80
|
+
body = @handle_aggregate.call(env.params['aggregate'])
|
81
|
+
[ 200, response_headers, body.to_json ]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_basic_stats_aggregate
|
86
|
+
results = @items.search("foo").aggregate.stats("bar").find
|
87
|
+
results.each_aggregate
|
88
|
+
assert_equal @stats, results.aggregates
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_basic_range_aggregate
|
92
|
+
results = @items.search("foo").aggregate.range("bar").below(40).find
|
93
|
+
results.each_aggregate
|
94
|
+
assert_equal @range, results.aggregates
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_basic_distance_aggregate
|
98
|
+
@query = "foo:NEAR:{lat:12.3 lon:56.7 dist:100km}"
|
99
|
+
results = @items.near("foo", 12.3, 56.7, 100).aggregate.distance("bar").between(0,1).find
|
100
|
+
results.each_aggregate
|
101
|
+
assert_equal @distance, results.aggregates
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_basic_time_series_aggregate
|
105
|
+
results = @items.search("foo").aggregate.time_series("bar").day.find
|
106
|
+
results.each_aggregate
|
107
|
+
assert_equal @time_series, results.aggregates
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_each_aggregate_enum
|
111
|
+
results = @items.search("foo").aggregate.time_series("bar").day.find
|
112
|
+
enum = results.each_aggregate
|
113
|
+
aggregates = enum.to_a
|
114
|
+
assert_equal 1, aggregates.size
|
115
|
+
assert aggregates.first.is_a?(Orchestrate::Search::TimeSeriesResult)
|
116
|
+
assert_equal "day", aggregates.first.interval
|
117
|
+
end
|
118
|
+
end
|
@@ -34,7 +34,7 @@ class CollectionGeoQueriesTest < MiniTest::Unit::TestCase
|
|
34
34
|
|
35
35
|
def test_near_search_without_units
|
36
36
|
@query = @near_query
|
37
|
-
results = @items.near("location", 12, 56, 1).map{|i| i }
|
37
|
+
results = @items.near("location", 12, 56, 1).find.each.map{|i| i }
|
38
38
|
assert_equal 10, results.length
|
39
39
|
results.each_with_index do |item, idx|
|
40
40
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -45,7 +45,7 @@ class CollectionGeoQueriesTest < MiniTest::Unit::TestCase
|
|
45
45
|
|
46
46
|
def test_near_search_with_units
|
47
47
|
@query = @near_query
|
48
|
-
results = @items.near("location", 12, 56, 1, 'km').map{|i| i }
|
48
|
+
results = @items.near("location", 12, 56, 1, 'km').find.each.map{|i| i }
|
49
49
|
assert_equal 10, results.length
|
50
50
|
results.each_with_index do |item, idx|
|
51
51
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -56,7 +56,7 @@ class CollectionGeoQueriesTest < MiniTest::Unit::TestCase
|
|
56
56
|
|
57
57
|
def test_near_search_with_sort
|
58
58
|
@query = @near_query
|
59
|
-
results = @items.near("location", 12, 56, 1, 'km').order(:location).map{|i| i }
|
59
|
+
results = @items.near("location", 12, 56, 1, 'km').order(:location).find.each.map{|i| i }
|
60
60
|
assert_equal 10, results.length
|
61
61
|
results.each_with_index do |item, idx|
|
62
62
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -67,7 +67,7 @@ class CollectionGeoQueriesTest < MiniTest::Unit::TestCase
|
|
67
67
|
|
68
68
|
def test_in_bounding_box
|
69
69
|
@query = @in_query
|
70
|
-
results = @items.in("location", {north:12, east:57, south:12, west:56}).map{|i| i }
|
70
|
+
results = @items.in("location", {north:12, east:57, south:12, west:56}).find.each.map{|i| i }
|
71
71
|
assert_equal 12, results.length
|
72
72
|
results.each_with_index do |item, idx|
|
73
73
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -78,7 +78,7 @@ class CollectionGeoQueriesTest < MiniTest::Unit::TestCase
|
|
78
78
|
|
79
79
|
def test_in_bounding_box_with_sort
|
80
80
|
@query = @in_query
|
81
|
-
results = @items.in("location", {north:12, east:57, south:12, west:56}).order(:location).map{|i| i }
|
81
|
+
results = @items.in("location", {north:12, east:57, south:12, west:56}).order(:location).find.each.map{|i| i }
|
82
82
|
assert_equal 12, results.length
|
83
83
|
results.each_with_index do |item, idx|
|
84
84
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -33,7 +33,7 @@ class CollectionSearchingTest < MiniTest::Unit::TestCase
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_basic_search
|
36
|
-
results = @items.search("foo").map{|i| i }
|
36
|
+
results = @items.search("foo").find.each.map{|i| i }
|
37
37
|
assert_equal 110, results.length
|
38
38
|
results.each_with_index do |item, idx|
|
39
39
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -48,14 +48,13 @@ class CollectionSearchingTest < MiniTest::Unit::TestCase
|
|
48
48
|
@handle_offset = lambda do |o|
|
49
49
|
case o
|
50
50
|
when "10"
|
51
|
-
{ "results" => 50.times.map{|i| @make_listing.call(i+offset) }, "count" => @limit, "total_count" => @total
|
52
|
-
"next" => "/v0/items?query=foo&offset=#{offset+@limit}&limit=#{@limit}"}
|
51
|
+
{ "results" => 50.times.map{|i| @make_listing.call(i+offset) }, "count" => @limit, "total_count" => @total }
|
53
52
|
else
|
54
53
|
raise ArgumentError.new("unexpected offset: #{o}")
|
55
54
|
end
|
56
55
|
end
|
57
|
-
results = @items.search("foo").offset(offset).
|
58
|
-
assert_equal
|
56
|
+
results = @items.search("foo").offset(offset).limit(@limit).find
|
57
|
+
assert_equal 10, results.options[:offset]
|
59
58
|
results.each_with_index do |item, idx|
|
60
59
|
assert_in_delta (@total-(idx+10)/@total * 5.0), item[0], 0.005
|
61
60
|
assert_equal "item-#{idx+10}", item[1].key
|
@@ -65,7 +64,7 @@ class CollectionSearchingTest < MiniTest::Unit::TestCase
|
|
65
64
|
|
66
65
|
def test_in_parallel_prefetches_enums
|
67
66
|
items = nil
|
68
|
-
@app.in_parallel { items = @app[:items].search("foo").each }
|
67
|
+
@app.in_parallel { items = @app[:items].search("foo").find.each }
|
69
68
|
assert @called, "enum wasn't prefetched inside in_parallel"
|
70
69
|
assert_equal @total, items.to_a.size
|
71
70
|
end
|
@@ -73,27 +72,27 @@ class CollectionSearchingTest < MiniTest::Unit::TestCase
|
|
73
72
|
def test_in_parallel_prefetches_lazy_enums
|
74
73
|
return unless [].respond_to?(:lazy)
|
75
74
|
items = nil
|
76
|
-
@app.in_parallel { items = @app[:items].search("foo").lazy.map{|d| d } }
|
75
|
+
@app.in_parallel { items = @app[:items].search("foo").find.lazy.map{|d| d } }
|
77
76
|
assert @called, "lazy wasn't prefetched from in_parallel"
|
78
77
|
assert_equal @total, items.force.size
|
79
78
|
end
|
80
79
|
|
81
80
|
def test_in_parallel_raises_if_forced
|
82
81
|
assert_raises Orchestrate::ResultsNotReady do
|
83
|
-
@app.in_parallel { @app[:items].search("foo").to_a }
|
82
|
+
@app.in_parallel { @app[:items].search("foo").find.each.to_a }
|
84
83
|
end
|
85
84
|
end
|
86
85
|
|
87
86
|
def test_enums_prefetch
|
88
87
|
items = nil
|
89
|
-
@app.in_parallel { items = @app[:items].search("foo").each }
|
88
|
+
@app.in_parallel { items = @app[:items].search("foo").find.each }
|
90
89
|
assert @called, "enum wasn't prefetched"
|
91
90
|
assert_equal @total, items.to_a.size
|
92
91
|
end
|
93
92
|
|
94
93
|
def test_lazy_enums_dont_prefetch
|
95
94
|
return unless [].respond_to?(:lazy)
|
96
|
-
items = @app[:items].search("foo").lazy.map{|d| d }
|
95
|
+
items = @app[:items].search("foo").find.lazy.map{|d| d }
|
97
96
|
refute @called, "lazy was prefetched outside in_parallel"
|
98
97
|
assert_equal @total, items.force.size
|
99
98
|
end
|
@@ -33,7 +33,7 @@ class CollectionSortingTest < MiniTest::Unit::TestCase
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_basic_sort_ascending
|
36
|
-
results = @items.search("foo").order(:score, :asc).map{|i| i }
|
36
|
+
results = @items.search("foo").order(:score, :asc).find.each.map{|i| i }
|
37
37
|
assert_equal 110, results.length
|
38
38
|
results.each_with_index do |item, idx|
|
39
39
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -44,7 +44,7 @@ class CollectionSortingTest < MiniTest::Unit::TestCase
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_basic_sort_descending
|
47
|
-
results = @items.search("foo").order(:score, :desc).map{|i| i }
|
47
|
+
results = @items.search("foo").order(:score, :desc).find.each.map{|i| i }
|
48
48
|
assert_equal 110, results.length
|
49
49
|
results.each_with_index do |item, idx|
|
50
50
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -55,7 +55,7 @@ class CollectionSortingTest < MiniTest::Unit::TestCase
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def test_basic_multiple_fields_sort_ascending
|
58
|
-
results = @items.search("foo").order(:score, :asc, :rank, :asc).map{|i| i }
|
58
|
+
results = @items.search("foo").order(:score, :asc, :rank, :asc).find.each.map{|i| i }
|
59
59
|
assert_equal 110, results.length
|
60
60
|
results.each_with_index do |item, idx|
|
61
61
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|
@@ -67,7 +67,7 @@ class CollectionSortingTest < MiniTest::Unit::TestCase
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_basic_multiple_fields_sort_descending
|
70
|
-
results = @items.search("foo").order(:score, :asc, :rank, :desc).map{|i| i }
|
70
|
+
results = @items.search("foo").order(:score, :asc, :rank, :desc).find.each.map{|i| i }
|
71
71
|
assert_equal 110, results.length
|
72
72
|
results.each_with_index do |item, idx|
|
73
73
|
assert_in_delta (@total-idx/@total * 5.0), item[0], 0.005
|