# frozen_string_literal: true module GraphQL class Schema # Subclasses of this can influence how {GraphQL::Execution::Interpreter} runs queries. # # - {.include?}: if it returns `false`, the field or fragment will be skipped altogether, as if it were absent # - {.resolve}: Wraps field resolution (so it should call `yield` to continue) class Directive < GraphQL::Schema::Member extend GraphQL::Schema::Member::HasArguments class << self # Return a name based on the class name, # but downcase the first letter. def default_graphql_name @default_graphql_name ||= begin camelized_name = super camelized_name[0] = camelized_name[0].downcase camelized_name end end def locations(*new_locations) if new_locations.any? @locations = new_locations else @locations ||= (superclass.respond_to?(:locations) ? superclass.locations : []) end end def default_directive(new_default_directive = nil) if new_default_directive != nil @default_directive = new_default_directive elsif @default_directive.nil? @default_directive = (superclass.respond_to?(:default_directive) ? superclass.default_directive : false) else @default_directive end end def to_graphql defn = GraphQL::Directive.new defn.name = self.graphql_name defn.description = self.description defn.locations = self.locations defn.default_directive = self.default_directive defn.metadata[:type_class] = self arguments.each do |name, arg_defn| arg_graphql = arg_defn.to_graphql defn.arguments[arg_graphql.name] = arg_graphql end defn end # If false, this part of the query won't be evaluated def include?(_object, _arguments, _context) true end # Continuing is passed as a block; `yield` to continue def resolve(object, arguments, context) yield end end LOCATIONS = [ QUERY = :QUERY, MUTATION = :MUTATION, SUBSCRIPTION = :SUBSCRIPTION, FIELD = :FIELD, FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION, FRAGMENT_SPREAD = :FRAGMENT_SPREAD, INLINE_FRAGMENT = :INLINE_FRAGMENT, SCHEMA = :SCHEMA, SCALAR = :SCALAR, OBJECT = :OBJECT, FIELD_DEFINITION = :FIELD_DEFINITION, ARGUMENT_DEFINITION = :ARGUMENT_DEFINITION, INTERFACE = :INTERFACE, UNION = :UNION, ENUM = :ENUM, ENUM_VALUE = :ENUM_VALUE, INPUT_OBJECT = :INPUT_OBJECT, INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION, ] DEFAULT_DEPRECATION_REASON = 'No longer supported' LOCATION_DESCRIPTIONS = { QUERY: 'Location adjacent to a query operation.', MUTATION: 'Location adjacent to a mutation operation.', SUBSCRIPTION: 'Location adjacent to a subscription operation.', FIELD: 'Location adjacent to a field.', FRAGMENT_DEFINITION: 'Location adjacent to a fragment definition.', FRAGMENT_SPREAD: 'Location adjacent to a fragment spread.', INLINE_FRAGMENT: 'Location adjacent to an inline fragment.', SCHEMA: 'Location adjacent to a schema definition.', SCALAR: 'Location adjacent to a scalar definition.', OBJECT: 'Location adjacent to an object type definition.', FIELD_DEFINITION: 'Location adjacent to a field definition.', ARGUMENT_DEFINITION: 'Location adjacent to an argument definition.', INTERFACE: 'Location adjacent to an interface definition.', UNION: 'Location adjacent to a union definition.', ENUM: 'Location adjacent to an enum definition.', ENUM_VALUE: 'Location adjacent to an enum value definition.', INPUT_OBJECT: 'Location adjacent to an input object type definition.', INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.', } end end end