elasticband 0.1.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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +5 -0
  5. data/.travis.yml +13 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +21 -0
  9. data/README.md +34 -0
  10. data/Rakefile +8 -0
  11. data/elasticband.gemspec +27 -0
  12. data/lib/elasticband/aggregation/nested.rb +18 -0
  13. data/lib/elasticband/aggregation/terms.rb +23 -0
  14. data/lib/elasticband/aggregation/top_hits.rb +26 -0
  15. data/lib/elasticband/aggregation.rb +56 -0
  16. data/lib/elasticband/filter/and.rb +24 -0
  17. data/lib/elasticband/filter/not.rb +24 -0
  18. data/lib/elasticband/filter/query.rb +24 -0
  19. data/lib/elasticband/filter/term.rb +23 -0
  20. data/lib/elasticband/filter/terms.rb +23 -0
  21. data/lib/elasticband/filter.rb +13 -0
  22. data/lib/elasticband/query/filtered.rb +25 -0
  23. data/lib/elasticband/query/function_score.rb +44 -0
  24. data/lib/elasticband/query/match.rb +25 -0
  25. data/lib/elasticband/query/multi_match.rb +23 -0
  26. data/lib/elasticband/query/score_function/boost_factor.rb +17 -0
  27. data/lib/elasticband/query/score_function/field_value_factor.rb +24 -0
  28. data/lib/elasticband/query/score_function/filtered.rb +19 -0
  29. data/lib/elasticband/query/score_function/script_score.rb +24 -0
  30. data/lib/elasticband/query/score_function.rb +14 -0
  31. data/lib/elasticband/query.rb +127 -0
  32. data/lib/elasticband/search.rb +18 -0
  33. data/lib/elasticband/version.rb +3 -0
  34. data/lib/elasticband.rb +12 -0
  35. data/spec/aggregation/nested_spec.rb +28 -0
  36. data/spec/aggregation/terms_spec.rb +17 -0
  37. data/spec/aggregation/top_hits_spec.rb +26 -0
  38. data/spec/aggregation_spec.rb +48 -0
  39. data/spec/filter/and_spec.rb +31 -0
  40. data/spec/filter/not_spec.rb +21 -0
  41. data/spec/filter/query_spec.rb +21 -0
  42. data/spec/filter/term_spec.rb +17 -0
  43. data/spec/filter/terms_spec.rb +23 -0
  44. data/spec/filter_spec.rb +9 -0
  45. data/spec/query/filtered_spec.rb +37 -0
  46. data/spec/query/function_score_spec.rb +76 -0
  47. data/spec/query/match_spec.rb +23 -0
  48. data/spec/query/multi_match_spec.rb +29 -0
  49. data/spec/query/score_function/boost_factor_spec.rb +9 -0
  50. data/spec/query/score_function/field_value_factor_spec.rb +17 -0
  51. data/spec/query/score_function/filtered_spec.rb +25 -0
  52. data/spec/query/score_function/script_score_spec.rb +17 -0
  53. data/spec/query/score_function_spec.rb +10 -0
  54. data/spec/query_spec.rb +274 -0
  55. data/spec/search_spec.rb +33 -0
  56. data/spec/spec_helper.rb +94 -0
  57. metadata +185 -0
