Class: ElasticGraph::GraphQL::Schema::Type

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/elastic_graph/graphql/schema/type.rb

Overview

Represents a GraphQL type.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema, graphql_type, index_definitions, object_runtime_metadata, enum_runtime_metadata) ⇒ Type

Returns a new instance of Type.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/elastic_graph/graphql/schema/type.rb', line 22

def initialize(
  schema,
  graphql_type,
  index_definitions,
  ,
  
)
  @schema = schema
  @graphql_type = graphql_type
  @enum_values_by_name = Hash.new do |hash, key|
    hash[key] = lookup_enum_value_by_name(key)
  end

  @index_definitions = index_definitions
  @object_runtime_metadata = 
  @elasticgraph_category = &.elasticgraph_category
  @graphql_only_return_type = &.graphql_only_return_type
  @enum_runtime_metadata = 
  @enum_value_names_by_original_name = (&.values_by_name || {}).to_h do |name, value|
    [value.alternate_original_name || name, name]
  end

  @fields_by_name = build_fields_by_name_hash(schema, graphql_type).freeze
end

Instance Attribute Details

#elasticgraph_categoryObject (readonly)

Returns the value of attribute elasticgraph_category.



20
21
22
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20

def elasticgraph_category
  @elasticgraph_category
end

#fields_by_nameObject (readonly)

Returns the value of attribute fields_by_name.



20
21
22
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20

def fields_by_name
  @fields_by_name
end

#graphql_only_return_typeObject (readonly)

Returns the value of attribute graphql_only_return_type.



20
21
22
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20

def graphql_only_return_type
  @graphql_only_return_type
end

#graphql_typeObject (readonly)

Returns the value of attribute graphql_type.



20
21
22
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20

def graphql_type
  @graphql_type
end

#index_definitionsObject (readonly)

Returns the value of attribute index_definitions.



20
21
22
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20

def index_definitions
  @index_definitions
end

Instance Method Details

#abstract?Boolean

Returns:

  • (Boolean)


159
160
161
162
# File 'lib/elastic_graph/graphql/schema/type.rb', line 159

def abstract?
  return unwrap_non_null.abstract? if non_null?
  @graphql_type.kind.abstract?
end

#coerce_result(result) ⇒ Object



128
129
130
# File 'lib/elastic_graph/graphql/schema/type.rb', line 128

def coerce_result(result)
  @enum_value_names_by_original_name.fetch(result, result)
end

#collection?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/elastic_graph/graphql/schema/type.rb', line 201

def collection?
  list? || relay_connection?
end

#embedded_object?Boolean

Indicates if this type is an object type that is embedded in another indexed type in the index mapping. Note: we have avoided the term ‘nested` here because it is a specific Elasticsearch/OpenSearch mapping type that we will not necessarily be using: www.elastic.co/guide/en/elasticsearch/reference/current/nested.html

Returns:

  • (Boolean)


195
196
197
198
199
# File 'lib/elastic_graph/graphql/schema/type.rb', line 195

def embedded_object?
  return unwrap_non_null.embedded_object? if non_null?
  return false if relay_edge? || relay_connection? || @graphql_type.kind.input_object?
  object? && !indexed_document? && !indexed_aggregation?
end

#enum?Boolean

Returns:

  • (Boolean)


164
165
166
167
# File 'lib/elastic_graph/graphql/schema/type.rb', line 164

def enum?
  return unwrap_non_null.enum? if non_null?
  @graphql_type.kind.enum?
end

#enum_value_named(enum_value_name) ⇒ Object



124
125
126
# File 'lib/elastic_graph/graphql/schema/type.rb', line 124

def enum_value_named(enum_value_name)
  @enum_values_by_name[enum_value_name.to_s]
end

#field_named(field_name) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/elastic_graph/graphql/schema/type.rb', line 116

def field_named(field_name)
  @fields_by_name.fetch(field_name.to_s)
rescue KeyError => e
  msg = "No field named #{field_name} (on type #{name}) could be found"
  msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
  raise NotFoundError, msg
end

#hidden_from_queries?Boolean

Indicates this type should be hidden in the GraphQL schema so as to not be queryable. We only hide a type if both of the following are true:

  • It’s backed by one or more search index definitions

  • None of the search index definitions are accessible from queries

Returns:

  • (Boolean)


218
219
220
221
# File 'lib/elastic_graph/graphql/schema/type.rb', line 218

def hidden_from_queries?
  return false if search_index_definitions.empty?
  search_index_definitions.none?(&:accessible_from_queries?)
end

#indexed_aggregation?Boolean

Returns:

  • (Boolean)


187
188
189
# File 'lib/elastic_graph/graphql/schema/type.rb', line 187

def indexed_aggregation?
  unwrapped_has_category?(:indexed_aggregation)
end

#indexed_document?Boolean

Is the type a user-defined document type directly indexed in the index?

Returns:

  • (Boolean)


180
181
182
183
184
185
# File 'lib/elastic_graph/graphql/schema/type.rb', line 180

def indexed_document?
  return unwrap_non_null.indexed_document? if non_null?
  return false if indexed_aggregation?
  return true if subtypes.any? && subtypes.all?(&:indexed_document?)
  @index_definitions.any?
end

#nameObject



47
48
49
# File 'lib/elastic_graph/graphql/schema/type.rb', line 47

def name
  @name ||= @graphql_type.to_type_signature.to_sym
end

#nullable?Boolean

Returns:

  • (Boolean)


155
156
157
# File 'lib/elastic_graph/graphql/schema/type.rb', line 155

def nullable?
  !non_null?
end

#object?Boolean

Returns ‘true` if this type serializes as a JSON object, with sub-fields. Note this is slightly different from the GraphQL gem and GraphQL spec: it considers inputs to be distinct from objects, but for our purposes we consider inputs to be objects since they have sub-fields and serialize as JSON objects.

