chewy_query 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +37 -0
  7. data/Rakefile +2 -0
  8. data/chewy_query.gemspec +27 -0
  9. data/lib/chewy_query.rb +12 -0
  10. data/lib/chewy_query/builder.rb +865 -0
  11. data/lib/chewy_query/builder/compose.rb +64 -0
  12. data/lib/chewy_query/builder/criteria.rb +182 -0
  13. data/lib/chewy_query/builder/filters.rb +227 -0
  14. data/lib/chewy_query/builder/nodes/and.rb +26 -0
  15. data/lib/chewy_query/builder/nodes/base.rb +17 -0
  16. data/lib/chewy_query/builder/nodes/bool.rb +33 -0
  17. data/lib/chewy_query/builder/nodes/equal.rb +34 -0
  18. data/lib/chewy_query/builder/nodes/exists.rb +20 -0
  19. data/lib/chewy_query/builder/nodes/expr.rb +28 -0
  20. data/lib/chewy_query/builder/nodes/field.rb +106 -0
  21. data/lib/chewy_query/builder/nodes/has_child.rb +14 -0
  22. data/lib/chewy_query/builder/nodes/has_parent.rb +14 -0
  23. data/lib/chewy_query/builder/nodes/has_relation.rb +61 -0
  24. data/lib/chewy_query/builder/nodes/match_all.rb +11 -0
  25. data/lib/chewy_query/builder/nodes/missing.rb +20 -0
  26. data/lib/chewy_query/builder/nodes/not.rb +26 -0
  27. data/lib/chewy_query/builder/nodes/or.rb +26 -0
  28. data/lib/chewy_query/builder/nodes/prefix.rb +18 -0
  29. data/lib/chewy_query/builder/nodes/query.rb +20 -0
  30. data/lib/chewy_query/builder/nodes/range.rb +63 -0
  31. data/lib/chewy_query/builder/nodes/raw.rb +15 -0
  32. data/lib/chewy_query/builder/nodes/regexp.rb +33 -0
  33. data/lib/chewy_query/builder/nodes/script.rb +20 -0
  34. data/lib/chewy_query/version.rb +3 -0
  35. data/spec/chewy_query/builder/context_spec.rb +529 -0
  36. data/spec/chewy_query/builder/filters_spec.rb +181 -0
  37. data/spec/chewy_query/builder/nodes/and_spec.rb +16 -0
  38. data/spec/chewy_query/builder/nodes/bool_spec.rb +22 -0
  39. data/spec/chewy_query/builder/nodes/equal_spec.rb +58 -0
  40. data/spec/chewy_query/builder/nodes/exists_spec.rb +16 -0
  41. data/spec/chewy_query/builder/nodes/has_child_spec.rb +79 -0
  42. data/spec/chewy_query/builder/nodes/has_parent_spec.rb +84 -0
  43. data/spec/chewy_query/builder/nodes/match_all_spec.rb +11 -0
  44. data/spec/chewy_query/builder/nodes/missing_spec.rb +14 -0
  45. data/spec/chewy_query/builder/nodes/not_spec.rb +14 -0
  46. data/spec/chewy_query/builder/nodes/or_spec.rb +16 -0
  47. data/spec/chewy_query/builder/nodes/prefix_spec.rb +15 -0
  48. data/spec/chewy_query/builder/nodes/query_spec.rb +17 -0
  49. data/spec/chewy_query/builder/nodes/range_spec.rb +36 -0
  50. data/spec/chewy_query/builder/nodes/raw_spec.rb +11 -0
  51. data/spec/chewy_query/builder/nodes/regexp_spec.rb +45 -0
  52. data/spec/chewy_query/builder/nodes/script_spec.rb +16 -0
  53. data/spec/chewy_query/builder_spec.rb +196 -0
  54. data/spec/chewy_query_spec.rb +0 -0
  55. data/spec/spec_helper.rb +8 -0
  56. metadata +191 -0
