stretchy 0.5.3 → 0.8.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
- SHA1:
3
- metadata.gz: fc1f47df9e733b26cbf7a600076991ef6c2fd740
4
- data.tar.gz: f62cabd7fc16980276d70de66c90dba0d25fb03e
2
+ SHA256:
3
+ metadata.gz: 76d1eeb5c2be5aad546eed305e53d83ea4c64dd9c61e9b40a64ec0246de6c4cf
4
+ data.tar.gz: 4a6ddb55f798e90fde4ce5a1a5cb2b39559ca0eb2b5f9f92f353b0c108dfe224
5
5
  SHA512:
6
- metadata.gz: 0642e6ceab6cb04e30aef51cfedefbc1ae4b49f49b387528f71425d7a72bd9bf21a0763f6e1968e95c4568cc9d9148a66f5565cc42b0e5802adfbf08d6c7d6e7
7
- data.tar.gz: 33e7884e2d19d7dbc269258b21b3cb448b8174e055c0f88338ef786caad83efc38886be1386ec3d094b96b4fed584ab7754bb3f2d7c239fd7d8a838f13be9b35
6
+ metadata.gz: 58dd985f4bdee6edd189c6b5235d2cb59dd96a79c479fae3abae7f88a087f10c383e4c4eb183090c49c9619b2bc5dddad5ad8fdc6f80efc6a507be1dd8de609f
7
+ data.tar.gz: 055776e2bfb69e791c631df6576ed33c76337d74e64720c9ec86e8e79500248d2c37f2104f820aa32c978ee4ee6280dbfc5a9f54c8cfa809465456ee9401c97a
data/.rubocop.yml ADDED
@@ -0,0 +1,260 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-12-09 14:43:24 -0800 using RuboCop version 0.32.1.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ # Cop supports --auto-correct.
10
+ Lint/BlockAlignment:
11
+ Enabled: false
12
+
13
+ # Offense count: 3
14
+ # Cop supports --auto-correct.
15
+ # Configuration parameters: AlignWith, SupportedStyles, AutoCorrect.
16
+ Lint/EndAlignment:
17
+ Enabled: false
18
+
19
+ # Offense count: 1
20
+ Lint/HandleExceptions:
21
+ Enabled: false
22
+
23
+ # Offense count: 3
24
+ # Cop supports --auto-correct.
25
+ Lint/UnusedBlockArgument:
26
+ Enabled: true
27
+
28
+ # Offense count: 2
29
+ Lint/UselessAssignment:
30
+ Enabled: true
31
+
32
+ # Offense count: 5
33
+ Metrics/AbcSize:
34
+ Max: 15
35
+
36
+ # Offense count: 2
37
+ # Configuration parameters: CountComments.
38
+ Metrics/ClassLength:
39
+ Max: 250
40
+
41
+ # Offense count: 1
42
+ Metrics/CyclomaticComplexity:
43
+ Max: 7
44
+
45
+ # Offense count: 3
46
+ # Configuration parameters: AllowURI, URISchemes.
47
+ Metrics/LineLength:
48
+ Max: 80
49
+
50
+ # Offense count: 8
51
+ # Configuration parameters: CountComments.
52
+ Metrics/MethodLength:
53
+ Max: 20
54
+
55
+ # Offense count: 2
56
+ # Configuration parameters: CountComments.
57
+ Metrics/ModuleLength:
58
+ Max: 250
59
+
60
+ # Offense count: 14
61
+ # Cop supports --auto-correct.
62
+ Style/Alias:
63
+ Enabled: false
64
+
65
+ # Offense count: 1
66
+ # Cop supports --auto-correct.
67
+ # Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles.
68
+ Style/AlignHash:
69
+ Enabled: false
70
+
71
+ # Offense count: 7
72
+ # Cop supports --auto-correct.
73
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
74
+ Style/BlockDelimiters:
75
+ Enabled: false
76
+
77
+ # Offense count: 3
78
+ # Cop supports --auto-correct.
79
+ Style/BlockEndNewline:
80
+ Enabled: false
81
+
82
+ # Offense count: 3
83
+ # Cop supports --auto-correct.
84
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
85
+ Style/BracesAroundHashParameters:
86
+ Enabled: false
87
+
88
+ # Offense count: 1
89
+ # Cop supports --auto-correct.
90
+ Style/ClosingParenthesisIndentation:
91
+ Enabled: false
92
+
93
+ # Offense count: 18
94
+ Style/Documentation:
95
+ Enabled: false
96
+
97
+ # Offense count: 3
98
+ Style/DoubleNegation:
99
+ Enabled: false
100
+
101
+ # Offense count: 5
102
+ # Cop supports --auto-correct.
103
+ Style/ElseAlignment:
104
+ Enabled: false
105
+
106
+ # Offense count: 16
107
+ # Cop supports --auto-correct.
108
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
109
+ Style/EmptyLinesAroundBlockBody:
110
+ Enabled: false
111
+
112
+ # Offense count: 6
113
+ # Cop supports --auto-correct.
114
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
115
+ Style/EmptyLinesAroundClassBody:
116
+ Enabled: false
117
+
118
+ # Offense count: 6
119
+ # Cop supports --auto-correct.
120
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
121
+ Style/EmptyLinesAroundModuleBody:
122
+ Enabled: false
123
+
124
+ # Offense count: 4
125
+ # Cop supports --auto-correct.
126
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
127
+ Style/FirstParameterIndentation:
128
+ Enabled: false
129
+
130
+ # Offense count: 1
131
+ # Cop supports --auto-correct.
132
+ # Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues.
133
+ Style/HashSyntax:
134
+ Enabled: false
135
+
136
+ # Offense count: 16
137
+ # Cop supports --auto-correct.
138
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
139
+ Style/IndentHash:
140
+ Enabled: false
141
+
142
+ # Offense count: 18
143
+ # Cop supports --auto-correct.
144
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
145
+ Style/IndentationConsistency:
146
+ Enabled: false
147
+
148
+ # Offense count: 3
149
+ # Cop supports --auto-correct.
150
+ # Configuration parameters: Width.
151
+ Style/IndentationWidth:
152
+ Enabled: false
153
+
154
+ # Offense count: 1
155
+ # Cop supports --auto-correct.
156
+ Style/LineEndConcatenation:
157
+ Enabled: false
158
+
159
+ # Offense count: 3
160
+ # Cop supports --auto-correct.
161
+ Style/MultilineBlockLayout:
162
+ Enabled: false
163
+
164
+ # Offense count: 10
165
+ # Cop supports --auto-correct.
166
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
167
+ Style/MultilineOperationIndentation:
168
+ Enabled: false
169
+
170
+ # Offense count: 2
171
+ # Cop supports --auto-correct.
172
+ # Configuration parameters: PreferredDelimiters.
173
+ Style/PercentLiteralDelimiters:
174
+ Enabled: false
175
+
176
+ # Offense count: 1
177
+ # Configuration parameters: NamePrefix, NamePrefixBlacklist.
178
+ Style/PredicateName:
179
+ Enabled: false
180
+
181
+ # Offense count: 3
182
+ # Configuration parameters: SupportedStyles.
183
+ Style/RaiseArgs:
184
+ EnforcedStyle: compact
185
+
186
+ # Offense count: 1
187
+ # Cop supports --auto-correct.
188
+ Style/RedundantSelf:
189
+ Enabled: false
190
+
191
+ # Offense count: 4
192
+ # Cop supports --auto-correct.
193
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
194
+ Style/SignalException:
195
+ Enabled: false
196
+
197
+ # Offense count: 4
198
+ # Cop supports --auto-correct.
199
+ Style/SingleSpaceBeforeFirstArg:
200
+ Enabled: false
201
+
202
+ # Offense count: 9
203
+ # Cop supports --auto-correct.
204
+ Style/SpaceAfterComma:
205
+ Enabled: false
206
+
207
+ # Offense count: 6
208
+ # Cop supports --auto-correct.
209
+ # Configuration parameters: MultiSpaceAllowedForOperators.
210
+ Style/SpaceAroundOperators:
211
+ Enabled: false
212
+
213
+ # Offense count: 5
214
+ # Cop supports --auto-correct.
215
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
216
+ Style/SpaceBeforeBlockBraces:
217
+ Enabled: false
218
+
219
+ # Offense count: 1
220
+ # Cop supports --auto-correct.
221
+ Style/SpaceBeforeSemicolon:
222
+ Enabled: false
223
+
224
+ # Offense count: 25
225
+ # Cop supports --auto-correct.
226
+ # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
227
+ Style/SpaceInsideBlockBraces:
228
+ Enabled: false
229
+
230
+ # Offense count: 145
231
+ # Cop supports --auto-correct.
232
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
233
+ Style/SpaceInsideHashLiteralBraces:
234
+ Enabled: false
235
+
236
+ # Offense count: 33
237
+ # Cop supports --auto-correct.
238
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
239
+ Style/StringLiterals:
240
+ Enabled: false
241
+
242
+ # Offense count: 1
243
+ # Cop supports --auto-correct.
244
+ # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
245
+ Style/TrivialAccessors:
246
+ Enabled: false
247
+
248
+ # Offense count: 2
249
+ # Cop supports --auto-correct.
250
+ Style/UnneededPercentQ:
251
+ Enabled: false
252
+
253
+ # Align with the style guide.
254
+ Style/CollectionMethods:
255
+ PreferredMethods:
256
+ collect: 'map'
257
+ collect!: 'map!'
258
+ inject: 'reduce'
259
+ detect: 'find'
260
+ find_all: 'select'
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.2
1
+ 2.4.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ This project adheres to [Semantic Versioning](http://semver.org/), although
4
+ "minor" (0.x) changes will include breaking changes until a stable 1.0 release.
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.6.0] - 2015-12-15
9
+ ### Changed
10
+
11
+ * [FEATURE] compatible with [new query / filter contexts](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html) for Elasticsearch 2.0+
12
+
data/Dockerfile ADDED
@@ -0,0 +1,12 @@
1
+ FROM ruby:slim
2
+ RUN apt-get update -qq && apt-get install -y \
3
+ git \
4
+ build-essential \
5
+ libpq-dev \
6
+ curl
7
+ RUN gem install bundler
8
+ RUN mkdir /stretchy
9
+ WORKDIR /stretchy
10
+ ADD . /stretchy
11
+ RUN bundle install
12
+
data/README.md CHANGED
@@ -52,7 +52,7 @@ Stretchy.client = Elasticsearch::Client.new
52
52
 
