Class: ElasticGraph::Apollo::GraphQL::EntitiesFieldResolver::RepresentationWithId

Inherits:
Object
  • Object
show all
Defined in:
lib/elastic_graph/apollo/graphql/entities_field_resolver.rb

Overview

A simple value object containing a parsed form of an ‘_Any` representation when there’s an ‘id` field.

Constant Summary collapse

Adapter =
::Data.define(:type, :schema_element_names) do
  # @implements Adapter

  def customize_query(query, representations)
    # Given a set of representations, builds a filter that will match all of them (and only them).
    all_ids = representations.map(&:id).reject { |id| id.is_a?(::Array) or id.is_a?(::Hash) }
    filter = {"id" => {schema_element_names.equal_to_any_of => all_ids}}

    query.merge_with(
      document_pagination: {first: representations.length},
      requested_fields: additional_requested_fields_for(representations),
      filter: filter
    )
  end

  # Given a query response, indexes the search hits for easy `O(1)` retrieval by `identify_matching_hit`.
  # This allows us to provide `O(N)` complexity in our resolver instead of `O(N^2)`.
  def index_search_hits(response)
    response.to_h { |hit| [hit.id, hit] }
  end

  # Given some indexed search hits and a representation, identifies the search hit that matches the representation.
  def identify_matching_hit(indexed_search_hits, representation, context:, index:)
    hit = indexed_search_hits[representation.id]
    hit if hit && match?(representation.other_fields, hit.payload)
  end

  def indexed?
    true
  end

  private

  def additional_requested_fields_for(representations)
    representations.flat_map do |representation|
      fields_in(representation.other_fields)
    end
  end

  def fields_in(hash)
    hash.flat_map do |field_name, value|
      case value
      when ::Hash
        fields_in(value).map do |sub_field_name|
          "#{field_name}.#{sub_field_name}"
        end
      else
        # TODO: Add support for array cases.
        [field_name]
      end
    end
  end

  def match?(expected, actual)
    expected.all? do |key, value|
      case value
      when ::Hash
        match?(value, actual[key])
      when ::Array
        # TODO: Add support for array filtering, instead of ignoring it.
        true
      else
        value == actual[key]
      end
    end
  end
end

Instance Method Summary collapse

Constructor Details

#initialize(type:, id:, other_fields:, schema_element_names:) ⇒ RepresentationWithId

Returns a new instance of RepresentationWithId.



149
150
151
152
153
154
155
156
# File 'lib/elastic_graph/apollo/graphql/entities_field_resolver.rb', line 149

def initialize(type:, id:, other_fields:, schema_element_names:)
  super(
    type: type, id: id, other_fields: other_fields, schema_element_names: schema_element_names,
    # All `RepresentationWithId` instances with the same `type` can be handled by the same adapter,
    # since we can combine them into a single query filtering on `id`.
    adapter: Adapter.new(type, schema_element_names)
  )
end