module GraphQL::Execution::Execute::ExecutionFunctions

@api private

Public Instance Methods

continue_or_wait(raw_value, arguments, field_ctx) click to toggle source

If the returned object is lazy (unfinished), assign the lazy object to `.value=` so we can resolve it later. When we resolve it later, reassign it to `.value=` so that the finished value replaces the unfinished one.

If the returned object is finished, continue to coerce and resolve child fields

# File lib/graphql/execution/execute.rb, line 139
def continue_or_wait(raw_value, arguments, field_ctx)
  if (lazy_method = field_ctx.schema.lazy_method_name(raw_value))
    field_ctx.value = Execution::Lazy.new {
      inner_value = begin
          begin
            raw_value.public_send(lazy_method)
          rescue GraphQL::UnauthorizedError => err
            field_ctx.schema.unauthorized_object(err)
          end
        rescue GraphQL::ExecutionError => err
          err
        end

      field_ctx.value = continue_or_wait(inner_value, arguments, field_ctx)
    }
  else
    field_ctx.value = continue_resolve_field(raw_value, field_ctx)
  end
end
continue_resolve_field(raw_value, field_ctx) click to toggle source
# File lib/graphql/execution/execute.rb, line 159
def continue_resolve_field(raw_value, field_ctx)
  if field_ctx.parent.invalid_null?
    return nil
  end
  query = field_ctx.query

  case raw_value
  when GraphQL::ExecutionError
    raw_value.ast_node ||= field_ctx.ast_node
    raw_value.path = field_ctx.path
    query.context.errors.push(raw_value)
  when Array
    list_errors = raw_value.each_with_index.select { |value, _| value.is_a?(GraphQL::ExecutionError) }
    if list_errors.any?
      list_errors.each do |error, index|
        error.ast_node = field_ctx.ast_node
        error.path = field_ctx.path + [index]
        query.context.errors.push(error)
      end
    end
  end

  resolve_value(
    raw_value,
    field_ctx.type,
    field_ctx,
  )
end
lazy_resolve_root_selection(result, query: nil, multiplex: nil) click to toggle source
# File lib/graphql/execution/execute.rb, line 44
def lazy_resolve_root_selection(result, query: nil, multiplex: nil)
  if query.nil? && multiplex.queries.length == 1
    query = multiplex.queries[0]
  end

  tracer = (query || multiplex)
  tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
    GraphQL::Execution::Lazy.resolve(result)
  end
end
resolve_field(object, field_ctx) click to toggle source
# File lib/graphql/execution/execute.rb, line 97
def resolve_field(object, field_ctx)
  query = field_ctx.query
  irep_node = field_ctx.irep_node
  parent_type = irep_node.owner_type
  field = field_ctx.field

  raw_value = begin
    arguments = query.arguments_for(irep_node, field)
    field_ctx.trace("execute_field", { context: field_ctx }) do
      field_ctx.schema.middleware.invoke([parent_type, object, field, arguments, field_ctx])
    end
  rescue GraphQL::ExecutionError => err
    err
  end

  if field_ctx.schema.lazy?(raw_value)
    field_ctx.value = Execution::Lazy.new {
      inner_value = field_ctx.trace("execute_field_lazy", {context: field_ctx}) {
        begin
          begin
            field_ctx.field.lazy_resolve(raw_value, arguments, field_ctx)
          rescue GraphQL::UnauthorizedError => err
            field_ctx.schema.unauthorized_object(err)
          end
        rescue GraphQL::ExecutionError => err
          err
        end
      }
      continue_or_wait(inner_value, arguments, field_ctx)
    }
  else
    continue_or_wait(raw_value, arguments, field_ctx)
  end
end
resolve_root_selection(query) click to toggle source
# File lib/graphql/execution/execute.rb, line 30
def resolve_root_selection(query)
  query.trace("execute_query", query: query) do
    operation = query.selected_operation
    op_type = operation.operation_type
    root_type = query.root_type_for_operation(op_type)
    resolve_selection(
      query.root_value,
      root_type,
      query.context,
      mutation: query.mutation?
    )
  end
end
resolve_selection(object, current_type, current_ctx, mutation: false ) click to toggle source
# File lib/graphql/execution/execute.rb, line 55
def resolve_selection(object, current_type, current_ctx, mutation: false )
  # Assign this _before_ resolving the children
  # so that when a child propagates null, the selection result is
  # ready for it.
  current_ctx.value = {}

  selections_on_type = current_ctx.irep_node.typed_children[current_type]

  selections_on_type.each do |name, child_irep_node|
    field_ctx = current_ctx.spawn_child(
      key: name,
      object: object,
      irep_node: child_irep_node,
    )

    field_result = resolve_field(
      object,
      field_ctx
    )

    if field_result.is_a?(Skip)
      next
    end

    if mutation
      GraphQL::Execution::Lazy.resolve(field_ctx)
    end


    # If the last subselection caused a null to propagate to _this_ selection,
    # then we may as well quit executing fields because they
    # won't be in the response
    if current_ctx.invalid_null?
      break
    else
      current_ctx.value[name] = field_ctx
    end
  end

  current_ctx.value
end
resolve_value(value, field_type, field_ctx) click to toggle source
# File lib/graphql/execution/execute.rb, line 188
def resolve_value(value, field_type, field_ctx)
  field_defn = field_ctx.field

  if value.nil?
    if field_type.kind.non_null?
      parent_type = field_ctx.irep_node.owner_type
      type_error = GraphQL::InvalidNullError.new(parent_type, field_defn, value)
      field_ctx.schema.type_error(type_error, field_ctx)
      PROPAGATE_NULL
    else
      nil
    end
  elsif value.is_a?(GraphQL::ExecutionError)
    if field_type.kind.non_null?
      PROPAGATE_NULL
    else
      nil
    end
  elsif value.is_a?(Array) && value.any? && value.all? {|v| v.is_a?(GraphQL::ExecutionError)}
    if field_type.kind.non_null?
      PROPAGATE_NULL
    else
      nil
    end
  elsif value.is_a?(Skip)
    field_ctx.value = value
  else
    case field_type.kind
    when GraphQL::TypeKinds::SCALAR, GraphQL::TypeKinds::ENUM
      field_type.coerce_result(value, field_ctx)
    when GraphQL::TypeKinds::LIST
      inner_type = field_type.of_type
      i = 0
      result = []
      field_ctx.value = result

      value.each do |inner_value|
        inner_ctx = field_ctx.spawn_child(
          key: i,
          object: inner_value,
          irep_node: field_ctx.irep_node,
        )

        inner_result = resolve_value(
          inner_value,
          inner_type,
          inner_ctx,
        )

        return PROPAGATE_NULL if inner_result == PROPAGATE_NULL

        inner_ctx.value = inner_result
        result << inner_ctx
        i += 1
      end

      result
    when GraphQL::TypeKinds::NON_NULL
      inner_type = field_type.of_type
      resolve_value(
        value,
        inner_type,
        field_ctx,
      )
    when GraphQL::TypeKinds::OBJECT
      resolve_selection(
        value,
        field_type,
        field_ctx
      )
    when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
      query = field_ctx.query
      resolved_type = field_type.resolve_type(value, field_ctx)
      possible_types = query.possible_types(field_type)

      if !possible_types.include?(resolved_type)
        parent_type = field_ctx.irep_node.owner_type
        type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
        field_ctx.schema.type_error(type_error, field_ctx)
        PROPAGATE_NULL
      else
        resolve_value(
          value,
          resolved_type,
          field_ctx,
        )
      end
    else
      raise("Unknown type kind: #{field_type.kind}")
    end
  end
end