Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Please mark backwards incompatible changes with an exclamation mark at the start
## [Unreleased]

### Added
- The `_source` parameter for Elasticsearch's `TopHits` aggregation.
- The `sort` parameter for Elasticsearch's `TopHits` aggregation.
- The `missing` parameter for Elasticsearch's `Terms` aggregation.

Expand Down
16 changes: 12 additions & 4 deletions lib/jay_api/elasticsearch/query_builder/aggregations/top_hits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,31 @@
# Information on this type of aggregation can be found here:
# https://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-top-hits-aggregation
class TopHits < ::JayAPI::Elasticsearch::QueryBuilder::Aggregations::Aggregation
attr_reader :size, :sort
attr_reader :size, :sort, :_source

# @param [String] name The name used by Elasticsearch to identify each
# of the aggregations.
# @param [String] size The number of hits that will be returned.
# @param [Hash] sort How to sort the documents to determine the top
# hits. When not specified the documents are sorted by the score of
# the main query.
def initialize(name, size:, sort: nil)
# @param [FalseClass, String, Array<String>, Hash] _source Expression
# used for source filtering.
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#source-filtering
# Elasticsearch's documentation for more information on what kind of
# expressions are allowed.
# rubocop:disable-next Lint/UnderscorePrefixedVariableName -- to match Elasticsearch's name
def initialize(name, size:, sort: nil, _source: nil)

Check failure on line 32 in lib/jay_api/elasticsearch/query_builder/aggregations/top_hits.rb

View workflow job for this annotation

GitHub Actions / lint

[reek] reported by reviewdog 🐶 UncommunicativeParameterName: JayAPI::Elasticsearch::QueryBuilder::Aggregations::TopHits#initialize has the parameter name '_source' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Parameter-Name.md] Raw Output: lib/jay_api/elasticsearch/query_builder/aggregations/top_hits.rb:32: UncommunicativeParameterName: JayAPI::Elasticsearch::QueryBuilder::Aggregations::TopHits#initialize has the parameter name '_source' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Parameter-Name.md]
super(name)

@size = size
@sort = sort
@_source = _source
end

# @return [self] A copy of the receiver.
def clone
optional_params = { sort: sort.deep_dup }.compact
optional_params = { sort: sort.deep_dup, _source: _source.deep_dup }.compact
copy = self.class.new(name, size: size, **optional_params)
copy.aggregations = aggregations.clone
copy
Expand All @@ -45,7 +52,8 @@
{
top_hits: {
size: size,
sort: sort.deep_dup
sort: sort.deep_dup,
_source: _source.deep_dup
}.compact
}
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,50 @@
end
end

shared_examples_for "#clone when a '_source' has been given" do
it "has its '_source' set to the same value" do
expect(method_call._source).to eq(_source)
end
end

shared_examples_for "#clone when a non-scalar '_source' has been given" do
it_behaves_like "#clone when a '_source' has been given"

it 'is not the same object' do
expect(method_call._source).not_to be(top_hits._source)
end
end

context "when a '_source' has been given" do
let(:constructor_params) { super().merge(_source:) }

context "when '_source' is a boolean" do
let(:_source) { false }

it_behaves_like "#clone when a '_source' has been given"
end

context "when '_source' is a string" do
let(:_source) { 'meta_data.*' }

it_behaves_like "#clone when a non-scalar '_source' has been given"
end

context "when '_source' is an array" do
let(:_source) { %w[meta_data.* timestamp] }

it_behaves_like "#clone when a non-scalar '_source' has been given"
end

context "when '_source' is a hash" do
let(:_source) do
{ includes: %i[date price] }
end

it_behaves_like "#clone when a non-scalar '_source' has been given"
end
end

context 'when the original object has nested aggregations' do
let(:cloned_aggregations) { instance_double(JayAPI::Elasticsearch::QueryBuilder::Aggregations) }

Expand Down Expand Up @@ -110,5 +154,53 @@
expect(sort_hash).to eq(sort)
end
end

context "when a '_source' has been given" do
let(:constructor_params) { super().merge(_source:) }

context "when '_source' is a scalar" do
let(:_source) { false }

let(:expected_hash) do
{
'an_aggregation_sample' => {
top_hits: {
size: 1,
_source: false
}
}
}
end

it 'returns the expected Hash' do
expect(method_call).to eq(expected_hash)
end
end

context "when '_source' is not a scalar" do
let(:_source) { %w[meta_data.* timestamp] }

let(:expected_hash) do
{
'an_aggregation_sample' => {
top_hits: {
size: 1,
_source: %w[meta_data.* timestamp]
}
}
}
end

it 'returns the expected Hash' do
expect(method_call).to eq(expected_hash)
end

it "does not return a reference to the internal '_source' object" do
source_hash = method_call.dig('an_aggregation_sample', :top_hits, :_source)
expect(source_hash).not_to be(top_hits._source)
expect(source_hash).to eq(_source)
end
end
end
end
end
Loading