Class: ElasticGraph::GraphQL::Schema::Field

Inherits:
Object
  • Object
show all
Defined in:
lib/elastic_graph/graphql/schema/field.rb

Overview

Represents a field within a GraphQL type.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema, parent_type, graphql_field, runtime_metadata) ⇒ Field

Returns a new instance of Field.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/elastic_graph/graphql/schema/field.rb', line 23

def initialize(schema, parent_type, graphql_field, )
  @schema = schema
  @schema_element_names = schema.element_names
  @parent_type = parent_type
  @graphql_field = graphql_field
  @relation = &.relation
  @computation_detail = &.computation_detail
  @name_in_index = &.name_in_index&.to_sym || name

  # Adds the :extras required by ElasticGraph. For now, this blindly adds `:lookahead`
  # to each field so that we have access to what the child selections are, as described here:
  #
  # https://graphql-ruby.org/queries/lookahead
  #
  # Currently we only need this when building an `DatastoreQuery` (which is not done for all
  # fields) so a future optimization may only add this to fields where we actually need it.
  # For now we add it to all fields because it's simplest and it's not clear if there is
  # any performance benefit to not adding it when we do not use it.
  #
  # Note: input fields do not respond to `extras`, which is why we do it conditionally here.
  #
  # Note: on GraphQL gem introspection types (e.g. `__Field`), the fields respond to `:extras`,
  # but that later causes a weird error (`ArgumentError: unknown keyword: :lookahead`)
  # when those types are accessed in a Query. We don't really want to mutate the fields on the
  # built-in types by adding `:lookahead` so it's best to avoid setting that extra on the built
  # in types.
  if @graphql_field.respond_to?(:extras) && !BUILT_IN_TYPE_NAMES.include?(parent_type.name.to_s)
    @graphql_field.extras([:lookahead])
  end
end

Instance Attribute Details

#computation_detailObject (readonly)

Returns the value of attribute computation_detail.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def computation_detail
  @computation_detail
end

#graphql_fieldObject (readonly)

Returns the value of attribute graphql_field.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def graphql_field
  @graphql_field
end

#name_in_indexObject (readonly)

Returns the value of attribute name_in_index.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def name_in_index
  @name_in_index
end

#parent_typeObject (readonly)

The type in which the field resides.



19
20
21
# File 'lib/elastic_graph/graphql/schema/field.rb', line 19

def parent_type
  @parent_type
end

#relationObject (readonly)

Returns the value of attribute relation.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def relation
  @relation
end

#schemaObject (readonly)

Returns the value of attribute schema.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def schema
  @schema
end

#schema_element_namesObject (readonly)

Returns the value of attribute schema_element_names.



21
22
23
# File 'lib/elastic_graph/graphql/schema/field.rb', line 21

def schema_element_names
  @schema_element_names
end

Instance Method Details

#aggregated?Boolean

Indicates if this is an aggregated field (used inside an ‘Aggregation` type).

Returns:

  • (Boolean)


78
79
80
# File 'lib/elastic_graph/graphql/schema/field.rb', line 78

def aggregated?
  type.unwrap_non_null.elasticgraph_category == :scalar_aggregated_values
end

#args_to_schema_form(args) ⇒ Object



82
83
84
# File 'lib/elastic_graph/graphql/schema/field.rb', line 82

def args_to_schema_form(args)
  Arguments.to_schema_form(args, @graphql_field)
end

#coerce_result(result) ⇒ Object



109
110
111
112
# File 'lib/elastic_graph/graphql/schema/field.rb', line 109

def coerce_result(result)
  return result unless parent_type.graphql_only_return_type
  type.coerce_result(result)
end

#descriptionObject



114
115
116
# File 'lib/elastic_graph/graphql/schema/field.rb', line 114

def description
  "#{@parent_type.name}.#{name}"
end

#hidden_from_queries?Boolean

Indicates this field should be hidden in the GraphQL schema so as to not be queryable. We only hide a field if resolving it would require using a datastore cluster that we can’t access. For the most part, this just delegates to ‘Type#hidden_from_queries?` which does the index accessibility check.

Returns:

  • (Boolean)


103
104
105
106
107
# File 'lib/elastic_graph/graphql/schema/field.rb', line 103

def hidden_from_queries?
  # The type has logic to check if the backing datastore index is accessible, so we just
  # delegate to that logic here.
  type.unwrap_fully.hidden_from_queries?
end

#index_field_names_for_resolutionObject

Returns a list of field names that are required from the datastore in order to resolve this field at GraphQL query handling time.



88
89
90
91
92
93
94
95
96
97
# File 'lib/elastic_graph/graphql/schema/field.rb', line 88

def index_field_names_for_resolution
  # For an embedded object, we do not require any fields because it is the nested fields
  # that we will request from the datastore, which will be required to resolve them. But
  # we do not need to request the embedded object field itself.
  return [] if type.embedded_object?
  return [] if parent_type.relay_connection? || parent_type.relay_edge?
  return index_id_field_names_for_relation if relation_join

  [name_in_index.to_s]
end

#nameObject



58
59
60
# File 'lib/elastic_graph/graphql/schema/field.rb', line 58

def name
  @name ||= @graphql_field.name.to_sym
end

#relation_joinObject

Returns an object that knows how this field joins to its relation. Used by ElasticGraph::Resolvers::NestedRelationships.



64
65
66
67
68
69
70
# File 'lib/elastic_graph/graphql/schema/field.rb', line 64

def relation_join
  # Not every field has a join relation, so it can be nil. But we do not want
  # to re-compute that on every call, so we return @relation_join if it's already
  # defined rather than if its truthy.
  return @relation_join if defined?(@relation_join)
  @relation_join = RelationJoin.from(self)
end

#sort_clauses_for(sorts) ⇒ Object

Given an array of sort enums, returns an array of datastore compatible sort clauses



73
74
75
# File 'lib/elastic_graph/graphql/schema/field.rb', line 73

def sort_clauses_for(sorts)
  Array(sorts).flat_map { |sort| sort_argument_type.enum_value_named(sort).sort_clauses }
end

#to_sObject Also known as: inspect



118
119
120
# File 'lib/elastic_graph/graphql/schema/field.rb', line 118

def to_s
  "#<#{self.class.name} #{description}>"
end

#typeObject



54
55
56
# File 'lib/elastic_graph/graphql/schema/field.rb', line 54

def type
  @type ||= @schema.type_from(@graphql_field.type)
end