53
53
  ```ruby
54
54
  # returns a Stretchy::API object
55
- api = Stretchy.query(index: 'myapp_development', type: 'model_name')
55
+ api = Stretchy.query(index: 'myapp_development')
56
56
  ```
57
57
 
58
58
  From here, you can chain the methods to build your desired query.
@@ -219,7 +219,7 @@ Performs a query for the given string anywhere in the document. At least one of
219
219
  api = api.more_like(ids: [1, 2, 3])
220
220
  .more_like(docs: other_search.results)
221
221
  .more_like(
222
- like_text: 'puppies and kittens are great',
222
+ like: 'puppies and kittens are great',
223
223
  fields: ['about_me']
224
224
  )
225
225
  ```
@@ -436,7 +436,7 @@ Included in the Results object for Kaminari compatibility.
436
436
 
437
437
  ## Development
438
438
 
439
- After checking out the repo, run `bundle install` to install dependencies. Then, run `pry` for an interactive prompt that will allow you to experiment.
439
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `pry` for an interactive prompt that will allow you to experiment. Run specs with `rspec`
440
440
 
441
441
  ## Contributing
442
442
 
data/Rakefile CHANGED
@@ -13,8 +13,8 @@ namespace :fixtures do
13
13
  task :gen do
14
14
  require 'json'
15
15
 
16
- q = Stretchy.query(index: 'stretchy_test', type: 'game_dev')
17
- .match(_all: 'game')
16
+ q = Stretchy.query(index: 'stretchy_test')
17
+ .multi_match(query: 'game')
18
18
  .where(url_slug: [
19
19
  'masahiro-sakurai',
20
20
  'tetsuya-mizuguchi',
@@ -0,0 +1,24 @@
1
+ version: '2'
2
+ services:
3
+ elastictwo:
4
+ image: elasticsearch:2-alpine
5
+ elasticfive:
6
+ image: elasticsearch:5-alpine
7
+ testtwo:
8
+ build: .
9
+ command: bundle exec rake
10
+ environment:
11
+ ELASTICSEARCH_URL: 'elastictwo:9200'
12
+ volumes:
13
+ - .:/stretchy
14
+ links:
15
+ - elastictwo
16
+ testfive:
17
+ build: .
18
+ command: bundle exec rake
19
+ environment:
20
+ ELASTICSEARCH_URL: 'elasticfive:9200'
21
+ volumes:
22
+ - .:/stretchy
23
+ links:
24
+ - elastictwo
@@ -22,138 +22,65 @@ module Stretchy
22
22
  end
23
23
 
24
24
  def node
25
- @node ||= if boost_nodes.any?
25
+ @node ||= if function_score_node?
26
26
  function_score_node
27
- elsif filter_nodes.any?
28
- filtered_query_node
29
27
  elsif query_nodes.any?
30
- single_query_node
28
+ query_node
31
29
  else
32
30
  Node.new({match_all: {}}, context)
33
31
  end
34
32
  end
35
33
 
36
34
  def query_nodes
37
- @query_nodes ||= collect_nodes nodes do |n|
38
- n.context?(:query) &&
39
- !n.context?(:boost) &&
40
- !n.context?(:filter)
41
- end
42
- end
43
-
44
- def filter_node
45
- @filter_node ||= if query_nodes.any?
46
- if boost_nodes.any?
47
- Node.new({query: function_score_node.json}, context)
48
- elsif filter_nodes.any?
49
- Node.new({query: filtered_query_node.json}, context)
50
- else
51
- Node.new({query: single_query_node.json}, context)
52
- end
53
- else
54
- Node.new(compile_nodes(filter_nodes).json, context)
55
- end
56
- end
57
-
58
- def filter_json
59
- filter_node.json
35
+ @query_nodes ||= nodes.reject {|n| n.context? :boost }
60
36
  end
61
37
 
62
- def filter_nodes
63
- @filter_nodes ||= begin
64
- node_arr = collect_nodes nodes do |n|
65
- n.context?(:filter) &&
66
- !n.context?(:query) &&
67
- !n.context?(:boost)
68
- end
69
- node_arr += Array(compile_query_filter_node)
70
- node_arr.compact
71
- end
72
- end
73
-
74
- def query_filter_nodes
75
- @query_filter_nodes ||= collect_nodes nodes do |n|
76
- n.context?(:filter) &&
77
- n.context?(:query) &&
78
- !n.context?(:boost)
79
- end
38
+ def boost_nodes
39
+ @boost_nodes ||= nodes.select {|n| n.context? :boost }
80
40
  end
81
41
 
82
- def boost_nodes
83
- @boost_nodes ||= collect_nodes nodes do |n|
84
- n.context?(:boost)
85
- end
42
+ def function_score_node?
43
+ boost_nodes.reject { |n| n.empty? }.any?
86
44
  end
87
45
 
88
46
  private
89
47
 
90
- def collect_nodes(node_arr)
91
- coll = []
92
- node_arr.each do |n|
93
- next unless yield(n)
94
-
95
- if n.respond_to? :node
96
- coll << Node.new(n.node.json, n.context)
97
- else
98
- coll << n
99
- end
48
+ def query_node
49
+ if query_nodes.size > 1 || multicontext?(query_nodes)
50
+ compile_bool query_nodes
51
+ else
52
+ query_nodes.first
100
53
  end
101
- coll.compact
102
54
  end
103
55
 
104
- def compile_nodes(node_arr)
105
- if node_arr.size > 1 ||
106
- node_arr.any?{|n| n.context?(:must_not) || n.context?(:should)}
107
-
108
- compile_bool(node_arr)
109
- else
110
- node_arr.first
111
- end
56
+ def multicontext?(node_arr)
57
+ Array(node_arr).any? {|n| n.context?(:must_not) || n.context?(:should) }
112
58
  end
113
59
 
114
60
  def compile_bool(bool_nodes)
115
61
  split_nodes = split_nodes_for_bool(bool_nodes)
116
- bool_json = {}
117
- if split_nodes[:should_not].size > 0
118
- bool_json[:should] = [
119
- {
120
- bool: {
121
- must: split_nodes[:should].map(&:as_json),
122
- must_not: split_nodes[:should_not].map(&:as_json)
123
- }
124
- }
125
- ]
126
- else
127
- bool_json[:should] = split_nodes[:should].map(&:as_json)
62
+ refined = bool_ctx.each_with_object(split_nodes) do |k, hash|
63
+ hash[k] = Array(compile_bool(hash[k])) if multicontext? hash[k]
128
64
  end
129
- bool_json[:must_not] = split_nodes[:must_not].map(&:as_json)
130
- bool_json[:must] = split_nodes[:must].map(&:as_json)
65
+ bool_json = Hash[refined.map{|k,v| [k, v.map(&:as_json)] }]
131
66
  Node.new(bool: bool_json)
132
67
  end
133
68
 
69
+ def bool_ctx
70
+ [:filter, :must_not, :should]
71
+ end
72
+
134
73
  def split_nodes_for_bool(bool_nodes)
135
- split_nodes = {must: [], must_not: [], should: [], should_not: []}
136
- bool_nodes.each do |n|
137
- if n.context?(:should)
138
- if n.context?(:must_not)
139
- split_nodes[:should_not] << n
140
- else
141
- split_nodes[:should] << n
142
- end
143
- else
144
- if n.context?(:must_not)
145
- split_nodes[:must_not] << n
146
- else
147
- split_nodes[:must] << n
148
- end
149
- end
74
+ bool_nodes.each_with_object({}) do |n, hash|
75
+ key = bool_ctx.find{|c| n.context? c } || :must
76
+ hash[key] ||= []
77
+ hash[key] << Node.new(n.json, n.context.merge(key => nil))
150
78
  end
151
- split_nodes
152
79
  end
153
80
 
154
81
  def compile_boost_functions
155
82
  boost_nodes.map do |n|
156
- next unless n.json.any?
83
+ next if n.empty?
157
84
  n.json
158
85
  end.compact
159
86
  end
@@ -164,36 +91,13 @@ module Stretchy
164
91
  end
165
92
  end
166
93
 
167
- def compile_query_filter_node
168
- compiled = compile_nodes(query_filter_nodes)
169
- Node.new(query: compiled.json) if compiled
170
- end
171
-
172
94
  def function_score_node
173
95
  function_score_json = compile_function_score_options
174
96
  function_score_json[:functions] = compile_boost_functions
175
-
176
- if query_nodes.any?
177
- function_score_json[:query] = filtered_query_node.json
178
- elsif filter_nodes.any?
179
- function_score_json[:filter] = filter_node.json
180
- end
97
+ function_score_json[:query] = query_node.json if query_nodes.any?
181
98
 
182
99
  Node.new({function_score: function_score_json}, context)
183
100
  end
184
101
 
185
- def filtered_query_node
186
- filtered_json = {}
187
- q = compile_nodes(query_nodes)
188
- f = compile_nodes(filter_nodes)
189
- filtered_json[:query] = q.json if q
190
- filtered_json[:filter] = f.json if f
191
- Node.new({filtered: filtered_json}, context)
192
- end
193
-
194
- def single_query_node
195
- Node.new(compile_nodes(query_nodes).json, context)
196
- end
197
-
198
102
  end
199
103
  end
data/lib/stretchy/api.rb CHANGED
@@ -11,19 +11,11 @@ module Stretchy
11
11
 
12
12
  attr_reader :collector, :opts, :root, :body, :context
13
13
 
14
+ delegate [:with_context, :json, :as_json] => :collector
15
+
14
16
  delegate [
15
- :total,
16
- :total_count,
17
- :length,
18
- :size,
19
- :total_pages,
20
- :results,
21
- :hits,
22
- :to_a,
23
- :ids,
24
- :scores,
25
- :explanations,
26
- :aggregations
17
+ :total, :total_count, :length, :size, :total_pages, :results, :hits,
18
+ :to_a, :ids, :scores, :explanations, :aggregations, :each
27
19
  ] => :results_obj
28
20
 
29
21
  def initialize(opts = {})
@@ -74,9 +66,11 @@ module Stretchy
74
66
  end
75
67
 
76
68
  def fields(*list)
77
- add_root fields: list
69
+ add_root _source: list
78
70
  end
79
71
 
72
+ alias :source :fields
73
+
80
74
  def aggs(params = {})
81
75
  add_body aggs: params
82
76
  end
@@ -130,20 +124,19 @@ module Stretchy
130
124
  end
131
125
 
132
126
  def range(params = {})
133
- require_context!
134
127
  add_params params, nil, :range_node
135
128
  end
136
129
 
137
130
  def geo_distance(params = {})
138
- add_params params, :filter, :geo_distance_node
131
+ add_params params, nil, :geo_distance_node
139
132
  end
140
133
 
141
134
  def boost(params = {}, options = {})
142
- return add_context(:boost) unless params.any?
135
+ return add_context(:boost) if Utils.is_empty? params
143
136
 
144
137
  subcontext = context.merge(boost: true)
145
138
  if params.is_a? self.class
146
- boost_json = options.merge(filter: params.filter_node.json)
139
+ boost_json = options.merge(filter: params.json)
147
140
  add_nodes Node.new(boost_json, subcontext)
148
141
  else
149
142
  add_nodes Factory.raw_boost_node(params, subcontext)
@@ -184,21 +177,8 @@ module Stretchy
184
177
  results_obj.ids.count
185
178
  end
186
179
 
187
- def method_missing(method, *args, &block)
188
- if collector.respond_to?(method)
189
- collector.send(method, *args, &block)
190
- else
191
- super
192
- end
193
- end
194
-
195
180
  private
196
181
 
197
- def require_context!
198
- return true if context?(:query) || context?(:filter)
199
- raise 'You must specify either query or filter context'
200
- end
201
-
202
182
  def args_to_context(*args)
203
183
  args.reduce({}) do |ctx, item|
204
184
  next ctx if item.nil?
@@ -23,9 +23,7 @@ module Stretchy
23
23
  end
24
24
 
25
25
  def extract_boost_params!(params)
26
- boost_params = Utils.extract_options!(params, BOOST_OPTIONS)
27
- boost_params = {weight: DEFAULT_WEIGHT} unless boost_params.any?
28
- boost_params
26
+ Utils.extract_options!(params, BOOST_OPTIONS)
29
27
  end
30
28
 
31
29
  def extract_function_score_options!(params)
@@ -53,19 +51,17 @@ module Stretchy
53
51
  context[:fn_score] = extract_function_score_options!(params)
54
52
  context[:boost] = true
55
53
  context[:filter] = true
56
- json = context[:query] ? {query: params} : params
57
- Node.new(boost_params.merge(filter: json), context)
54
+ boost_params.merge!(filter: params) unless Utils.is_empty? params
55
+ Node.new(boost_params, context)
58
56
  end
59
57
 
60
58
  def context_nodes(params, context = default_context)
61
- subparams = dotify_params(params, context)
62
-
63
59
  if context[:boost]
64
- params_to_boost(subparams, context)
65
- elsif context[:query]
66
- params_to_queries(subparams, context)
60
+ params_to_boost(params, context)
61
+ elsif context[:filter] && !context[:query]
62
+ params_to_filters(dotify_params(params, context), context)
67
63
  else
68
- params_to_filters(subparams, context)
64
+ params_to_queries(dotify_params(params, context), context)
69
65
  end
70
66
  end
71
67
 
@@ -76,14 +72,12 @@ module Stretchy
76
72
  nodes = context_nodes(params, subcontext)
77
73
  collector = AndCollector.new(nodes, subcontext)
78
74
 
79
- if context[:query]
80
- Node.new(boost_params.merge(filter: {query: collector.json}), context)
81
- else
82
- Node.new(
83
- boost_params.merge(filter: collector.filter_node.json),
84
- context
85
- )
75
+ boost_params.merge!(filter: collector.json) if collector.any?
76
+ if boost_params.count == 1 && boost_params.key?(:filter)
77
+ boost_params[:weight] = DEFAULT_WEIGHT
86
78
  end
79
+
80
+ Node.new(boost_params, context)
87
81
  end
88
82
 
89
83
  def params_to_queries(params, context = default_context)
@@ -100,7 +94,11 @@ module Stretchy
100
94
  when Hash
101
95
  nested(val, field, context)
102
96
  else
103
- Node.new({match: {field => val}}, context)
97
+ if field == '_all'
98
+ Node.new({multi_match: {:query => val}}, context)
99
+ else
100
+ Node.new({match: {field => val}}, context)
101
+ end
104
102
  end
105
103
  end
106
104
  end
@@ -111,7 +109,8 @@ module Stretchy
111
109
  when Range
112
110
  Node.new({range: {field => {gte: val.min, lte: val.max}}}, context)
113
111
  when nil
114
- Node.new({missing: {field: field}}, context)
112
+ nil_ctx = context.merge(must_not: true)
113
+ Node.new({exists: {field: field}}, nil_ctx)
115
114
  when Hash
116
115
  nested(val, field, context)
117
116
  else
@@ -121,19 +120,16 @@ module Stretchy
121
120
  end
122
121
 
123
122
  def nested(params, path, context = default_context)
124
- type, json = if context[:query]
125
- nodes = params_to_queries(params, context)
126
- json = AndCollector.new(nodes, context).json
127
- [:query, json]
123
+ nodes = if context[:filter] && !context[:query]
124
+ params_to_filters(params, context)
128
125
  else
129
- nodes = params_to_filters(params, context)
130
- json = AndCollector.new(nodes, context).filter_json
131
- [:filter, json]
126
+ params_to_queries(params, context)
132
127
  end
128
+ json = AndCollector.new(nodes, context).json
133
129
 
134
130
  Node.new({nested: {
135
131
  path: path,
136
- type => json
132
+ query: json
137
133
  }}, context)
138
134
  end
139
135
 
@@ -141,18 +137,16 @@ module Stretchy
141
137
  def fulltext_nodes_from_string(params, context = default_context)
142
138
  subcontext = context.merge(query: true)
143
139
  nodes = [raw_node({
144
- match: {
145
- _all: {
140
+ multi_match: {
146
141
  query: params,
147
142
  minimum_should_match: 1
148
143
  }
149
- }
150
144
  }, subcontext)]
151
145
 
152
146
  subcontext = subcontext.merge(should: true)
153
147
  nodes << Factory.raw_node({
154
148
  match_phrase: {
155
- _all: {
149
+ multi_match: {
156
150
  query: params,
157
151
  slop: DEFAULT_SLOP
158
152
  }
@@ -188,7 +182,7 @@ module Stretchy
188
182
 
189
183
  # https://www.elastic.co/guide/en/elasticsearch/reference/current/querydslfunctionscorequery.html#functionrandom
190
184
  def random_score_function_node(params, context = default_context)
191
- json = {random_score: {seed: params[:seed]}}
185
+ json = {random_score: {seed: params[:seed], field: :id}}
192
186
  json[:weight] = params[:weight] if params[:weight]
193
187
  Node.new(json, context)
194
188
  end
data/lib/stretchy/node.rb CHANGED
@@ -9,6 +9,10 @@ module Stretchy
9
9
  @context = context
10
10
  end
11
11
 
12
+ def empty?
13
+ !@json.any?
14
+ end
15
+
12
16
  def context?(*args)
13
17
  args.all? {|c| !!context[c] }
14
18
  end
@@ -1,3 +1,4 @@
1
+ require 'json'
1
2
  module Stretchy
2
3
  class Results
3
4
 
@@ -12,7 +13,10 @@ module Stretchy
12
13
  def self.fake
13
14
  self.new(
14
15
  {size: API::DEFAULT_PER_PAGE, fake: true},
15
- {'hits' => {'total' => 0, 'hits' => [], 'aggregations' => {}}}
16
+ {'hits' => {'total' => {
17
+ "value" => 3,
18
+ "relation" => "eq"
19
+ }, 'hits' => [], 'aggregations' => {}}}
16
20
  )
17
21
  end
18
22
 
@@ -43,7 +47,7 @@ module Stretchy
43
47
  end
44
48
 
45
49
  def total
46
- response['hits']['total']
50
+ response['hits']['total']['value']
47
51
  end
48
52
  alias :total_count :total
49
53
  alias :count :total
@@ -5,7 +5,9 @@ module Stretchy
5
5
  # detects empty string, empty array, empty hash, nil
6
6
  def is_empty?(arg = nil)
7
7
  return true if arg.nil?
8
- if arg.respond_to?(:any?)
8
+ if arg.respond_to?(:collector)
9
+ !arg.collector.any?
10
+ elsif arg.respond_to?(:any?)
9
11
  !arg.any? {|a| !is_empty?(a) }
10
12
  elsif arg.respond_to?(:empty?)
11
13
  arg.empty?
@@ -1,3 +1,3 @@
1
1
  module Stretchy
2
- VERSION = "0.5.3"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/stretchy.rb CHANGED
@@ -58,7 +58,7 @@ module Stretchy
58
58
  end
59
59
 
60
60
  def index_document(params = {})
61
- Utils.require_params!(:index_document, params, :index, :type, :body)
61
+ Utils.require_params!(:index_document, params, :index, :body)
62
62
 
63
63
  raise IndexDoesNotExistError.new(
64
64
  "index #{params[:index]} does not exist"
data/solano.yml CHANGED
@@ -1,9 +1,9 @@
1
1
  ---
2
- ruby_version: ruby-2.2.2
3
- bundler_version: 1.9.4
2
+ ruby_version: ruby-2.4.2
3
+ bundler_version: 1.14.6
4
4
  test_pattern:
5
5
  - spec/**/*_spec.rb
6
6
  elasticsearch:
7
- version: '1.6'
7
+ version: 5.0.1
8
8
  java:
9
- java_version: java-7-openjdk
9
+ java_version: java-8-openjdk
data/stretchy.gemspec CHANGED
@@ -19,14 +19,13 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency "elasticsearch", "~> 1.0"
22
+ spec.add_dependency "elasticsearch", "~> 7.0"
23
23
  spec.add_dependency "excon", "~> 0.45"
24
24
 
25
- spec.add_development_dependency "bundler", "~> 1.8"
26
- spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rake", "~> 10.4"
27
26
  spec.add_development_dependency "rspec", "~> 3.2"
28
27
  spec.add_development_dependency "fuubar", "~> 2.0"
29
28
  spec.add_development_dependency "pry", "~> 0.10"
30
29
  spec.add_development_dependency "awesome_print", "~> 1.6"
31
- spec.add_development_dependency "yard", "~> 0.8"
30
+ spec.add_development_dependency "yard", "~> 0.9"
32
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stretchy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - agius
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-30 00:00:00.000000000 Z
11
+ date: 2021-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elasticsearch
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: excon
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,34 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.45'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.8'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.8'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '10.0'
47
+ version: '10.4'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '10.0'
54
+ version: '10.4'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rspec
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +114,14 @@ dependencies:
128
114
  requirements:
129
115
  - - "~>"
130
116
  - !ruby/object:Gem::Version
131
- version: '0.8'
117
+ version: '0.9'
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
122
  - - "~>"
137
123
  - !ruby/object:Gem::Version
138
- version: '0.8'
124
+ version: '0.9'
139
125
  description: Build queries for Elasticsearch with a chainable interface like ActiveRecord's.
140
126
  email:
141
127
  - andrew@atevans.com
@@ -145,14 +131,18 @@ extra_rdoc_files: []
145
131
  files:
146
132
  - ".editorconfig"
147
133
  - ".gitignore"
134
+ - ".rubocop.yml"
148
135
  - ".ruby-version"
149
136
  - ".yardopts"
137
+ - CHANGELOG.md
150
138
  - CONTRIBUTING.md
139
+ - Dockerfile
151
140
  - Gemfile
152
141
  - README.md
153
142
  - Rakefile
154
143
  - bin/console
155
144
  - bin/setup
145
+ - docker-compose.yml
156
146
  - lib/stretchy.rb
157
147
  - lib/stretchy/and_collector.rb
158
148
  - lib/stretchy/api.rb
@@ -184,10 +174,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
174
  - !ruby/object:Gem::Version
185
175
  version: '0'
186
176
  requirements: []
187
- rubyforge_project:
188
- rubygems_version: 2.4.5
177
+ rubygems_version: 3.0.3
189
178
  signing_key:
190
179
  specification_version: 4
191
180
  summary: Query builder for Elasticsearch
192
181
  test_files: []
193
- has_rdoc: