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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +13 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +34 -0
- data/Rakefile +8 -0
- data/elasticband.gemspec +27 -0
- data/lib/elasticband/aggregation/nested.rb +18 -0
- data/lib/elasticband/aggregation/terms.rb +23 -0
- data/lib/elasticband/aggregation/top_hits.rb +26 -0
- data/lib/elasticband/aggregation.rb +56 -0
- data/lib/elasticband/filter/and.rb +24 -0
- data/lib/elasticband/filter/not.rb +24 -0
- data/lib/elasticband/filter/query.rb +24 -0
- data/lib/elasticband/filter/term.rb +23 -0
- data/lib/elasticband/filter/terms.rb +23 -0
- data/lib/elasticband/filter.rb +13 -0
- data/lib/elasticband/query/filtered.rb +25 -0
- data/lib/elasticband/query/function_score.rb +44 -0
- data/lib/elasticband/query/match.rb +25 -0
- data/lib/elasticband/query/multi_match.rb +23 -0
- data/lib/elasticband/query/score_function/boost_factor.rb +17 -0
- data/lib/elasticband/query/score_function/field_value_factor.rb +24 -0
- data/lib/elasticband/query/score_function/filtered.rb +19 -0
- data/lib/elasticband/query/score_function/script_score.rb +24 -0
- data/lib/elasticband/query/score_function.rb +14 -0
- data/lib/elasticband/query.rb +127 -0
- data/lib/elasticband/search.rb +18 -0
- data/lib/elasticband/version.rb +3 -0
- data/lib/elasticband.rb +12 -0
- data/spec/aggregation/nested_spec.rb +28 -0
- data/spec/aggregation/terms_spec.rb +17 -0
- data/spec/aggregation/top_hits_spec.rb +26 -0
- data/spec/aggregation_spec.rb +48 -0
- data/spec/filter/and_spec.rb +31 -0
- data/spec/filter/not_spec.rb +21 -0
- data/spec/filter/query_spec.rb +21 -0
- data/spec/filter/term_spec.rb +17 -0
- data/spec/filter/terms_spec.rb +23 -0
- data/spec/filter_spec.rb +9 -0
- data/spec/query/filtered_spec.rb +37 -0
- data/spec/query/function_score_spec.rb +76 -0
- data/spec/query/match_spec.rb +23 -0
- data/spec/query/multi_match_spec.rb +29 -0
- data/spec/query/score_function/boost_factor_spec.rb +9 -0
- data/spec/query/score_function/field_value_factor_spec.rb +17 -0
- data/spec/query/score_function/filtered_spec.rb +25 -0
- data/spec/query/score_function/script_score_spec.rb +17 -0
- data/spec/query/score_function_spec.rb +10 -0
- data/spec/query_spec.rb +274 -0
- data/spec/search_spec.rb +33 -0
- data/spec/spec_helper.rb +94 -0
- metadata +185 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'elasticband/query/filtered'
|
2
|
+
require 'elasticband/query/function_score'
|
3
|
+
require 'elasticband/query/match'
|
4
|
+
require 'elasticband/query/multi_match'
|
5
|
+
require 'elasticband/query/score_function'
|
6
|
+
|
7
|
+
module Elasticband
|
8
|
+
class Query
|
9
|
+
def to_h
|
10
|
+
{ match_all: {} }
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# Parses a query text with options to a Elasticsearch syntax
|
15
|
+
#
|
16
|
+
# #### Options
|
17
|
+
#
|
18
|
+
# * `on:` Defines which attributes will searched in documents
|
19
|
+
# * `only:` Filter the search results where the condition is `true`
|
20
|
+
# * `except`: Filter the search results where the condition is `false`.
|
21
|
+
# * `boost_by:` Boosts the score of a query result based on a attribute of the document.
|
22
|
+
# This score will be multiplied for the `boost_by` attribute over function `ln2p`.
|
23
|
+
# * `boost_where:` Boosts the score of a query result where some condition is `true`.
|
24
|
+
# This score will be multiplied by 1000 (arbitrary, based on gem `searchkick`)
|
25
|
+
#
|
26
|
+
# #### Examples
|
27
|
+
# ```
|
28
|
+
# Query.parse('foo')
|
29
|
+
# => { match: { _all: 'foo' } }
|
30
|
+
#
|
31
|
+
# Query.parse('foo', on: :name)
|
32
|
+
# => { match: { name: 'foo' } }
|
33
|
+
#
|
34
|
+
# Query.parse('foo', on: %i(name description))
|
35
|
+
# => { multi_match: { query: 'foo', fields: [:name, :description] } }
|
36
|
+
#
|
37
|
+
# Query.parse('foo', only: { status: :published })
|
38
|
+
# => { filtered: { query: ..., filter: { term: { status: :published } } } }
|
39
|
+
#
|
40
|
+
# Query.parse('foo', except: { company: { id: 1 } })
|
41
|
+
# => { filtered: { query: ..., filter: { not: { term: { status: :published } } } } }
|
42
|
+
#
|
43
|
+
# Query.parse('foo', boost_by: :contents_count)
|
44
|
+
# => { function_score: { query: ..., field_value_factor: { field: :contents_count, modifier: :ln2p } } }
|
45
|
+
#
|
46
|
+
# Query.parse('foo', boost_where: { company: { id: 1 } })
|
47
|
+
# => {
|
48
|
+
# function_score: {
|
49
|
+
# query: ...,
|
50
|
+
# functions: [
|
51
|
+
# { filter: { term: { 'company.id': 1 } }, boost_factor: 1000 }
|
52
|
+
# ]
|
53
|
+
# }
|
54
|
+
# }
|
55
|
+
# ```
|
56
|
+
def parse(query_text, options = {})
|
57
|
+
query = parse_on(query_text, options[:on])
|
58
|
+
query = parse_only_and_except(query, options[:only], options[:except])
|
59
|
+
query = parse_boost(query, options[:boost_by], options[:boost_where])
|
60
|
+
query.to_h
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def to_dotted_notation(hash_params, prefix = nil, dotted_hash = {})
|
66
|
+
hash_params.each_with_object(dotted_hash) do |(key, val), hash|
|
67
|
+
if val.is_a?(Hash)
|
68
|
+
to_dotted_notation(val, "#{prefix}#{key}.", hash)
|
69
|
+
else
|
70
|
+
hash["#{prefix}#{key}"] = val
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_on(query_text, on_options)
|
76
|
+
if on_options.is_a?(Enumerable)
|
77
|
+
Query::MultiMatch.new(query_text, on_options)
|
78
|
+
else
|
79
|
+
Query::Match.new(query_text, on_options)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def parse_only_and_except(query, only_options, except_options)
|
84
|
+
return query if only_options.blank? && except_options.blank?
|
85
|
+
|
86
|
+
filter = parse_filters(only_options) + parse_filters(except_options).map { |f| Filter::Not.new(f) }
|
87
|
+
filter = join_filters(filter)
|
88
|
+
|
89
|
+
Query::Filtered.new(filter, query)
|
90
|
+
end
|
91
|
+
|
92
|
+
def join_filters(filters)
|
93
|
+
filters.count > 1 ? Filter::And.new(filters) : filters.first
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_filters(options)
|
97
|
+
return [] if options.blank?
|
98
|
+
|
99
|
+
to_dotted_notation(options).map { |attribute, value| parse_filter(attribute, value) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_filter(attribute, value)
|
103
|
+
if value.is_a?(Enumerable)
|
104
|
+
Filter::Terms.new(value, attribute)
|
105
|
+
else
|
106
|
+
Filter::Term.new(value, attribute)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def parse_boost(query, boost_by_options, boost_where_options)
|
111
|
+
return query if boost_by_options.blank? && boost_where_options.blank?
|
112
|
+
|
113
|
+
function = parse_boost_function(boost_by_options, boost_where_options)
|
114
|
+
Query::FunctionScore.new(query, function)
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_boost_function(boost_by_options, boost_where_options)
|
118
|
+
if boost_by_options.present?
|
119
|
+
ScoreFunction::FieldValueFactor.new(boost_by_options, modifier: :ln2p)
|
120
|
+
else
|
121
|
+
filter = join_filters(parse_filters(boost_where_options))
|
122
|
+
ScoreFunction::Filtered.new(filter, ScoreFunction::BoostFactor.new(1_000))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Elasticband
|
2
|
+
class Search
|
3
|
+
class << self
|
4
|
+
# Parses a query text with options to a Elasticsearch search syntax.
|
5
|
+
# See Elasticband::Query.parse and Elasticband::Aggregation.parse options for details.
|
6
|
+
#
|
7
|
+
# #### Examples
|
8
|
+
# ```
|
9
|
+
# Search.parse('foo', on: :name, group_by: :status)
|
10
|
+
# => { query: { match: { name: 'foo' } }, aggs: { status: { terms: { field: :status } } } }
|
11
|
+
# ```
|
12
|
+
def parse(query_text, options)
|
13
|
+
hash = { query: Query.parse(query_text, options), aggs: Aggregation.parse(options) }
|
14
|
+
hash.reject { |_, value| value.blank? }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/elasticband.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext/object'
|
3
|
+
require 'active_support/core_ext/array'
|
4
|
+
|
5
|
+
require 'elasticband/aggregation'
|
6
|
+
require 'elasticband/filter'
|
7
|
+
require 'elasticband/query'
|
8
|
+
require 'elasticband/search'
|
9
|
+
require 'elasticband/version'
|
10
|
+
|
11
|
+
module Elasticband
|
12
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Aggregation::Nested do
|
4
|
+
describe '#to_h' do
|
5
|
+
subject { described_class.new(root_aggregation, nested_aggregation).to_h }
|
6
|
+
|
7
|
+
let(:root_aggregation) { Elasticband::Aggregation.new(:root_aggregation) }
|
8
|
+
let(:nested_aggregation) { Elasticband::Aggregation.new(:nested_aggregation) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(root_aggregation).to receive(:to_h) { { root_aggregation: { key_1: :value_1 } } }
|
12
|
+
allow(nested_aggregation).to receive(:to_h) { { nested_aggregation: { key_2: :value_2 } } }
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns a nested aggreagation hash' do
|
16
|
+
is_expected.to eq(
|
17
|
+
root_aggregation: {
|
18
|
+
key_1: :value_1,
|
19
|
+
aggs: {
|
20
|
+
nested_aggregation: {
|
21
|
+
key_2: :value_2
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Aggregation::Terms do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without options' do
|
6
|
+
subject { described_class.new(:aggregation_name, :field_name).to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(aggregation_name: { terms: { field: :field_name } }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with options' do
|
12
|
+
subject { described_class.new(:aggregation_name, :field_name, size: 1).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(aggregation_name: { terms: { field: :field_name, size: 1 } }) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Aggregation::TopHits do
|
4
|
+
describe '#to_h' do
|
5
|
+
subject { described_class.new(:top_hits_aggregation, root_aggregation, 3).to_h }
|
6
|
+
|
7
|
+
let(:root_aggregation) { Elasticband::Aggregation.new(:root_aggregation) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(root_aggregation).to receive(:to_h) { { root_aggregation: { terms: { field: :field_name } } } }
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns a nested aggreagation hash' do
|
14
|
+
is_expected.to eq(
|
15
|
+
root_aggregation: {
|
16
|
+
terms: { field: :field_name },
|
17
|
+
aggs: {
|
18
|
+
top_hits_aggregation: {
|
19
|
+
top_hits: { size: 3 }
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Aggregation do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without a aggregation_hash' do
|
6
|
+
subject { described_class.new(:aggregation_name).to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(aggregation_name: {}) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a aggregation_hash' do
|
12
|
+
subject { described_class.new(:aggregation_name).to_h(key: :value) }
|
13
|
+
|
14
|
+
it { is_expected.to eq(aggregation_name: { key: :value }) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.parse' do
|
19
|
+
subject { described_class.parse(options) }
|
20
|
+
|
21
|
+
context 'with `:group_by` option' do
|
22
|
+
context 'with the field_name' do
|
23
|
+
let(:options) { { group_by: :status } }
|
24
|
+
|
25
|
+
it { is_expected.to eq(status: { terms: { field: :status } }) }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with an array with field_name and :top_hits option' do
|
29
|
+
let(:options) { { group_by: [:status, top_hits: 3] } }
|
30
|
+
|
31
|
+
it 'returns the `terms` aggregation with a `top_hits` nested' do
|
32
|
+
is_expected.to eq(
|
33
|
+
status: {
|
34
|
+
terms: { field: :status },
|
35
|
+
aggs: { top_status: { top_hits: { size: 3 } } }
|
36
|
+
}
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with an array with field_name and other options' do
|
42
|
+
let(:options) { { group_by: [:status, size: 3] } }
|
43
|
+
|
44
|
+
it { is_expected.to eq(status: { terms: { field: :status, size: 3 } }) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Filter::And do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:filter_1) { Elasticband::Filter.new }
|
6
|
+
let(:filter_2) { Elasticband::Filter.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(filter_1).to receive(:to_h) { 'filter_1' }
|
10
|
+
allow(filter_2).to receive(:to_h) { 'filter_2' }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with only one filter' do
|
14
|
+
subject { described_class.new(filter_1).to_h }
|
15
|
+
|
16
|
+
it { is_expected.to eq(and: ['filter_1']) }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with multiple filters' do
|
20
|
+
subject { described_class.new([filter_1, filter_2]).to_h }
|
21
|
+
|
22
|
+
it { is_expected.to eq(and: %w(filter_1 filter_2)) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with options' do
|
26
|
+
subject { described_class.new(filter_1, _cache: true).to_h }
|
27
|
+
|
28
|
+
it { is_expected.to eq(and: { filter: ['filter_1'], _cache: true }) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Filter::Not do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:other_filter) { Elasticband::Filter.new }
|
6
|
+
|
7
|
+
before { allow(other_filter).to receive(:to_h) { 'other_filter' } }
|
8
|
+
|
9
|
+
context 'without options' do
|
10
|
+
subject { described_class.new(other_filter).to_h }
|
11
|
+
|
12
|
+
it { is_expected.to eq(not: 'other_filter') }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with options' do
|
16
|
+
subject { described_class.new(other_filter, _cache: true).to_h }
|
17
|
+
|
18
|
+
it { is_expected.to eq(not: { filter: 'other_filter', _cache: true }) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Filter::Query do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:query) { Elasticband::Query.new }
|
6
|
+
|
7
|
+
before { allow(query).to receive(:to_h) { 'query' } }
|
8
|
+
|
9
|
+
context 'without options' do
|
10
|
+
subject { described_class.new(query).to_h }
|
11
|
+
|
12
|
+
it { is_expected.to eq(query: 'query') }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with options' do
|
16
|
+
subject { described_class.new(query, _cache: true).to_h }
|
17
|
+
|
18
|
+
it { is_expected.to eq(fquery: { query: 'query', _cache: true }) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Filter::Term do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without options' do
|
6
|
+
subject { described_class.new('filter', :field_name).to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(term: { field_name: 'filter' }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with options' do
|
12
|
+
subject { described_class.new('filter', :field_name, _cache: true).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(term: { field_name: 'filter', _cache: true }) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Filter::Terms do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'with only one value' do
|
6
|
+
subject { described_class.new('filter', :field_name).to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(terms: { field_name: ['filter'] }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with multiple values' do
|
12
|
+
subject { described_class.new(%w(filter_1 filter_2), :field_name).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(terms: { field_name: %w(filter_1 filter_2) }) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with options' do
|
18
|
+
subject { described_class.new('filter', :field_name, _cache: true).to_h }
|
19
|
+
|
20
|
+
it { is_expected.to eq(terms: { field_name: ['filter'], _cache: true }) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/filter_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::Filtered do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:other_query) { Elasticband::Query.new }
|
6
|
+
let(:filter) { Elasticband::Filter.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(other_query).to receive(:to_h) { 'query' }
|
10
|
+
allow(filter).to receive(:to_h) { 'filter' }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with only filter' do
|
14
|
+
subject { described_class.new(filter).to_h }
|
15
|
+
|
16
|
+
it { is_expected.to eq(filtered: { filter: 'filter' }) }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with filter and query' do
|
20
|
+
subject { described_class.new(filter, other_query).to_h }
|
21
|
+
|
22
|
+
it { is_expected.to eq(filtered: { query: 'query', filter: 'filter' }) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with filter and options' do
|
26
|
+
subject { described_class.new(filter, nil, strategy: :leap_frog).to_h }
|
27
|
+
|
28
|
+
it { is_expected.to eq(filtered: { filter: 'filter', strategy: :leap_frog }) }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with filter, query and options' do
|
32
|
+
subject { described_class.new(filter, other_query, strategy: :leap_frog).to_h }
|
33
|
+
|
34
|
+
it { is_expected.to eq(filtered: { query: 'query', filter: 'filter', strategy: :leap_frog }) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::FunctionScore do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:other_query) { Elasticband::Query.new }
|
6
|
+
let(:filter) { Elasticband::Filter.new }
|
7
|
+
let(:score_function_1) { Elasticband::Query::ScoreFunction.new }
|
8
|
+
let(:score_function_2) { Elasticband::Query::ScoreFunction.new }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(other_query).to receive(:to_h) { 'query' }
|
12
|
+
allow(filter).to receive(:to_h) { 'filter' }
|
13
|
+
allow(score_function_1).to receive(:to_h) { { score_function_1: 'score_function_1' } }
|
14
|
+
allow(score_function_2).to receive(:to_h) { { score_function_2: 'score_function_2' } }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with a single function' do
|
18
|
+
context 'with a query' do
|
19
|
+
subject { described_class.new(other_query, score_function_1).to_h }
|
20
|
+
|
21
|
+
it { is_expected.to eq(function_score: { query: 'query', score_function_1: 'score_function_1' }) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with filter' do
|
25
|
+
subject { described_class.new(filter, score_function_1).to_h }
|
26
|
+
|
27
|
+
it { is_expected.to eq(function_score: { filter: 'filter', score_function_1: 'score_function_1' }) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with multiple functions' do
|
32
|
+
subject { described_class.new(other_query, [score_function_1, score_function_2]).to_h }
|
33
|
+
|
34
|
+
it 'returns a hash with the query/filter and an array with the functions' do
|
35
|
+
is_expected.to eq(
|
36
|
+
function_score: {
|
37
|
+
query: 'query',
|
38
|
+
functions: [
|
39
|
+
{ score_function_1: 'score_function_1' },
|
40
|
+
{ score_function_2: 'score_function_2' }
|
41
|
+
]
|
42
|
+
}
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with options' do
|
48
|
+
subject { described_class.new(other_query, score_function_1, boost: 1.2).to_h }
|
49
|
+
|
50
|
+
it 'returns a hash with the query, function and options' do
|
51
|
+
is_expected.to eq(
|
52
|
+
function_score: {
|
53
|
+
query: 'query',
|
54
|
+
score_function_1: 'score_function_1',
|
55
|
+
boost: 1.2
|
56
|
+
}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with a filtered function' do
|
62
|
+
let(:filtered_function) { Elasticband::Query::ScoreFunction::Filtered.new(filter, score_function_1) }
|
63
|
+
|
64
|
+
subject { described_class.new(other_query, filtered_function).to_h }
|
65
|
+
|
66
|
+
it 'returns a hash with the query/filter and an array with the function' do
|
67
|
+
is_expected.to eq(
|
68
|
+
function_score: {
|
69
|
+
query: 'query',
|
70
|
+
functions: [{ filter: 'filter', score_function_1: 'score_function_1' }]
|
71
|
+
}
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::Match do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without field' do
|
6
|
+
subject { described_class.new('q').to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(match: { _all: 'q' }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a field and no options' do
|
12
|
+
subject { described_class.new('q', :field_name).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(match: { field_name: 'q' }) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with options' do
|
18
|
+
subject { described_class.new('q', :field_name, operator: :and).to_h }
|
19
|
+
|
20
|
+
it { is_expected.to eq(match: { field_name: { query: 'q', operator: :and } }) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::MultiMatch do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without field' do
|
6
|
+
subject { described_class.new('q').to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(multi_match: { query: 'q', fields: [:_all] }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a single field' do
|
12
|
+
subject { described_class.new('q', :field_name).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(multi_match: { query: 'q', fields: [:field_name] }) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with multiple fields' do
|
18
|
+
subject { described_class.new('q', [:field_name_1, :field_name_2]).to_h }
|
19
|
+
|
20
|
+
it { is_expected.to eq(multi_match: { query: 'q', fields: [:field_name_1, :field_name_2] }) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with options' do
|
24
|
+
subject { described_class.new('q', :field_name, operator: :and).to_h }
|
25
|
+
|
26
|
+
it { is_expected.to eq(multi_match: { query: 'q', operator: :and, fields: [:field_name] }) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::ScoreFunction::FieldValueFactor do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without options' do
|
6
|
+
subject { described_class.new(:field_name).to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(field_value_factor: { field: :field_name }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with options' do
|
12
|
+
subject { described_class.new(:field_name, factor: 1.2).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(field_value_factor: { field: :field_name, factor: 1.2 }) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::ScoreFunction::Filtered do
|
4
|
+
describe '#to_h' do
|
5
|
+
let(:other_score_function) { Elasticband::Query::ScoreFunction.new }
|
6
|
+
let(:filter) { Elasticband::Filter.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(other_score_function).to receive(:to_h) { { function_name: 'score_function' } }
|
10
|
+
allow(filter).to receive(:to_h) { 'filter' }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'without options' do
|
14
|
+
subject { described_class.new(filter, other_score_function).to_h }
|
15
|
+
|
16
|
+
it { is_expected.to eq(filter: 'filter', function_name: 'score_function') }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with options' do
|
20
|
+
subject { described_class.new(filter, other_score_function, weight: 2).to_h }
|
21
|
+
|
22
|
+
it { is_expected.to eq(filter: 'filter', function_name: 'score_function', weight: 2) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Query::ScoreFunction::ScriptScore do
|
4
|
+
describe '#to_h' do
|
5
|
+
context 'without options' do
|
6
|
+
subject { described_class.new('script').to_h }
|
7
|
+
|
8
|
+
it { is_expected.to eq(script_score: { script: 'script' }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with options' do
|
12
|
+
subject { described_class.new('script', params: { param_1: :value_1 }).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(script_score: { script: 'script', params: { param_1: :value_1 } }) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|