lib/graphql/schema/build_from_definition.rb in graphql-1.11.4 vs lib/graphql/schema/build_from_definition.rb in graphql-1.11.5

- old
+ new

@@ -2,23 +2,30 @@ require "graphql/schema/build_from_definition/resolve_map" module GraphQL class Schema module BuildFromDefinition + if !String.method_defined?(:-@) + using GraphQL::StringDedupBackport + end + class << self # @see {Schema.from_definition} - def from_definition(definition_string, default_resolve:, using: {}, relay: false, interpreter: true, parser: DefaultParser) - document = parser.parse(definition_string) - default_resolve ||= {} - Builder.build(document, default_resolve: default_resolve, relay: relay, using: using, interpreter: interpreter) + def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs) + from_document(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) + end + + def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true) + Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter) + end end # @api private - DefaultParser = GraphQL::Language::Parser - - # @api private module Builder extend self def build(document, default_resolve:, using: {}, interpreter: true, relay:) raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document) @@ -41,11 +48,11 @@ when GraphQL::Language::Nodes::SchemaDefinition nil # already handled when GraphQL::Language::Nodes::EnumTypeDefinition types[definition.name] = build_enum_type(definition, type_resolver) when GraphQL::Language::Nodes::ObjectTypeDefinition - types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve) + types[definition.name] = build_object_type(definition, type_resolver) when GraphQL::Language::Nodes::InterfaceTypeDefinition types[definition.name] = build_interface_type(definition, type_resolver) when GraphQL::Language::Nodes::UnionTypeDefinition types[definition.name] = build_union_type(definition, type_resolver) when GraphQL::Language::Nodes::ScalarTypeDefinition @@ -109,15 +116,15 @@ err_backtrace = err.backtrace raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace end if default_resolve.respond_to?(:resolve_type) - define_singleton_method(:resolve_type) do |*args| - default_resolve.resolve_type(*args) + def self.resolve_type(*args) + self.definition_default_resolve.resolve_type(*args) end else - define_singleton_method(:resolve_type) do |*args| + def self.resolve_type(*args) NullResolveType.call(*args) end end directives directives.values @@ -139,10 +146,24 @@ end end # Empty `orphan_types` -- this will make unreachable types ... unreachable. own_orphan_types.clear + + class << self + attr_accessor :definition_default_resolve + end + + self.definition_default_resolve = default_resolve + + def definition_default_resolve + self.class.definition_default_resolve + end + + def self.inherited(child_class) + child_class.definition_default_resolve = self.definition_default_resolve + end end end NullResolveType = ->(type, obj, ctx) { raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.") @@ -180,16 +201,16 @@ graphql_name(scalar_type_definition.name) description(scalar_type_definition.description) ast_node(scalar_type_definition) if default_resolve.respond_to?(:coerce_input) - define_singleton_method(:coerce_input) do |val, ctx| - default_resolve.coerce_input(self, val, ctx) + def self.coerce_input(val, ctx) + ctx.schema.definition_default_resolve.coerce_input(self, val, ctx) end - define_singleton_method(:coerce_result) do |val, ctx| - default_resolve.coerce_result(self, val, ctx) + def self.coerce_result(val, ctx) + ctx.schema.definition_default_resolve.coerce_result(self, val, ctx) end end end end @@ -200,27 +221,24 @@ possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) }) ast_node(union_type_definition) end end - def build_object_type(object_type_definition, type_resolver, default_resolve:) + def build_object_type(object_type_definition, type_resolver) builder = self - type_def = nil - typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) } Class.new(GraphQL::Schema::Object) do - type_def = self graphql_name(object_type_definition.name) description(object_type_definition.description) ast_node(object_type_definition) object_type_definition.interfaces.each do |interface_name| interface_defn = type_resolver.call(interface_name) implements(interface_defn) end - builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn) + builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true) end end def build_input_object_type(input_object_type_definition, type_resolver) builder = self @@ -245,24 +263,28 @@ else default_value end end + NO_DEFAULT_VALUE = {}.freeze + def build_arguments(type_class, arguments, type_resolver) builder = self arguments.each do |argument_defn| - default_value_kwargs = {} - if !argument_defn.default_value.nil? - default_value_kwargs[:default_value] = builder.build_default_value(argument_defn.default_value) + default_value_kwargs = if !argument_defn.default_value.nil? + { default_value: builder.build_default_value(argument_defn.default_value) } + else + NO_DEFAULT_VALUE end type_class.argument( argument_defn.name, type: type_resolver.call(argument_defn.type), required: false, description: argument_defn.description, + deprecation_reason: builder.build_deprecation_reason(argument_defn.directives), ast_node: argument_defn, camelize: false, method_access: false, **default_value_kwargs ) @@ -293,14 +315,14 @@ end def build_fields(owner, field_definitions, type_resolver, default_resolve:) builder = self - field_definitions.map do |field_definition| + field_definitions.each do |field_definition| type_name = resolve_type_name(field_definition.type) - resolve_method_name = "resolve_field_#{field_definition.name}" - owner.field( + resolve_method_name = -"resolve_field_#{field_definition.name}" + schema_field_defn = owner.field( field_definition.name, description: field_definition.description, type: type_resolver.call(field_definition.type), null: true, connection: type_name.end_with?("Connection"), @@ -308,19 +330,22 @@ deprecation_reason: build_deprecation_reason(field_definition.directives), ast_node: field_definition, method_conflict_warning: false, camelize: false, resolver_method: resolve_method_name, - ) do - builder.build_arguments(self, field_definition.arguments, type_resolver) + ) - # Don't do this for interfaces - if default_resolve - owner.send(:define_method, resolve_method_name) do |**args| - field_instance = self.class.get_field(field_definition.name) - default_resolve.call(field_instance, object, args, context) + builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver) + + # Don't do this for interfaces + if default_resolve + owner.class_eval <<-RUBY, __FILE__, __LINE__ + # frozen_string_literal: true + def #{resolve_method_name}(**args) + field_instance = self.class.get_field("#{field_definition.name}") + context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context) end - end + RUBY end end end def resolve_type(types, ast_node)