@@ -0,0 +1,274 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Elasticband::Query do
4
+ describe '#to_h' do
5
+ subject { described_class.new.to_h }
6
+
7
+ it { is_expected.to eq(match_all: {}) }
8
+ end
9
+
10
+ describe '.parse' do
11
+ context 'with only the query text' do
12
+ subject { described_class.parse('foo') }
13
+
14
+ it { is_expected.to eq(match: { _all: 'foo' }) }
15
+ end
16
+
17
+ context 'with options' do
18
+ subject { described_class.parse('foo', options) }
19
+
20
+ context 'with `:on` option' do
21
+ context 'with a single field' do
22
+ let(:options) { { on: :name } }
23
+
24
+ it { is_expected.to eq(match: { name: 'foo' }) }
25
+ end
26
+
27
+ context 'with multiple fields on `:on` option' do
28
+ let(:options) { { on: %i(name description) } }
29
+
30
+ it { is_expected.to eq(multi_match: { query: 'foo', fields: %i(name description) }) }
31
+ end
32
+
33
+ context 'with a composed name on `:on` option' do
34
+ let(:options) { { on: 'company.name' } }
35
+
36
+ it { is_expected.to eq(match: { 'company.name': 'foo' }) }
37
+ end
38
+ end
39
+
40
+ context 'with `:only/:except` option' do
41
+ context 'with only `:only` option' do
42
+ context 'with a single clause' do
43
+ let(:options) { { only: { status: :published } } }
44
+
45
+ it 'returns a filtered query with a `term` filter' do
46
+ is_expected.to eq(
47
+ filtered: {
48
+ query: { match: { _all: 'foo' } },
49
+ filter: { term: { status: :published } }
50
+ }
51
+ )
52
+ end
53
+ end
54
+
55
+ context 'with multiple clauses' do
56
+ let(:options) { { only: { status: :published, company_id: 1 } } }
57
+
58
+ it 'returns a filtered query with an `and` filter' do
59
+ is_expected.to eq(
60
+ filtered: {
61
+ query: { match: { _all: 'foo' } },
62
+ filter: {
63
+ and: [
64
+ { term: { status: :published } },
65
+ term: { company_id: 1 }
66
+ ]
67
+ }
68
+ }
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'with a nested attribute' do
74
+ let(:options) { { only: { company: { id: 1 } } } }
75
+
76
+ it 'returns a filtered query with a `term` filter on dotted notation' do
77
+ is_expected.to eq(
78
+ filtered: {
79
+ query: { match: { _all: 'foo' } },
80
+ filter: { term: { 'company.id': 1 } }
81
+ }
82
+ )
83
+ end
84
+ end
85
+
86
+ context 'with multiple values' do
87
+ let(:options) { { only: { status: %i(published rejected) } } }
88
+
89
+ it 'returns a filtered query with a `terms` filter' do
90
+ is_expected.to eq(
91
+ filtered: {
92
+ query: { match: { _all: 'foo' } },
93
+ filter: { terms: { status: %i(published rejected) } }
94
+ }
95
+ )
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'with only `:except` option' do
101
+ context 'with a single clause' do
102
+ let(:options) { { except: { status: :published } } }
103
+
104
+ it 'returns a filtered query with a `not` filter wrapping a `term` filter' do
105
+ is_expected.to eq(
106
+ filtered: {
107
+ query: { match: { _all: 'foo' } },
108
+ filter: { not: { term: { status: :published } } }
109
+ }
110
+ )
111
+ end
112
+ end
113
+
114
+ context 'with multiple clauses' do
115
+ let(:options) { { except: { status: :published, company_id: 1 } } }
116
+
117
+ it 'returns a filtered query with a `not` filter wrapping an `and` filter' do
118
+ is_expected.to eq(
119
+ filtered: {
120
+ query: { match: { _all: 'foo' } },
121
+ filter: {
122
+ and: [
123
+ { not: { term: { status: :published } } },
124
+ not: { term: { company_id: 1 } }
125
+ ]
126
+ }
127
+ }
128
+ )
129
+ end
130
+ end
131
+
132
+ context 'with a nested attribute' do
133
+ let(:options) { { except: { company: { id: 1 } } } }
134
+
135
+ it 'returns a filtered query with a `not` filter wrapping a `term` filter on dotted notation' do
136
+ is_expected.to eq(
137
+ filtered: {
138
+ query: { match: { _all: 'foo' } },
139
+ filter: { not: { term: { 'company.id': 1 } } }
140
+ }
141
+ )
142
+ end
143
+ end
144
+
145
+ context 'with multiple values' do
146
+ let(:options) { { except: { status: %i(published rejected) } } }
147
+
148
+ it 'returns a filtered query with `not` filter wrapping a `terms` filter' do
149
+ is_expected.to eq(
150
+ filtered: {
151
+ query: { match: { _all: 'foo' } },
152
+ filter: { not: { terms: { status: %i(published rejected) } } }
153
+ }
154
+ )
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'with both options' do
160
+ let(:options) { { only: { status: :published }, except: { company_id: 1 } } }
161
+
162
+ it 'returns a filtered query combining the filters' do
163
+ is_expected.to eq(
164
+ filtered: {
165
+ query: { match: { _all: 'foo' } },
166
+ filter: {
167
+ and: [
168
+ { term: { status: :published } },
169
+ not: { term: { company_id: 1 } }
170
+ ]
171
+ }
172
+ }
173
+ )
174
+ end
175
+ end
176
+ end
177
+
178
+ context 'with `:boost_by` option' do
179
+ let(:options) { { boost_by: :contents_count } }
180
+
181
+ it 'returns a function score query with a `field_value_factor` function' do
182
+ is_expected.to eq(
183
+ function_score: {
184
+ query: { match: { _all: 'foo' } },
185
+ field_value_factor: {
186
+ field: :contents_count,
187
+ modifier: :ln2p
188
+ }
189
+ }
190
+ )
191
+ end
192
+ end
193
+
194
+ context 'with `:boost_where` option' do
195
+ context 'with a regular attribute' do
196
+ let(:options) { { boost_where: { status: :published } } }
197
+
198
+ it 'returns a function score query with a `boost_factor` filtered function' do
199
+ is_expected.to eq(
200
+ function_score: {
201
+ query: { match: { _all: 'foo' } },
202
+ functions: [
203
+ {
204
+ filter: { term: { status: :published } },
205
+ boost_factor: 1000
206
+ }
207
+ ]
208
+ }
209
+ )
210
+ end
211
+ end
212
+
213
+ context 'with a multiple attributes' do
214
+ let(:options) { { boost_where: { status: :published, company_id: 1 } } }
215
+
216
+ it 'returns a function score query with a `boost_factor` filtered function' do
217
+ is_expected.to eq(
218
+ function_score: {
219
+ query: { match: { _all: 'foo' } },
220
+ functions: [
221
+ {
222
+ filter: {
223
+ and: [
224
+ { term: { status: :published } },
225
+ term: { company_id: 1 }
226
+ ]
227
+ },
228
+ boost_factor: 1000
229
+ }
230
+ ]
231
+ }
232
+ )
233
+ end
234
+ end
235
+
236
+ context 'with a nested attribute' do
237
+ let(:options) { { boost_where: { company: { id: 1 } } } }
238
+
239
+ it 'returns a function score query with a `boost_factor` filtered function' do
240
+ is_expected.to eq(
241
+ function_score: {
242
+ query: { match: { _all: 'foo' } },
243
+ functions: [
244
+ {
245
+ filter: { term: { 'company.id': 1 } },
246
+ boost_factor: 1000
247
+ }
248
+ ]
249
+ }
250
+ )
251
+ end
252
+ end
253
+
254
+ context 'with multiple values' do
255
+ let(:options) { { boost_where: { status: %i(published rejected) } } }
256
+
257
+ it 'returns a function score query with a `boost_factor` filtered function' do
258
+ is_expected.to eq(
259
+ function_score: {
260
+ query: { match: { _all: 'foo' } },
261
+ functions: [
262
+ {
263
+ filter: { terms: { status: %i(published rejected) } },
264
+ boost_factor: 1000
265
+ }
266
+ ]
267
+ }
268
+ )
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Elasticband::Search do
4
+ describe '.parse' do
5
+ subject { described_class.parse('foo', on: :name, group_by: :status) }
6
+
7
+ before do
8
+ allow(Elasticband::Query).to receive(:parse).with('foo', on: :name, group_by: :status) { query }
9
+ allow(Elasticband::Aggregation).to receive(:parse).with(on: :name, group_by: :status) { aggregation }
10
+ end
11
+
12
+ context 'with only query' do
13
+ let(:query) { 'query' }
14
+ let(:aggregation) { {} }
15
+
16
+ it { is_expected.to eq(query: 'query') }
17
+ end
18
+
19
+ context 'with only aggregation' do
20
+ let(:query) { {} }
21
+ let(:aggregation) { 'aggregation' }
22
+
23
+ it { is_expected.to eq(aggs: 'aggregation') }
24
+ end
25
+
26
+ context 'with query and aggregation' do
27
+ let(:query) { 'query' }
28
+ let(:aggregation) { 'aggregation' }
29
+
30
+ it { is_expected.to eq(query: 'query', aggs: 'aggregation') }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,94 @@
1
+ require 'dotenv'
2
+ Dotenv.load
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+
6
+ if ENV['CODECLIMATE_REPO_TOKEN']
7
+ require 'codeclimate-test-reporter'
8
+
9
+ CodeClimate::TestReporter.start
10
+ end
11
+
12
+ require 'rspec'
13
+ require 'elasticband'
14
+ Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }
15
+
16
+ RSpec.configure do |config|
17
+ # The settings below are suggested to provide a good initial experience
18
+ # with RSpec, but feel free to customize to your heart's content.
19
+
20
+ # Exclude tests marked as broken
21
+ config.filter_run_excluding :broken
22
+
23
+ # These two settings work together to allow you to limit a spec run
24
+ # to individual examples or groups you care about by tagging them with
25
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
26
+ # get run.
27
+ config.filter_run :focus
28
+ config.run_all_when_everything_filtered = true
29
+
30
+ # Many RSpec users commonly either run the entire suite or an individual
31
+ # file, and it's useful to allow more verbose output when running an
32
+ # individual spec file.
33
+ if config.files_to_run.one?
34
+ # Use the documentation formatter for detailed output,
35
+ # unless a formatter has already been configured
36
+ # (e.g. via a command-line flag).
37
+ config.default_formatter = 'doc'
38
+ end
39
+
40
+ # Print the 10 slowest examples and example groups at the
41
+ # end of the spec run, to help surface which specs are running
42
+ # particularly slow.
43
+ config.profile_examples = 5
44
+
45
+ # Run specs in random order to surface order dependencies. If you find an
46
+ # order dependency and want to debug it, you can fix the order by providing
47
+ # the seed, which is printed after each run.
48
+ # --seed 1234
49
+ config.order = :random
50
+
51
+ # Seed global randomization in this process using the `--seed` CLI option.
52
+ # Setting this allows you to use `--seed` to deterministically reproduce
53
+ # test failures related to randomization by passing the same `--seed` value
54
+ # as the one that triggered the failure.
55
+ Kernel.srand config.seed
56
+
57
+ # rspec-expectations config goes here. You can use an alternate
58
+ # assertion/expectation library such as wrong or the stdlib/minitest
59
+ # assertions if you prefer.
60
+ config.expect_with :rspec do |expectations|
61
+ # Enable only the newer, non-monkey-patching expect syntax.
62
+ # For more details, see:
63
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
64
+ expectations.syntax = :expect
65
+ end
66
+
67
+ # Disable RSpec monkey patches
68
+ #
69
+ # - It force to use `RSpec.describe` at the top level spec
70
+ config.disable_monkey_patching!
71
+
72
+ # rspec-mocks config goes here. You can use an alternate test double
73
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
74
+ config.mock_with :rspec do |mocks|
75
+ # Enable only the newer, non-monkey-patching expect syntax.
76
+ # For more details, see:
77
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
+ mocks.syntax = :expect
79
+
80
+ # Prevents you from mocking or stubbing a method that does not exist on
81
+ # a real object. This is generally recommended.
82
+ mocks.verify_partial_doubles = true
83
+ end
84
+
85
+ config.example_status_persistence_file_path = '.rspec_persistence'
86
+
87
+ config.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
88
+
89
+ # Turn on aggregate_failures by default, if you don't want it specify `aggregate_failures: false`
90
+ # into your example
91
+ config.define_derived_metadata do |meta|
92
+ meta[:aggregate_failures] = true unless meta.key?(:aggregate_failures)
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elasticband
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Glauber Campinho
8
+ - Rubens Minoru Andako Bueno
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-06-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: dotenv
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 3.3.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 3.3.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: rubocop
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: codeclimate-test-reporter
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description:
99
+ email:
100
+ - ggcampinho@gmail.com
101
+ - rubensmabueno@hotmail.com
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".rubocop.yml"
109
+ - ".travis.yml"
110
+ - CODE_OF_CONDUCT.md
111
+ - Gemfile
112
+ - LICENSE
113
+ - README.md
114
+ - Rakefile
115
+ - elasticband.gemspec
116
+ - lib/elasticband.rb
117
+ - lib/elasticband/aggregation.rb
118
+ - lib/elasticband/aggregation/nested.rb
119
+ - lib/elasticband/aggregation/terms.rb
120
+ - lib/elasticband/aggregation/top_hits.rb
121
+ - lib/elasticband/filter.rb
122
+ - lib/elasticband/filter/and.rb
123
+ - lib/elasticband/filter/not.rb
124
+ - lib/elasticband/filter/query.rb
125
+ - lib/elasticband/filter/term.rb
126
+ - lib/elasticband/filter/terms.rb
127
+ - lib/elasticband/query.rb
128
+ - lib/elasticband/query/filtered.rb
129
+ - lib/elasticband/query/function_score.rb
130
+ - lib/elasticband/query/match.rb
131
+ - lib/elasticband/query/multi_match.rb
132
+ - lib/elasticband/query/score_function.rb
133
+ - lib/elasticband/query/score_function/boost_factor.rb
134
+ - lib/elasticband/query/score_function/field_value_factor.rb
135
+ - lib/elasticband/query/score_function/filtered.rb
136
+ - lib/elasticband/query/score_function/script_score.rb
137
+ - lib/elasticband/search.rb
138
+ - lib/elasticband/version.rb
139
+ - spec/aggregation/nested_spec.rb
140
+ - spec/aggregation/terms_spec.rb
141
+ - spec/aggregation/top_hits_spec.rb
142
+ - spec/aggregation_spec.rb
143
+ - spec/filter/and_spec.rb
144
+ - spec/filter/not_spec.rb
145
+ - spec/filter/query_spec.rb
146
+ - spec/filter/term_spec.rb
147
+ - spec/filter/terms_spec.rb
148
+ - spec/filter_spec.rb
149
+ - spec/query/filtered_spec.rb
150
+ - spec/query/function_score_spec.rb
151
+ - spec/query/match_spec.rb
152
+ - spec/query/multi_match_spec.rb
153
+ - spec/query/score_function/boost_factor_spec.rb
154
+ - spec/query/score_function/field_value_factor_spec.rb
155
+ - spec/query/score_function/filtered_spec.rb
156
+ - spec/query/score_function/script_score_spec.rb
157
+ - spec/query/score_function_spec.rb
158
+ - spec/query_spec.rb
159
+ - spec/search_spec.rb
160
+ - spec/spec_helper.rb
161
+ homepage: https://github.com/LoveMondays/elasticband
162
+ licenses:
163
+ - MIT
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 2.4.7
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: Query builder for elasticsearch-rails
185
+ test_files: []