lib/graphql/schema/argument.rb in graphql-1.11.4 vs lib/graphql/schema/argument.rb in graphql-1.11.5
- old
+ new
@@ -43,11 +43,12 @@
# @param as [Symbol] Override the keyword name when passed to a method
# @param prepare [Symbol] A method to call to transform this argument's valuebefore sending it to field resolution
# @param camelize [Boolean] if true, the name will be camelized when building the schema
# @param from_resolver [Boolean] if true, a Resolver class defined this argument
# @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
- def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, &definition_block)
+ # @param deprecation_reason [String]
+ def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, deprecation_reason: nil, &definition_block)
arg_name ||= name
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
@type_expr = type_expr || type
@description = desc || description
@null = !required
@@ -58,10 +59,11 @@
@keyword = as || (arg_name.is_a?(Symbol) ? arg_name : Schema::Member::BuildType.underscore(@name).to_sym)
@prepare = prepare
@ast_node = ast_node
@from_resolver = from_resolver
@method_access = method_access
+ self.deprecation_reason = deprecation_reason
if definition_block
if definition_block.arity == 1
instance_exec(self, &definition_block)
else
@@ -87,10 +89,22 @@
else
@description
end
end
+ # @return [String] Deprecation reason for this argument
+ def deprecation_reason(text = nil)
+ if text
+ validate_deprecated_or_optional(null: @null, deprecation_reason: text)
+ @deprecation_reason = text
+ else
+ @deprecation_reason
+ end
+ end
+
+ alias_method :deprecation_reason=, :deprecation_reason
+
def visible?(context)
true
end
def accessible?(context)
@@ -141,19 +155,36 @@
argument.ast_node = ast_node
argument.method_access = @method_access
if NO_DEFAULT != @default_value
argument.default_value = @default_value
end
+ if @deprecation_reason
+ argument.deprecation_reason = @deprecation_reason
+ end
argument
end
- attr_writer :type
+ def type=(new_type)
+ validate_input_type(new_type)
+ # This isn't true for LateBoundTypes, but we can assume those will
+ # be updated via this codepath later in schema setup.
+ if new_type.respond_to?(:non_null?)
+ validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
+ end
+ @type = new_type
+ end
def type
- @type ||= Member::BuildType.parse_type(@type_expr, null: @null)
- rescue StandardError => err
- raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
+ @type ||= begin
+ parsed_type = begin
+ Member::BuildType.parse_type(@type_expr, null: @null)
+ rescue StandardError => err
+ raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
+ end
+ # Use the setter method to get validations
+ self.type = parsed_type
+ end
end
def statically_coercible?
return @statically_coercible if defined?(@statically_coercible)
@@ -182,9 +213,29 @@
end
elsif @prepare.respond_to?(:call)
@prepare.call(value, context || obj.context)
else
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
+ end
+ end
+
+ private
+
+ def validate_input_type(input_type)
+ if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
+ # Do nothing; assume this will be validated later
+ elsif input_type.kind.non_null? || input_type.kind.list?
+ validate_input_type(input_type.unwrap)
+ elsif !input_type.kind.input?
+ raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
+ else
+ # It's an input type, we're OK
+ end
+ end
+
+ def validate_deprecated_or_optional(null:, deprecation_reason:)
+ if deprecation_reason && !null
+ raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
end
end
end
end
end