Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure we can type GraphQL object with anonymous input fields #1162

Merged
merged 3 commits into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions lib/tapioca/dsl/compilers/graphql_input_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ def decorate
arguments = constant.all_argument_definitions
return if arguments.empty?

graphql_type_helper = Helpers::GraphqlTypeHelper.new

root.create_path(constant) do |input_object|
arguments.each do |argument|
name = argument.keyword.to_s
input_object.create_method(name, return_type: graphql_type_helper.type_for(argument.type))
input_object.create_method(name, return_type: Helpers::GraphqlTypeHelper.type_for(argument.type))
end
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/tapioca/dsl/compilers/graphql_mutation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ def decorate
return if arguments.empty?

arguments_by_name = arguments.to_h { |a| [a.keyword.to_s, a] }
graphql_type_helper = Helpers::GraphqlTypeHelper.new

params = compile_method_parameters_to_rbi(method_def).map do |param|
name = param.param.name
argument = arguments_by_name.fetch(name, nil)
create_typed_param(param.param, argument ? graphql_type_helper.type_for(argument.type) : "T.untyped")
create_typed_param(param.param, argument ? Helpers::GraphqlTypeHelper.type_for(argument.type) : "T.untyped")
end

root.create_path(constant) do |mutation|
Expand Down
38 changes: 21 additions & 17 deletions lib/tapioca/dsl/helpers/graphql_type_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
module Tapioca
module Dsl
module Helpers
class GraphqlTypeHelper
module GraphqlTypeHelper
extend self

extend T::Sig
include RBIHelper
include Runtime::Reflection

sig { params(type: GraphQL::Schema::Wrapper).returns(String) }
def type_for(type)
Expand All @@ -17,45 +17,49 @@ def type_for(type)
when GraphQL::Types::Boolean.singleton_class
"T::Boolean"
when GraphQL::Types::Float.singleton_class
qualified_name_of(Float)
when GraphQL::Types::ID.singleton_class
qualified_name_of(String)
type_for_constant(Float)
when GraphQL::Types::ID.singleton_class, GraphQL::Types::String.singleton_class
type_for_constant(String)
when GraphQL::Types::Int.singleton_class
qualified_name_of(Integer)
type_for_constant(Integer)
when GraphQL::Types::ISO8601Date.singleton_class
qualified_name_of(Date)
type_for_constant(Date)
when GraphQL::Types::ISO8601DateTime.singleton_class
qualified_name_of(DateTime)
type_for_constant(DateTime)
when GraphQL::Types::JSON.singleton_class
"T::Hash[::String, T.untyped]"
when GraphQL::Types::String.singleton_class
qualified_name_of(String)
when GraphQL::Schema::Enum.singleton_class
enum_values = T.cast(unwrapped_type.enum_values, T::Array[GraphQL::Schema::EnumValue])
value_types = enum_values.map { |v| qualified_name_of(v.value.class) }.uniq
value_types = enum_values.map { |v| type_for_constant(v.value.class) }.uniq

if value_types.size == 1
value_types.first
T.must(value_types.first)
else
"T.any(#{value_types.join(", ")})"
end
when GraphQL::Schema::InputObject.singleton_class
qualified_name_of(unwrapped_type)
type_for_constant(unwrapped_type)
else
"T.untyped"
end

parsed_type = T.must(parsed_type)

if type.list?
parsed_type = "T::Array[#{parsed_type}]"
end

unless type.non_null?
parsed_type = as_nilable_type(parsed_type)
parsed_type = RBIHelper.as_nilable_type(parsed_type)
end

parsed_type
end

private

sig { params(constant: Module).returns(String) }
def type_for_constant(constant)
Runtime::Reflection.qualified_name_of(constant) || "T.untyped"
end
end
end
end
Expand Down
23 changes: 23 additions & 0 deletions spec/tapioca/dsl/compilers/graphql_input_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ def post_id; end

assert_equal(expected, rbi_for(:CreateCommentInput))
end

it "doesn't fail when input object is anonymous" do
add_ruby_file("create_comment_input.rb", <<~RUBY)
class CreateCommentInput < GraphQL::Schema::InputObject
argument :transport, Class.new(GraphQL::Schema::InputObject), required: true

def resolve(body:, post_id:)
# ...
end
end
RUBY

expected = <<~RBI
# typed: strong

class CreateCommentInput
sig { returns(T.untyped) }
def transport; end
end
RBI

assert_equal(expected, rbi_for(:CreateCommentInput))
end
end
end
end
Expand Down