Returns:

  • (Boolean)


173
174
175
176
177
# File 'lib/elastic_graph/graphql/schema/type.rb', line 173

def object?
  return unwrap_non_null.object? if non_null?
  kind = @graphql_type.kind
  kind.abstract? || kind.object? || kind.input_object?
end

#relay_connection?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/elastic_graph/graphql/schema/type.rb', line 205

def relay_connection?
  unwrapped_has_category?(:relay_connection)
end

#relay_edge?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/elastic_graph/graphql/schema/type.rb', line 209

def relay_edge?
  unwrapped_has_category?(:relay_edge)
end

#search_index_definitionsObject Also known as: indexing_index_definitions

List of index definitions that should be searched for this type.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/elastic_graph/graphql/schema/type.rb', line 52

def search_index_definitions
  @search_index_definitions ||=
    if indexed_aggregation?
      # For an indexed aggregation, we just delegate to its source type. This works better than
      # dumping index definitions in the runtime metadata of the indexed aggregation type itself
      # because of abstract (interface/union) types. The source document type handles that (since
      # there is a supertype/subtype relationship on the document types) but that relationship
      # does not exist on the indexed aggregation.
      #
      # For example, assume we have these indexed document types:
      # - type Person {}
      # - type Company {}
      # - union Inventor = Person | Company
      #
      # We can go from `Inventor` to its subtypes to find the search indexes. However, `InventorAggregation`
      # is NOT a union of `PersonAggregation` and `CompanyAggregation`, so we can't do the same thing on the
      # indexed aggregation types. Delegating to the source type solves this case.
      @schema.type_named(@object_runtime_metadata.source_type).search_index_definitions
    else
      @index_definitions.union(subtypes.flat_map(&:search_index_definitions))
    end
end

#subtypesObject

Returns the subtypes of this type, if it has any. This is like ‘#possible_types` provided by the GraphQL gem, but that includes a type itself when you ask for the possible types of a non-abstract type.



112
113
114
# File 'lib/elastic_graph/graphql/schema/type.rb', line 112

def subtypes
  @subtypes ||= @schema.graphql_schema.possible_types(graphql_type).map { |t| @schema.type_from(t) } - [self]
end

#to_sObject Also known as: inspect



132
133
134
# File 'lib/elastic_graph/graphql/schema/type.rb', line 132

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

#unwrap_fullyObject

Fully unwraps this type, in order to extracts the underlying type (an object or scalar) from its wrappings. As needed, this will unwrap any of these wrappings:

- non-null
- list
- relay connection


96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/elastic_graph/graphql/schema/type.rb', line 96

def unwrap_fully
  @unwrap_fully ||= begin
    unwrapped = @schema.type_from(@graphql_type.unwrap)

    if unwrapped.relay_connection?
      unwrapped
        .field_named(@schema.element_names.edges).type.unwrap_fully
        .field_named(@schema.element_names.node).type.unwrap_fully
    else
      unwrapped
    end
  end
end

#unwrap_non_nullObject

Unwraps the non-null type wrapping, if this type is non-null. If this type is nullable, returns it as-is.



85
86
87
88
# File 'lib/elastic_graph/graphql/schema/type.rb', line 85

def unwrap_non_null
  return self if nullable?
  @schema.type_from(@graphql_type.of_type)
end