lib/graphql/schema/build_from_definition.rb in graphql-2.0.14 vs lib/graphql/schema/build_from_definition.rb in graphql-2.0.15
- old
+ new
@@ -4,28 +4,28 @@
module GraphQL
class Schema
module BuildFromDefinition
class << self
# @see {Schema.from_definition}
- def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
- from_document(parser.parse(definition_string), **kwargs)
+ def from_definition(schema_superclass, definition_string, parser: GraphQL.default_parser, **kwargs)
+ from_document(schema_superclass, parser.parse(definition_string), **kwargs)
end
- def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
- from_document(parser.parse_file(definition_path), **kwargs)
+ def from_definition_path(schema_superclass, definition_path, parser: GraphQL.default_parser, **kwargs)
+ from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
end
- def from_document(document, default_resolve:, using: {}, relay: false)
- Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
+ def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
+ Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
end
end
# @api private
module Builder
extend self
- def build(document, default_resolve:, using: {}, relay:)
+ def build(schema_superclass, document, default_resolve:, using: {}, relay:)
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
if default_resolve.is_a?(Hash)
default_resolve = ResolveMap.new(default_resolve)
end
@@ -34,11 +34,11 @@
if schema_defns.size > 1
raise InvalidDocumentError.new('Must provide only one schema definition.')
end
schema_definition = schema_defns.first
types = {}
- directives = {}
+ directives = schema_superclass.directives.dup
type_resolver = build_resolve_type(types, directives, ->(type_name) { types[type_name] ||= Schema::LateBoundType.new(type_name)})
# Make a different type resolver because we need to coerce directive arguments
# _while_ building the schema.
# It will dig for a type if it encounters a custom type. This could be a problem if there are cycles.
directive_type_resolver = nil
@@ -63,14 +63,18 @@
end
# In case any directives referenced built-in types for their arguments:
replace_late_bound_types_with_built_in(types)
+ schema_extensions = nil
document.definitions.each do |definition|
case definition
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
nil # already handled
+ when GraphQL::Language::Nodes::SchemaExtension
+ schema_extensions ||= []
+ schema_extensions << definition
else
# It's possible that this was already loaded by the directives
prev_type = types[definition.name]
if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
@@ -101,11 +105,11 @@
subscription_root_type = types['Subscription']
end
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
- Class.new(GraphQL::Schema) do
+ schema_class = Class.new(schema_superclass) do
begin
# Add these first so that there's some chance of resolving late-bound types
orphan_types types.values
query query_root_type
mutation mutation_root_type
@@ -155,10 +159,18 @@
def self.inherited(child_class)
child_class.definition_default_resolve = self.definition_default_resolve
end
end
+
+ if schema_extensions
+ schema_extensions.each do |ext|
+ build_directives(schema_class, ext, type_resolver)
+ end
+ end
+
+ schema_class
end
NullResolveType = ->(type, obj, ctx) {
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
}
@@ -194,28 +206,33 @@
end
end
def build_directives(definition, ast_node, type_resolver)
dirs = prepare_directives(ast_node, type_resolver)
- dirs.each do |dir_class, options|
- definition.directive(dir_class, **options)
+ dirs.each do |(dir_class, options)|
+ if definition.respond_to?(:schema_directive)
+ # it's a schema
+ definition.schema_directive(dir_class, **options)
+ else
+ definition.directive(dir_class, **options)
+ end
end
end
def prepare_directives(ast_node, type_resolver)
- dirs = {}
+ dirs = []
ast_node.directives.each do |dir_node|
if dir_node.name == "deprecated"
# This is handled using `deprecation_reason`
next
else
dir_class = type_resolver.call(dir_node.name)
if dir_class.nil?
- raise ArgumentError, "No definition for @#{dir_node.name} on #{ast_node.name} at #{ast_node.line}:#{ast_node.col}"
+ raise ArgumentError, "No definition for @#{dir_node.name} #{ast_node.respond_to?(:name) ? "on #{ast_node.name} " : ""}at #{ast_node.line}:#{ast_node.col}"
end
options = args_to_kwargs(dir_class, dir_node)
- dirs[dir_class] = options
+ dirs << [dir_class, options]
end
end
dirs
end
@@ -387,10 +404,9 @@
Module.new do
include GraphQL::Schema::Interface
graphql_name(interface_type_definition.name)
description(interface_type_definition.description)
interface_type_definition.interfaces.each do |interface_name|
- "Implements: #{interface_type_definition} -> #{interface_name}"
interface_defn = type_resolver.call(interface_name)
implements(interface_defn)
end
ast_node(interface_type_definition)
builder.build_directives(self, interface_type_definition, type_resolver)