1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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 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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
# frozen_string_literal: true
module GraphQL
class Schema
module Interface
include GraphQL::Schema::Member::GraphQLTypeNames
module DefinitionMethods
include GraphQL::Schema::Member::BaseDSLMethods
# ConfigurationExtension's responsibilities are in `def included` below
include GraphQL::Schema::Member::TypeSystemHelpers
include GraphQL::Schema::Member::HasFields
include GraphQL::Schema::Member::HasPath
include GraphQL::Schema::Member::RelayShortcuts
include GraphQL::Schema::Member::Scoped
include GraphQL::Schema::Member::HasAstNode
include GraphQL::Schema::Member::HasUnresolvedTypeError
include GraphQL::Schema::Member::HasDirectives
include GraphQL::Schema::Member::HasInterfaces
# Methods defined in this block will be:
# - Added as class methods to this interface
# - Added as class methods to all child interfaces
def definition_methods(&block)
# Use an instance variable to tell whether it's been included previously or not;
# You can't use constant detection because constants are brought into scope
# by `include`, which has already happened at this point.
if !defined?(@_definition_methods)
defn_methods_module = Module.new
@_definition_methods = defn_methods_module
const_set(:DefinitionMethods, defn_methods_module)
extend(self::DefinitionMethods)
end
self::DefinitionMethods.module_exec(&block)
end
# @see {Schema::Warden} hides interfaces without visible implementations
def visible?(context)
true
end
def type_membership_class(membership_class = nil)
if membership_class
@type_membership_class = membership_class
else
@type_membership_class || find_inherited_value(:type_membership_class, GraphQL::Schema::TypeMembership)
end
end
# Here's the tricky part. Make sure behavior keeps making its way down the inheritance chain.
def included(child_class)
if !child_class.is_a?(Class)
# In this case, it's been included into another interface.
# This is how interface inheritance is implemented
# We need this before we can call `own_interfaces`
child_class.extend(Schema::Interface::DefinitionMethods)
child_class.type_membership_class(self.type_membership_class)
child_class.ancestors.reverse_each do |ancestor|
if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
child_class.extend(ancestor::DefinitionMethods)
end
end
child_class.introspection(introspection)
child_class.description(description)
# If interfaces are mixed into each other, only define this class once
if !child_class.const_defined?(:UnresolvedTypeError, false)
add_unresolved_type_error(child_class)
end
elsif child_class < GraphQL::Schema::Object
# This is being included into an object type, make sure it's using `implements(...)`
backtrace_line = caller_locations(0, 10).find do |location|
location.base_label == "implements" &&
location.path.end_with?("schema/member/has_interfaces.rb")
end
if !backtrace_line
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
end
end
super
end
def orphan_types(*types)
if types.any?
@orphan_types = types
else
all_orphan_types = @orphan_types || []
all_orphan_types += super if defined?(super)
all_orphan_types.uniq
end
end
def kind
GraphQL::TypeKinds::INTERFACE
end
end
extend DefinitionMethods
def unwrap
self
end
end
end
end
|