Class: GraphQL::Query::LiteralInput

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/query/literal_input.rb

Overview

Turn query string values into something useful for query execution

Class Method Summary collapse

Class Method Details

.coerce(type, ast_node, variables) ⇒ Object



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
# File 'lib/graphql/query/literal_input.rb', line 6

def self.coerce(type, ast_node, variables)
  case ast_node
  when nil
    nil
  when Language::Nodes::NullValue
    nil
  when Language::Nodes::VariableIdentifier
    variables[ast_node.name]
  else
    case type.kind.name
    when "SCALAR"
      # TODO smell
      # This gets used for plain values during subscriber.trigger
      if variables
        type.coerce_input(ast_node, variables.context)
      else
        type.coerce_isolated_input(ast_node)
      end
    when "ENUM"
      # TODO smell
      # This gets used for plain values sometimes
      v = ast_node.is_a?(GraphQL::Language::Nodes::Enum) ? ast_node.name : ast_node
      if variables
        type.coerce_input(v, variables.context)
      else
        type.coerce_isolated_input(v)
      end
    when "NON_NULL"
      LiteralInput.coerce(type.of_type, ast_node, variables)
    when "LIST"
      if ast_node.is_a?(Array)
        ast_node.map { |element_ast| LiteralInput.coerce(type.of_type, element_ast, variables) }
      else
        [LiteralInput.coerce(type.of_type, ast_node, variables)]
      end
    when "INPUT_OBJECT"
      # TODO smell: handling AST vs handling plain Ruby
      next_args = ast_node.is_a?(Hash) ? ast_node : ast_node.arguments
      from_arguments(next_args, type, variables)
    else
      raise "Invariant: unexpected type to coerce to: #{type}"
    end
  end
end

.from_arguments(ast_arguments, argument_owner, variables) ⇒ Object



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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/graphql/query/literal_input.rb', line 51

def self.from_arguments(ast_arguments, argument_owner, variables)
  context = variables ? variables.context : nil
  values_hash = {}
  defaults_used = Set.new

  indexed_arguments = case ast_arguments
  when Hash
    ast_arguments
  when Array
    ast_arguments.each_with_object({}) { |a, memo| memo[a.name] = a }
  else
    raise ArgumentError, "Unexpected ast_arguments: #{ast_arguments}"
  end

  argument_defns = argument_owner.arguments
  argument_defns.each do |arg_name, arg_defn|
    ast_arg = indexed_arguments[arg_name]
    # First, check the argument in the AST.
    # If the value is a variable,
    # only add a value if the variable is actually present.
    # Otherwise, coerce the value in the AST, prepare the value and add it.
    #
    # TODO: since indexed_arguments can come from a plain Ruby hash,
    # have to check for `false` or `nil` as hash values. This is getting smelly :S
    if indexed_arguments.key?(arg_name)
      arg_value = ast_arg.is_a?(GraphQL::Language::Nodes::Argument) ? ast_arg.value : ast_arg

      value_is_a_variable = arg_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)

      if (!value_is_a_variable || (value_is_a_variable && variables.key?(arg_value.name)))

        value = coerce(arg_defn.type, arg_value, variables)
        # Legacy `prepare` application
        if arg_defn.is_a?(GraphQL::Argument)
          value = arg_defn.prepare(value, context)
        end

        if value.is_a?(GraphQL::ExecutionError)
          value.ast_node = ast_arg
          raise value
        end

        values_hash[arg_name] = value
      end
    end

    # Then, the definition for a default value.
    # If the definition has a default value and
    # a value wasn't provided from the AST,
    # then add the default value.
    if arg_defn.default_value? && !values_hash.key?(arg_name)
      value = arg_defn.default_value
      defaults_used << arg_name
      # `context` isn't present when pre-calculating defaults
      if context
        if arg_defn.is_a?(GraphQL::Argument)
          value = arg_defn.prepare(value, context)
        end
        if value.is_a?(GraphQL::ExecutionError)
          value.ast_node = ast_arg
          raise value
        end
      end
      values_hash[arg_name] = value
    end
  end

  if argument_owner.is_a?(Class) || argument_owner.is_a?(GraphQL::Schema::Field)
    # A Schema::InputObject, Schema::GraphQL::Field, Schema::Directive, logic from Query::Arguments#to_kwargs
    ruby_kwargs = {}
    values_hash.each do |key, value|
      ruby_kwargs[Schema::Member::BuildType.underscore(key).to_sym] = value
    end
    if argument_owner.is_a?(Class) && argument_owner < GraphQL::Schema::InputObject
      argument_owner.new(ruby_kwargs: ruby_kwargs, context: context, defaults_used: defaults_used)
    else
      ruby_kwargs
    end
  else
    result = argument_owner.arguments_class.new(values_hash, context: context, defaults_used: defaults_used)
    result.prepare
  end
end