@@ -0,0 +1,18 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Prefix < Expr
5
+ def initialize(name, value, options = {})
6
+ @name = name.to_s
7
+ @value, @options = value, options
8
+ end
9
+
10
+ def __render__
11
+ filter = { prefix: { @name => @value } }
12
+ filter[:prefix][:_cache] = !!@options[:cache] if @options.key?(:cache)
13
+ filter
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Query < Expr
5
+ def initialize(query, options = {})
6
+ @query = query
7
+ @options = options
8
+ end
9
+
10
+ def __render__
11
+ if @options.key?(:cache)
12
+ { fquery: { query: @query, _cache: !!@options[:cache] } }
13
+ else
14
+ { query: @query }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Range < Expr
5
+ EXECUTION = {
6
+ i: :index,
7
+ index: :index,
8
+ f: :fielddata,
9
+ fielddata: :fielddata
10
+ }
11
+
12
+ def initialize(name, *args)
13
+ @name = name.to_s
14
+ @options = args.extract_options!
15
+ @range = @options.reject{|k, v| ![:gt, :lt].include?(k) }
16
+ @bounds = @options.reject{|k, v| ![:left_closed, :right_closed].include?(k) }
17
+ execution = EXECUTION[args.first.to_sym] if args.first
18
+ @options[:execution] = execution if execution
19
+ end
20
+
21
+ def &(other)
22
+ if other.is_a?(self.class) && other.__name__ == @name
23
+ state = __state__.merge(other.__state__)
24
+
25
+ cache = other.__options__[:cache] || @options[:cache]
26
+ state[:cache] = cache unless cache.nil?
27
+
28
+ execution = other.__options__[:execution] || @options[:execution]
29
+ state[:execution] = execution unless execution.nil?
30
+
31
+ self.class.new(@name, state)
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def __name__
38
+ @name
39
+ end
40
+
41
+ def __state__
42
+ @range.merge(@bounds)
43
+ end
44
+
45
+ def __options__
46
+ @options
47
+ end
48
+
49
+ def __render__
50
+ body = {}
51
+ body[@bounds[:left_closed] ? :gte : :gt] = @range[:gt] if @range.key?(:gt)
52
+ body[@bounds[:right_closed] ? :lte : :lt] = @range[:lt] if @range.key?(:lt)
53
+
54
+ filter = { @name => body }
55
+ filter[:_cache] = !!@options[:cache] if @options.key?(:cache)
56
+ filter.merge!(@options.slice(:execution))
57
+
58
+ { range: filter }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Raw < Expr
5
+ def initialize(raw)
6
+ @raw = raw
7
+ end
8
+
9
+ def __render__
10
+ @raw
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Regexp < Expr
5
+ FLAGS = %w(all anystring automaton complement empty intersection interval none)
6
+
7
+ def initialize(name, regexp, *args)
8
+ @name = name.to_s
9
+ @regexp = regexp.respond_to?(:source) ? regexp.source : regexp.to_s
10
+ @options = args.extract_options!
11
+
12
+ if args.any? || @options[:flags].present?
13
+ @options[:flags] = FLAGS & (args.any? ? args.flatten : @options[:flags]).map(&:to_s).map(&:downcase)
14
+ end
15
+ end
16
+
17
+ def __render__
18
+ body = @options[:flags] ?
19
+ { value: @regexp, flags: @options[:flags].map(&:to_s).map(&:upcase).uniq.join('|') } : @regexp
20
+
21
+ filter = { @name => body }
22
+
23
+ if @options.key?(:cache)
24
+ filter[:_cache] = !!@options[:cache]
25
+ filter[:_cache_key] = @options[:cache].is_a?(TrueClass) || @options[:cache].is_a?(FalseClass) ?
26
+ @regexp.underscore : @options[:cache]
27
+ end
28
+ { regexp: filter }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Script < Expr
5
+ def initialize(script, params = {})
6
+ @script = script
7
+ @params = params
8
+ @options = params.reject{|k, v| ![:cache].include?(k) }
9
+ end
10
+
11
+ def __render__
12
+ script = { script: @script }
13
+ script.merge!(params: @params) if @params.present?
14
+ script.merge!(_cache: !!@options[:cache]) if @options.key?(:cache)
15
+ { script: script }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module ChewyQuery
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,529 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChewyQuery::Builder::Criteria do
4
+ subject{ described_class.new }
5
+
6
+ its(:options){ should be_a(Hash) }
7
+ its(:request_options){ should be_a(Hash) }
8
+ its(:facets){ should eq({}) }
9
+ its(:aggregations){ should eq({}) }
10
+ its(:queries){ should eq([]) }
11
+ its(:filters){ should eq([]) }
12
+ its(:post_filters){ should eq([]) }
13
+ its(:sort){ should eq([]) }
14
+ its(:fields){ should eq([]) }
15
+ its(:types){ should eq([]) }
16
+
17
+ its(:request_options?){ should be_falsy }
18
+ its(:facets?){ should be_falsy }
19
+ its(:aggregations?){ should be_falsy }
20
+ its(:queries?){ should be_falsy }
21
+ its(:filters?){ should be_falsy }
22
+ its(:post_filters?){ should be_falsy }
23
+ its(:sort?){ should be_falsy }
24
+ its(:fields?){ should be_falsy }
25
+ its(:types?){ should be_falsy }
26
+ its(:none?){ should be_falsy }
27
+
28
+ describe '#update_options' do
29
+ specify{ expect{ subject.update_options(field: 'hello') }.to change{
30
+ subject.options
31
+ }.to(hash_including(field: 'hello')) }
32
+ end
33
+
34
+ describe '#update_request_options' do
35
+ specify{ expect{ subject.update_request_options(field: 'hello') }.to change{
36
+ subject.request_options
37
+ }.to(hash_including(field: 'hello')) }
38
+ end
39
+
40
+ describe '#update_facets' do
41
+ specify{ expect{ subject.update_facets(field: 'hello') }.to change{ subject.facets? }.to(true) }
42
+ specify{ expect{ subject.update_facets(field: 'hello') }.to change{ subject.facets }.to(field: 'hello') }
43
+ end
44
+
45
+ describe '#update_aggregations' do
46
+ specify{ expect{ subject.update_aggregations(field: 'hello') }.to change{ subject.aggregations? }.to(true) }
47
+ specify{ expect{ subject.update_aggregations(field: 'hello') }.to change{ subject.aggregations }.to(field: 'hello') }
48
+ end
49
+
50
+ describe '#update_queries' do
51
+ specify{ expect{ subject.update_queries(field: 'hello') }.to change{ subject.queries? }.to(true) }
52
+ specify{ expect{ subject.update_queries(field: 'hello') }.to change{ subject.queries }.to([field: 'hello']) }
53
+ specify{ expect{
54
+ subject.update_queries(field: 'hello')
55
+ subject.update_queries(field: 'world')
56
+ }.to change { subject.queries }.to([{ field: 'hello' }, { field: 'world' }]) }
57
+
58
+ specify{ expect{
59
+ subject.update_queries([{ field: 'hello' }, { field: 'world' }, nil])
60
+ }.to change { subject.queries }.to([{ field: 'hello' }, { field: 'world' }]) }
61
+ end
62
+
63
+ describe '#update_filters' do
64
+ specify{ expect{ subject.update_filters(field: 'hello') }.to change{ subject.filters? }.to(true) }
65
+ specify{ expect{ subject.update_filters(field: 'hello') }.to change{ subject.filters }.to([{field: 'hello'}]) }
66
+ specify{ expect{
67
+ subject.update_filters(field: 'hello')
68
+ subject.update_filters(field: 'world')
69
+ }.to change { subject.filters }.to([{ field: 'hello' }, { field: 'world' }]) }
70
+
71
+ specify{ expect{
72
+ subject.update_filters([{ field: 'hello' }, { field: 'world' }, nil])
73
+ }.to change{ subject.filters }.to([{ field: 'hello' }, { field: 'world' }]) }
74
+ end
75
+
76
+ describe '#update_post_filters' do
77
+ specify{ expect{ subject.update_post_filters(field: 'hello') }.to change { subject.post_filters? }.to(true) }
78
+ specify{ expect{ subject.update_post_filters(field: 'hello') }.to change { subject.post_filters }.to([{field: 'hello'}]) }
79
+ specify{ expect{
80
+ subject.update_post_filters(field: 'hello')
81
+ subject.update_post_filters(field: 'world')
82
+ }.to change{ subject.post_filters }.to([{ field: 'hello' }, { field: 'world' }]) }
83
+
84
+ specify{ expect{
85
+ subject.update_post_filters([{ field: 'hello' }, { field: 'world' }, nil])
86
+ }.to change{ subject.post_filters }.to([{ field: 'hello' }, { field: 'world' }]) }
87
+ end
88
+
89
+ describe '#update_sort' do
90
+ specify{ expect{ subject.update_sort(:field) }.to change{ subject.sort? }.to(true) }
91
+
92
+ specify{ expect{ subject.update_sort([:field]) }.to change{ subject.sort }.to([:field]) }
93
+ specify{ expect{ subject.update_sort([:field1, :field2]) }.to change{ subject.sort }.to([:field1, :field2]) }
94
+ specify{ expect{ subject.update_sort([{field: :asc}]) }.to change{ subject.sort }.to([{field: :asc}]) }
95
+ specify{ expect{
96
+ subject.update_sort([:field1, field2: { order: :asc }])
97
+ }.to change{ subject.sort }.to([:field1, { field2: { order: :asc } }]) }
98
+
99
+ specify{ expect{
100
+ subject.update_sort([{ field1: { order: :asc } }, :field2])
101
+ }.to change{ subject.sort }.to([{ field1: { order: :asc }} , :field2]) }
102
+
103
+ specify{ expect{
104
+ subject.update_sort([field1: :asc, field2: { order: :asc }])
105
+ }.to change{ subject.sort }.to([{ field1: :asc }, { field2: { order: :asc } }]) }
106
+
107
+ specify{ expect{
108
+ subject.update_sort([{ field1: { order: :asc } }, :field2, :field3])
109
+ }.to change { subject.sort }.to([{ field1: { order: :asc } }, :field2, :field3]) }
110
+
111
+ specify{ expect{
112
+ subject.update_sort([{ field1: { order: :asc } }, [:field2, :field3]])
113
+ }.to change{ subject.sort }.to([{ field1: { order: :asc } }, :field2, :field3]) }
114
+
115
+ specify{ expect{
116
+ subject.update_sort([{ field1: { order: :asc } }, [:field2], :field3])
117
+ }.to change{ subject.sort }.to([{ field1: { order: :asc } }, :field2, :field3]) }
118
+
119
+ specify{ expect{
120
+ subject.update_sort([{ field1: { order: :asc }, field2: :desc }, [:field3], :field4])
121
+ }.to change{ subject.sort }.to([{ field1: { order: :asc } }, { field2: :desc }, :field3, :field4]) }
122
+
123
+ specify{ expect{
124
+ subject.tap{|s| s.update_sort([field1: { order: :asc }, field2: :desc]) }.update_sort([[:field3], :field4])
125
+ }.to change{ subject.sort }.to([{ field1: { order: :asc } }, { field2: :desc }, :field3, :field4]) }
126
+
127
+ specify{ expect{
128
+ subject.tap{|s|
129
+ s.update_sort([field1: { order: :asc }, field2: :desc])
130
+ }.update_sort([[:field3], :field4], purge: true)
131
+ }.to change{ subject.sort }.to([:field3, :field4]) }
132
+ end
133
+
134
+ describe '#update_fields' do
135
+ specify{ expect{ subject.update_fields(:field) }.to change{ subject.fields? }.to(true) }
136
+ specify{ expect{ subject.update_fields(:field) }.to change{ subject.fields }.to(['field']) }
137
+ specify{ expect{ subject.update_fields([:field, :field]) }.to change{ subject.fields }.to(['field']) }
138
+ specify{ expect{ subject.update_fields([:field1, :field2]) }.to change{ subject.fields }.to(['field1', 'field2']) }
139
+ specify{ expect{
140
+ subject.tap{|s| s.update_fields(:field1) }.update_fields([:field2, :field3])
141
+ }.to change{ subject.fields }.to(['field1', 'field2', 'field3']) }
142
+
143
+ specify{ expect{
144
+ subject.tap{|s| s.update_fields(:field1) }.update_fields([:field2, :field3], purge: true)
145
+ }.to change{ subject.fields }.to(['field2', 'field3']) }
146
+ end
147
+
148
+ describe '#update_types' do
149
+ specify{ expect{ subject.update_types(:type) }.to change{ subject.types? }.to(true) }
150
+ specify{ expect{ subject.update_types(:type) }.to change{ subject.types }.to(['type']) }
151
+ specify{ expect{ subject.update_types([:type, :type]) }.to change{ subject.types }.to(['type']) }
152
+ specify{ expect{ subject.update_types([:type1, :type2]) }.to change{ subject.types }.to(['type1', 'type2']) }
153
+ specify{
154
+ expect{ subject.tap{|s| s.update_types(:type1) }.update_types([:type2, :type3])
155
+ }.to change{ subject.types }.to(['type1', 'type2', 'type3']) }
156
+
157
+ specify{
158
+ expect{ subject.tap{|s| s.update_types(:type1) }.update_types([:type2, :type3], purge: true)
159
+ }.to change{ subject.types }.to(['type2', 'type3']) }
160
+ end
161
+
162
+ describe '#merge' do
163
+ let(:criteria){ described_class.new }
164
+
165
+ specify{ expect(subject.merge(criteria)).not_to be_equal(subject) }
166
+ specify{ expect(subject.merge(criteria)).not_to be_equal(criteria) }
167
+
168
+ specify{ expect(
169
+ subject.tap{|c| c.update_options(opt1: 'hello') }.
170
+ merge(criteria.tap{|c| c.update_options(opt2: 'hello') }).options
171
+ ).to include(opt1: 'hello', opt2: 'hello') }
172
+
173
+ specify{ expect(
174
+ subject.tap{|c| c.update_request_options(opt1: 'hello') }.
175
+ merge(criteria.tap{|c| c.update_request_options(opt2: 'hello') }).request_options
176
+ ).to include(opt1: 'hello', opt2: 'hello') }
177
+
178
+ specify{ expect(
179
+ subject.tap{|c| c.update_facets(field1: 'hello') }.
180
+ merge(criteria.tap{|c| c.update_facets(field1: 'hello') }).facets
181
+ ).to eq(field1: 'hello', field1: 'hello') }
182
+
183
+ specify{ expect(
184
+ subject.tap{|c| c.update_aggregations(field1: 'hello') }.
185
+ merge(criteria.tap{|c| c.update_aggregations(field1: 'hello') }).aggregations
186
+ ).to eq(field1: 'hello', field1: 'hello') }
187
+
188
+ specify{ expect(
189
+ subject.tap{|c| c.update_queries(field1: 'hello') }.
190
+ merge(criteria.tap{|c| c.update_queries(field2: 'hello') }).queries
191
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
192
+
193
+ specify{ expect(
194
+ subject.tap{|c| c.update_filters(field1: 'hello') }.
195
+ merge(criteria.tap{|c| c.update_filters(field2: 'hello') }).filters
196
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
197
+
198
+ specify{ expect(
199
+ subject.tap{|c| c.update_post_filters(field1: 'hello') }.
200
+ merge(criteria.tap{|c| c.update_post_filters(field2: 'hello') }).post_filters
201
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
202
+
203
+ specify{ expect(
204
+ subject.tap{|c| c.update_sort(:field1) }.merge(criteria.tap{|c| c.update_sort(:field2) }).sort
205
+ ).to eq([:field1, :field2]) }
206
+
207
+ specify{ expect(
208
+ subject.tap{|c| c.update_fields(:field1) }.merge(criteria.tap{|c| c.update_fields(:field2) }).fields
209
+ ).to eq(['field1', 'field2']) }
210
+
211
+ specify{ expect(
212
+ subject.tap{|c| c.update_types(:type1) }.merge(criteria.tap{|c| c.update_types(:type2) }).types
213
+ ).to eq(['type1', 'type2']) }
214
+ end
215
+
216
+ describe '#merge!' do
217
+ let(:criteria){ described_class.new }
218
+
219
+ specify{ expect(subject.merge!(criteria)).to be_equal(subject) }
220
+ specify{ expect(subject.merge!(criteria)).not_to be_equal(criteria) }
221
+
222
+ specify{ expect(
223
+ subject.tap{|c| c.update_options(opt1: 'hello') }.
224
+ merge!(criteria.tap{|c| c.update_options(opt2: 'hello') }).options
225
+ ).to include(opt1: 'hello', opt2: 'hello') }
226
+
227
+ specify{ expect(
228
+ subject.tap{|c| c.update_request_options(opt1: 'hello') }.
229
+ merge!(criteria.tap{|c| c.update_request_options(opt2: 'hello') }).request_options
230
+ ).to include(opt1: 'hello', opt2: 'hello') }
231
+
232
+ specify{ expect(
233
+ subject.tap{|c| c.update_facets(field1: 'hello') }.
234
+ merge!(criteria.tap{|c| c.update_facets(field1: 'hello') }).facets
235
+ ).to eq(field1: 'hello', field1: 'hello') }
236
+
237
+ specify{ expect(
238
+ subject.tap{|c| c.update_aggregations(field1: 'hello') }.
239
+ merge!(criteria.tap{|c| c.update_aggregations(field1: 'hello') }).aggregations
240
+ ).to eq(field1: 'hello', field1: 'hello') }
241
+
242
+ specify{ expect(
243
+ subject.tap{|c| c.update_queries(field1: 'hello') }.
244
+ merge!(criteria.tap{|c| c.update_queries(field2: 'hello') }).queries
245
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
246
+
247
+ specify{ expect(
248
+ subject.tap{|c| c.update_filters(field1: 'hello') }.
249
+ merge!(criteria.tap{|c| c.update_filters(field2: 'hello') }).filters
250
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
251
+
252
+ specify{ expect(
253
+ subject.tap{|c| c.update_post_filters(field1: 'hello') }.
254
+ merge!(criteria.tap{|c| c.update_post_filters(field2: 'hello') }).post_filters
255
+ ).to eq([{ field1: 'hello' }, { field2: 'hello' }]) }
256
+
257
+ specify{ expect(
258
+ subject.tap{|c| c.update_sort(:field1) }.merge!(criteria.tap{|c| c.update_sort(:field2) }).sort
259
+ ).to eq([:field1, :field2]) }
260
+
261
+ specify{ expect(
262
+ subject.tap{|c| c.update_fields(:field1) }.merge!(criteria.tap{|c| c.update_fields(:field2) }).fields
263
+ ).to eq(['field1', 'field2']) }
264
+
265
+ specify{ expect(
266
+ subject.tap{|c| c.update_types(:type1) }.merge!(criteria.tap{|c| c.update_types(:type2) }).types
267
+ ).to eq(['type1', 'type2']) }
268
+ end
269
+
270
+ describe '#request_body' do
271
+ def request_body(&block)
272
+ subject.instance_exec(&block) if block
273
+ subject.request_body
274
+ end
275
+
276
+ specify{ expect(request_body).to eq(body: {}) }
277
+ specify{ expect(request_body{ update_request_options(size: 10) }).to eq(body: { size: 10 }) }
278
+ specify{ expect(request_body{ update_request_options(from: 10) }).to eq(body: { from: 10 }) }
279
+ specify{ expect(request_body{ update_request_options(explain: true) }).to eq(body: { explain: true }) }
280
+ specify{ expect(request_body{ update_queries(:query) }).to eq(body: { query: :query }) }
281
+ specify{ expect(request_body{
282
+ update_request_options(from: 10)
283
+ update_sort(:field)
284
+ update_fields(:field)
285
+ update_queries(:query)
286
+ }).to eq(body: { query: :query, from: 10, sort: [:field], _source: ['field'] }) }
287
+
288
+ specify{ expect(request_body{
289
+ update_queries(:query)
290
+ update_filters(:filters)
291
+ }).to eq(body: { query: { filtered: { query: :query, filter: :filters } } }) }
292
+
293
+ specify{ expect(request_body{
294
+ update_queries(:query)
295
+ update_post_filters(:post_filter)
296
+ }).to eq(body: { query: :query, post_filter: :post_filter }) }
297
+ end
298
+
299
+ describe '#_filtered_query' do
300
+ def _filtered_query(options = {}, &block)
301
+ subject.instance_exec(&block) if block
302
+ subject.send(:_filtered_query, subject.send(:_request_query), subject.send(:_request_filter), options)
303
+ end
304
+
305
+ specify{ expect(_filtered_query).to eq({}) }
306
+ specify{ expect(_filtered_query{ update_queries(:query) }).to eq(query: :query) }
307
+ specify{ expect(_filtered_query(strategy: 'query_first'){ update_queries(:query) }).to eq(query: :query) }
308
+ specify{ expect(
309
+ _filtered_query{ update_queries([:query1, :query2]) }
310
+ ).to eq(query: { bool: { must: [:query1, :query2] } }) }
311
+
312
+ specify{ expect(_filtered_query{
313
+ update_options(query_mode: :should)
314
+ update_queries([:query1, :query2])
315
+ }).to eq(query: { bool: { should: [:query1, :query2] } }) }
316
+
317
+ specify{ expect(_filtered_query{
318
+ update_options(query_mode: :dis_max)
319
+ update_queries([:query1, :query2])
320
+ }).to eq(query: { dis_max: { queries: [:query1, :query2] } }) }
321
+
322
+ specify{ expect(
323
+ _filtered_query(strategy: 'query_first'){ update_filters([:filter1, :filter2]) }
324
+ ).to eq(
325
+ query: { filtered: { query: { match_all: {} }, filter: { and: [:filter1, :filter2] }, strategy: 'query_first' } }
326
+ )}
327
+
328
+ specify{ expect(
329
+ _filtered_query{ update_filters([:filter1, :filter2]) }
330
+ ).to eq(query: { filtered: { query: { match_all: {} }, filter: { and: [:filter1, :filter2] } } }) }
331
+
332
+ specify{ expect(_filtered_query{
333
+ update_filters([:filter1, :filter2])
334
+ update_queries([:query1, :query2])
335
+ }).to eq(
336
+ query: { filtered: { query: { bool: { must: [:query1, :query2] } }, filter: { and: [:filter1, :filter2] } } }
337
+ ) }
338
+
339
+ specify{ expect(_filtered_query(strategy: 'query_first'){
340
+ update_filters([:filter1, :filter2])
341
+ update_queries([:query1, :query2])
342
+ }).to eq(
343
+ query: {
344
+ filtered: {
345
+ query: { bool: { must: [:query1, :query2] } },
346
+ filter: { and: [:filter1, :filter2] },
347
+ strategy: 'query_first'
348
+ }
349
+ }
350
+ ) }
351
+
352
+ specify{ expect(_filtered_query{
353
+ update_options(query_mode: :should)
354
+ update_options(filter_mode: :or)
355
+ update_filters([:filter1, :filter2])
356
+ update_queries([:query1, :query2])
357
+ }).to eq(
358
+ query: { filtered: { query: { bool: { should: [:query1, :query2] } }, filter: { or: [:filter1, :filter2] } } }
359
+ ) }
360
+ end
361
+
362
+ describe '#_request_filter' do
363
+ def _request_filter(&block)
364
+ subject.instance_exec(&block) if block
365
+ subject.send(:_request_filter)
366
+ end
367
+
368
+ specify{ expect(_request_filter).to be_nil }
369
+
370
+ specify{ expect(_request_filter{ update_types(:type) }).to eq(type: { value: 'type' }) }
371
+ specify{ expect(
372
+ _request_filter{ update_types([:type1, :type2]) }
373
+ ).to eq(or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } }]) }
374
+
375
+ specify{ expect(_request_filter{ update_filters([:filter1, :filter2]) }).to eq(and: [:filter1, :filter2]) }
376
+ specify{ expect(_request_filter{
377
+ update_options(filter_mode: :or)
378
+ update_filters([:filter1, :filter2])
379
+ }).to eq(or: [:filter1, :filter2]) }
380
+
381
+ specify{ expect(_request_filter{
382
+ update_options(filter_mode: :must)
383
+ update_filters([:filter1, :filter2])
384
+ }).to eq(bool: { must: [:filter1, :filter2] }) }
385
+
386
+ specify{ expect(_request_filter{
387
+ update_options(filter_mode: :should)
388
+ update_filters([:filter1, :filter2])
389
+ } ).to eq(bool: { should: [:filter1, :filter2] }) }
390
+
391
+ specify{ expect(_request_filter{
392
+ update_types([:type1, :type2])
393
+ update_filters([:filter1, :filter2])
394
+ }).to eq(and: [{ or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } }] }, :filter1, :filter2]) }
395
+
396
+ specify{ expect(_request_filter{
397
+ update_options(filter_mode: :or)
398
+ update_types([:type1, :type2])
399
+ update_filters([:filter1, :filter2])
400
+ }).to eq(
401
+ and: [{ or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } }] }, { or: [:filter1, :filter2] }]
402
+ ) }
403
+
404
+ specify{ expect(_request_filter{
405
+ update_options(filter_mode: :must)
406
+ update_types([:type1, :type2])
407
+ update_filters([:filter1, :filter2])
408
+ }).to eq(
409
+ and: [
410
+ { or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } }] },
411
+ { bool: { must: [:filter1, :filter2] } }
412
+ ]
413
+ ) }
414
+
415
+ specify{ expect(_request_filter{
416
+ update_options(filter_mode: :should)
417
+ update_types([:type1, :type2])
418
+ update_filters([:filter1, :filter2])
419
+ }).to eq(and: [
420
+ { or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } } ]},
421
+ { bool: { should: [:filter1, :filter2] } }
422
+ ]) }
423
+ end
424
+
425
+ describe '#_request_post_filter' do
426
+ def _request_post_filter(&block)
427
+ subject.instance_exec(&block) if block
428
+ subject.send(:_request_post_filter)
429
+ end
430
+
431
+ specify{ expect(_request_post_filter).to be_nil }
432
+
433
+ specify{ expect(
434
+ _request_post_filter{ update_post_filters([:post_filter1, :post_filter2]) }
435
+ ).to eq(and: [:post_filter1, :post_filter2]) }
436
+
437
+ specify{ expect(_request_post_filter{
438
+ update_options(post_filter_mode: :or)
439
+ update_post_filters([:post_filter1, :post_filter2])
440
+ }).to eq(or: [:post_filter1, :post_filter2]) }
441
+
442
+ specify{ expect(_request_post_filter{
443
+ update_options(post_filter_mode: :must)
444
+ update_post_filters([:post_filter1, :post_filter2])
445
+ }).to eq(bool: { must: [:post_filter1, :post_filter2] }) }
446
+
447
+ specify{ expect(_request_post_filter{
448
+ update_options(post_filter_mode: :should)
449
+ update_post_filters([:post_filter1, :post_filter2])
450
+ }).to eq(bool: { should: [:post_filter1, :post_filter2] }) }
451
+
452
+ context do
453
+ subject{ described_class.new(filter_mode: :or) }
454
+
455
+ specify{ expect(
456
+ _request_post_filter{ update_post_filters([:post_filter1, :post_filter2]) }
457
+ ).to eq(or: [:post_filter1, :post_filter2]) }
458
+ end
459
+ end
460
+
461
+ describe '#_request_types' do
462
+ def _request_types(&block)
463
+ subject.instance_exec(&block) if block
464
+ subject.send(:_request_types)
465
+ end
466
+
467
+ specify{ expect(_request_types).to be_nil }
468
+ specify{ expect(_request_types{ update_types(:type1) }).to eq(type: { value: 'type1' }) }
469
+ specify{ expect(
470
+ _request_types{ update_types([:type1, :type2]) }
471
+ ).to eq(or: [{ type: { value: 'type1' } }, { type: { value: 'type2' } }]) }
472
+ end
473
+
474
+ describe '#_queries_join' do
475
+ def _queries_join(*args)
476
+ subject.send(:_queries_join, *args)
477
+ end
478
+
479
+ let(:query){ { term: { field: 'value' } } }
480
+
481
+ specify{ expect(_queries_join([], :dis_max)).to be_nil }
482
+ specify{ expect(_queries_join([query], :dis_max)).to eq(query) }
483
+ specify{ expect(_queries_join([query, query], :dis_max)).to eq(dis_max: { queries: [query, query] }) }
484
+ specify{ expect(_queries_join([], 0.7)).to be_nil }
485
+ specify{ expect(_queries_join([query], 0.7)).to eq(query) }
486
+ specify{ expect(_queries_join([query, query], 0.7)).to eq(dis_max: { queries: [query, query], tie_breaker: 0.7 }) }
487
+ specify{ expect(_queries_join([], :must)).to be_nil }
488
+ specify{ expect(_queries_join([query], :must)).to eq(query) }
489
+ specify{ expect(_queries_join([query, query], :must)).to eq(bool: { must: [query, query] }) }
490
+ specify{ expect(_queries_join([], :should)).to be_nil }
491
+ specify{ expect(_queries_join([query], :should)).to eq(query) }
492
+ specify{ expect(_queries_join([query, query], :should)).to eq(bool: { should: [query, query] }) }
493
+ specify{ expect(_queries_join([], '25%')).to be_nil }
494
+ specify{ expect(_queries_join([query], '25%')).to eq(query) }
495
+ specify{ expect(_queries_join([query, query], '25%')).to eq(
496
+ bool: { should: [query, query], minimum_should_match: '25%' }
497
+ ) }
498
+ end
499
+
500
+ describe '#_filters_join' do
501
+ def _filters_join *args
502
+ subject.send(:_filters_join, *args)
503
+ end
504
+
505
+ let(:filter) { {term: {field: 'value'}} }
506
+
507
+ specify{ expect(_filters_join([], :and)).to be_nil }
508
+ specify{ expect(_filters_join([filter], :and)).to eq(filter) }
509
+ specify{ expect(_filters_join([filter, filter], :and)).to eq(and: [filter, filter]) }
510
+
511
+ specify{ expect(_filters_join([], :or)).to be_nil }
512
+ specify{ expect(_filters_join([filter], :or)).to eq(filter) }
513
+ specify{ expect(_filters_join([filter, filter], :or)).to eq(or: [filter, filter]) }
514
+
515
+ specify{ expect(_filters_join([], :must)).to be_nil }
516
+ specify{ expect(_filters_join([filter], :must)).to eq(filter) }
517
+ specify{ expect(_filters_join([filter, filter], :must)).to eq(bool: { must: [filter, filter] }) }
518
+
519
+ specify{ expect(_filters_join([], :should)).to be_nil }
520
+ specify{ expect(_filters_join([filter], :should)).to eq(filter) }
521
+ specify{ expect(_filters_join([filter, filter], :should)).to eq(bool: { should: [filter, filter] }) }
522
+
523
+ specify{ expect(_filters_join([], '25%')).to be_nil }
524
+ specify{ expect(_filters_join([filter], '25%')).to eq(filter) }
525
+ specify{ expect(_filters_join([filter, filter], '25%')).to eq(
526
+ bool: { should: [filter, filter], minimum_should_match: '25%' }
527
+ ) }
528
+ end
529
+ end