lib/elastic_graph/graphql/aggregation/nested_sub_aggregation.rb



# Copyright 2024 Block, Inc.
#
# Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
#
# frozen_string_literal: true

require "elastic_graph/graphql/aggregation/field_path_encoder"
require "elastic_graph/support/memoizable_data"

module ElasticGraph
  class GraphQL
    module Aggregation
      # Represents a sub-aggregation on a `nested` field.
      # For the relevant Elasticsearch docs, see:
      # https://www.elastic.co/guide/en/elasticsearch/reference/8.10/search-aggregations-bucket-nested-aggregation.html
      class NestedSubAggregation < Support::MemoizableData.define(:nested_path, :query)
        # The nested path in the GraphQL query from the parent aggregation to this-subaggregation, encoded
        # for use as a hash key.
        #
        # This key will be unique in the scope of the parent aggregation query, and thus suitable as a key
        # in a sub-aggregations hash.
        def nested_path_key
          @nested_path_key ||= FieldPathEncoder.encode(nested_path.map(&:name_in_graphql_query))
        end

        def build_agg_hash(filter_interpreter, parent_queries:)
          detail = query.build_agg_detail(filter_interpreter, field_path: nested_path, parent_queries: parent_queries)
          return {} if detail.nil?

          parent_query_names = parent_queries.map(&:name)
          {
            Key.encode(parent_query_names + [nested_path_key]) => {
              "nested" => {"path" => FieldPathEncoder.encode(nested_path.filter_map(&:name_in_index))},
              "aggs" => detail.clauses,
              "meta" => detail.meta.merge({
                "size" => query.paginator.desired_page_size,
                "adapter" => query.grouping_adapter.meta_name
              })
            }.compact
          }
        end
      end
    end
  end
end