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
|
# frozen_string_literal: true
module GraphQL
module StaticValidation
module RequiredInputObjectAttributesArePresent
def on_input_object(node, parent)
if parent.is_a? GraphQL::Language::Nodes::Argument
validate_input_object(node, context, parent)
end
super
end
private
def get_parent_type(context, parent)
# If argument_definition is defined we're at nested object
# and need to refer to the containing input object type rather
# than the field_definition.
# h/t @rmosolgo
arg_defn = context.argument_definition
# Double checking that arg_defn is an input object as nested
# scalars, namely JSON, can make it to this branch
defn = if arg_defn && arg_defn.type.unwrap.kind.input_object?
arg_defn.type.unwrap
else
context.directive_definition || context.field_definition
end
parent_type = context.warden.get_argument(defn, parent_name(parent, defn))
parent_type ? parent_type.type.unwrap : nil
end
def validate_input_object(ast_node, context, parent)
parent_type = get_parent_type(context, parent)
return unless parent_type && parent_type.kind.input_object?
required_fields = context.warden.arguments(parent_type)
.select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
.map!(&:graphql_name)
present_fields = ast_node.arguments.map(&:name)
missing_fields = required_fields - present_fields
missing_fields.each do |missing_field|
path = [*context.path, missing_field]
missing_field_type = context.warden.get_argument(parent_type, missing_field).type
add_error(RequiredInputObjectAttributesArePresentError.new(
"Argument '#{missing_field}' on InputObject '#{parent_type.to_type_signature}' is required. Expected type #{missing_field_type.to_type_signature}",
argument_name: missing_field,
argument_type: missing_field_type.to_type_signature,
input_object_type: parent_type.to_type_signature,
path: path,
nodes: ast_node,
))
end
end
end
end
end
|