Class: ElasticGraph::GraphQL::Schema

Inherits:
Object
  • Object
show all
Defined in:
lib/elastic_graph/graphql/schema.rb,
lib/elastic_graph/graphql/schema/type.rb,
lib/elastic_graph/graphql/schema/field.rb,
lib/elastic_graph/graphql/schema/arguments.rb,
lib/elastic_graph/graphql/schema/enum_value.rb,
lib/elastic_graph/graphql/schema/relation_join.rb

Defined Under Namespace

Modules: Arguments Classes: EnumValue, Field, RelationJoin, Type

Constant Summary collapse

BUILT_IN_TYPE_NAMES =
(
  scalar_types = ::GraphQL::Schema::BUILT_IN_TYPES.keys # Int, ID, String, etc
  introspection_types = ::GraphQL::Schema.types.keys # __Type, __Schema, etc
  scalar_types.to_set.union(introspection_types)
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(graphql_schema_string:, config:, logger:, runtime_metadata:, datastore_search_router:, index_definitions_by_graphql_type:, graphql_gem_plugins:, graphql_adapter:) ⇒ Schema

Returns a new instance of Schema.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/elastic_graph/graphql/schema.rb', line 29

def initialize(
  graphql_schema_string:,
  config:,
  logger:,
  runtime_metadata:,
  datastore_search_router:,
  index_definitions_by_graphql_type:,
  graphql_gem_plugins:,
  graphql_adapter:
)
  @element_names = .schema_element_names
  @config = config
  @logger = logger
  @runtime_metadata = 
  @datastore_search_router = datastore_search_router

  resolvers_needing_lookahead = .graphql_resolvers_by_name.filter_map do |name, resolver|
    name if resolver.needs_lookahead
  end.to_set

  @types_by_graphql_type = Hash.new do |hash, key|
    hash[key] = Type.new(
      self,
      key,
      index_definitions_by_graphql_type[key.graphql_name] || [],
      .object_types_by_name[key.graphql_name],
      .enum_types_by_name[key.graphql_name],
      .scalar_types_by_name[key.graphql_name],
      resolvers_needing_lookahead
    )
  end

  # Note: as part of loading the schema, the GraphQL gem may use the resolver (such
  # when a directive has a custom scalar) so we must wait to instantiate the schema
  # as late as possible here. If we do this before initializing some of the instance
  # variables above we'll get `NoMethodError` on `nil`.
  @graphql_schema = ::GraphQL::Schema.from_definition(
    graphql_schema_string,
    base_types: {object: build_base_object_class},
    default_resolve: graphql_adapter,
    using: graphql_gem_plugins
  )

  # Pre-load all defined types so that all field extras can get configured as part
  # of loading the schema, before we execute the first query.
  @types_by_name = build_types_by_name
  @graphql_schema.visibility.preload

  log_hidden_types
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



27
28
29
# File 'lib/elastic_graph/graphql/schema.rb', line 27

def config
  @config
end

#element_namesObject (readonly)

Returns the value of attribute element_names.



27
28
29
# File 'lib/elastic_graph/graphql/schema.rb', line 27

def element_names
  @element_names
end

#graphql_schemaObject (readonly)

Returns the value of attribute graphql_schema.



27
28
29
# File 'lib/elastic_graph/graphql/schema.rb', line 27

def graphql_schema
  @graphql_schema
end

#loggerObject (readonly)

Returns the value of attribute logger.



27
28
29
# File 'lib/elastic_graph/graphql/schema.rb', line 27

def logger
  @logger
end

#runtime_metadataObject (readonly)

Returns the value of attribute runtime_metadata.



27
28
29
# File 'lib/elastic_graph/graphql/schema.rb', line 27

def 
  @runtime_metadata
end

Instance Method Details

#defined_typesObject



151
152
153
# File 'lib/elastic_graph/graphql/schema.rb', line 151

def defined_types
  @defined_types ||= @types_by_name.except(*BUILT_IN_TYPE_NAMES).values
end

#document_types_stored_in(index_definition_name) ⇒ Object

Returns all indexed document types stored in the named index definition. The returned set includes both abstract and concrete types. Multiple types may be returned when abstract types share an index with their concrete subtypes via index inheritance.

Raises:

  • (Errors::NotFoundError)

    if the index definition name is not recognized

  • (ArgumentError)

    if given the name of a rollover index instead of the parent index definition name



128
129
130
131
132
133
134
135
136
# File 'lib/elastic_graph/graphql/schema.rb', line 128

def document_types_stored_in(index_definition_name)
  indexed_document_types_by_index_definition_name.fetch(index_definition_name) do
    if index_definition_name.include?(ROLLOVER_INDEX_INFIX_MARKER)
      raise ArgumentError, "`#{index_definition_name}` is the name of a rollover index; pass the name of the parent index definition instead."
    else
      raise Errors::NotFoundError, "The index definition `#{index_definition_name}` does not appear to exist. Is it misspelled?"
    end
  end
end

#enum_value_named(type_name, enum_value_name) ⇒ Object



142
143
144
# File 'lib/elastic_graph/graphql/schema.rb', line 142

def enum_value_named(type_name, enum_value_name)
  type_named(type_name).enum_value_named(enum_value_name)
end

#field_named(type_name, field_name) ⇒ Object



138
139
140
# File 'lib/elastic_graph/graphql/schema.rb', line 138

def field_named(type_name, field_name)
  type_named(type_name).field_named(field_name)
end

#graphql_query_contextObject



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

def graphql_query_context
  @graphql_query_context ||= new_graphql_query(nil).context
end

#indexed_document_typesObject

The list of user-defined types that are indexed document types. (Indexed aggregation types will not be included in this.)



147
148
149
# File 'lib/elastic_graph/graphql/schema.rb', line 147

def indexed_document_types
  @indexed_document_types ||= defined_types.select(&:indexed_document?)
end

#new_graphql_query(query_string, operation_name: nil, variables: {}, context: {}, document: nil, validate: true) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/elastic_graph/graphql/schema.rb', line 80

def new_graphql_query(
  query_string,
  operation_name: nil,
  variables: {},
  context: {},
  document: nil,
  validate: true
)
  ::GraphQL::Query.new(
    graphql_schema,
    query_string,
    variables: variables,
    operation_name: operation_name,
    document: document,
    validate: validate,
    context: context.merge({
      datastore_search_router: @datastore_search_router,
      elastic_graph_schema: self,
      visibility_profile: VISIBILITY_PROFILE
    })
  )
end

#to_sObject Also known as: inspect



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

def to_s
  "#<#{self.class.name} 0x#{__id__.to_s(16)} indexed_document_types=[#{indexed_document_types.map(&:name).sort.join(", ")}]>"
end

#type_from(graphql_type) ⇒ Object



107
108
109
# File 'lib/elastic_graph/graphql/schema.rb', line 107

def type_from(graphql_type)
  @types_by_graphql_type[graphql_type]
end

#type_named(type_name) ⇒ Object

Note: this does not support “wrapped” types (e.g. ‘Int!` or `[Int]` compared to `Int`), as the graphql schema object does not give us an index of those by name. You can still get type objects for wrapped types, but you need to get it from a field object of that type.



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

def type_named(type_name)
  @types_by_name.fetch(type_name)
rescue KeyError => e
  msg = "No type named #{type_name} could be found"
  msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
  raise Errors::NotFoundError, msg
end