diff --git a/codegen/src/main/scala/caliban/codegen/ClientWriter.scala b/codegen/src/main/scala/caliban/codegen/ClientWriter.scala index 2edc069f5..17b1a0c26 100644 --- a/codegen/src/main/scala/caliban/codegen/ClientWriter.scala +++ b/codegen/src/main/scala/caliban/codegen/ClientWriter.scala @@ -249,9 +249,8 @@ object ClientWriter { ) } val args = field.args match { - case Nil => "" - case list => - s"(${list.map(arg => s"${safeName(arg.name)}: ${writeType(arg.ofType)}").mkString(", ")})" + case Nil => "" + case list => s"(${writeArgumentFields(list)})" } val argBuilder = field.args match { case Nil => "" @@ -263,7 +262,14 @@ object ClientWriter { } def writeArgumentFields(args: List[InputValueDefinition]): String = - s"${args.map(arg => s"${safeName(arg.name)}: ${writeType(arg.ofType)}").mkString(", ")}" + s"${args.map(arg => s"${safeName(arg.name)}: ${writeType(arg.ofType)}${writeDefaultArgument(arg)}").mkString(", ")}" + + def writeDefaultArgument(arg: InputValueDefinition): String = + arg.ofType match { + case t if t.nullable => " = None" + case ListType(_, _) => " = Nil" + case _ => "" + } def writeArguments(field: FieldDefinition): String = if (field.args.nonEmpty) { diff --git a/codegen/src/test/scala/caliban/codegen/ClientWriterSpec.scala b/codegen/src/test/scala/caliban/codegen/ClientWriterSpec.scala index 84dcbf005..6126851b7 100644 --- a/codegen/src/test/scala/caliban/codegen/ClientWriterSpec.scala +++ b/codegen/src/test/scala/caliban/codegen/ClientWriterSpec.scala @@ -255,7 +255,7 @@ import caliban.client.Value._ object Client { - case class CharacterInput(name: String, nicknames: List[String]) + case class CharacterInput(name: String, nicknames: List[String] = Nil) object CharacterInput { implicit val encoder: ArgEncoder[CharacterInput] = new ArgEncoder[CharacterInput] { override def encode(value: CharacterInput): Value = @@ -356,6 +356,46 @@ object Client { def nicknames: SelectionBuilder[Character, List[String]] = Field("nicknames", ListOf(Scalar())) } +} +""" + ) + ) + }, + testM("default arguments for optional and list arguments") { + val schema = + """ + type Query { + characters( + first: Int! + last: Int + origins: [String]! + ): String + }""".stripMargin + + assertM( + gen(schema), + equalTo( + """import caliban.client.FieldBuilder._ +import caliban.client.SelectionBuilder._ +import caliban.client._ +import caliban.client.Operations._ + +object Client { + + type Query = RootQuery + object Query { + def characters( + first: Int, + last: Option[Int] = None, + origins: List[Option[String]] = Nil + ): SelectionBuilder[RootQuery, Option[String]] = + Field( + "characters", + OptionOf(Scalar()), + arguments = List(Argument("first", first), Argument("last", last), Argument("origins", origins)) + ) + } + } """ ) diff --git a/core/src/main/scala/caliban/parsing/adt/Type.scala b/core/src/main/scala/caliban/parsing/adt/Type.scala index 369ea7a76..f30f663fb 100644 --- a/core/src/main/scala/caliban/parsing/adt/Type.scala +++ b/core/src/main/scala/caliban/parsing/adt/Type.scala @@ -2,7 +2,10 @@ package caliban.parsing.adt import scala.annotation.tailrec -sealed trait Type +sealed trait Type { + val nonNull: Boolean + var nullable: Boolean = !nonNull +} object Type { diff --git a/examples/src/main/scala/caliban/client/Client.scala b/examples/src/main/scala/caliban/client/Client.scala index 7a08d3a98..fe99ec830 100644 --- a/examples/src/main/scala/caliban/client/Client.scala +++ b/examples/src/main/scala/caliban/client/Client.scala @@ -5,14 +5,10 @@ import caliban.client.FieldBuilder._ import caliban.client.SelectionBuilder._ import caliban.client.Operations._ import caliban.client.Value._ -import Client.Role._ -/** - * This code was auto-generated by the caliban-codegen sbt plugin - */ object Client { - sealed trait Origin extends Product with Serializable + sealed trait Origin extends scala.Product with scala.Serializable object Origin { case object BELT extends Origin case object EARTH extends Origin @@ -26,31 +22,17 @@ object Client { } implicit val encoder: ArgEncoder[Origin] = new ArgEncoder[Origin] { override def encode(value: Origin): Value = value match { - case BELT => EnumValue("BELT") - case EARTH => EnumValue("EARTH") - case MARS => EnumValue("MARS") + case Origin.BELT => EnumValue("BELT") + case Origin.EARTH => EnumValue("EARTH") + case Origin.MARS => EnumValue("MARS") } override def typeName: String = "Origin" } } - object Role { - type Captain - object Captain { - def shipName: SelectionBuilder[Captain, String] = Field("shipName", Scalar()) - } - type Engineer - object Engineer { - def shipName: SelectionBuilder[Engineer, String] = Field("shipName", Scalar()) - } - type Mechanic - object Mechanic { - def shipName: SelectionBuilder[Mechanic, String] = Field("shipName", Scalar()) - } - type Pilot - object Pilot { - def shipName: SelectionBuilder[Pilot, String] = Field("shipName", Scalar()) - } + type Engineer + object Engineer { + def shipName: SelectionBuilder[Engineer, String] = Field("shipName", Scalar()) } type Character @@ -79,9 +61,25 @@ object Client { ) } + type Pilot + object Pilot { + def shipName: SelectionBuilder[Pilot, String] = Field("shipName", Scalar()) + } + + type Mechanic + object Mechanic { + def shipName: SelectionBuilder[Mechanic, String] = Field("shipName", Scalar()) + } + + type Captain + object Captain { + def shipName: SelectionBuilder[Captain, String] = Field("shipName", Scalar()) + } + + type Queries = RootQuery object Queries { def characters[A]( - origin: Option[Origin] + origin: Option[Origin] = None )(innerSelection: SelectionBuilder[Character, A]): SelectionBuilder[RootQuery, List[A]] = Field("characters", ListOf(Obj(innerSelection)), arguments = List(Argument("origin", origin))) def character[A]( @@ -90,9 +88,11 @@ object Client { Field("character", OptionOf(Obj(innerSelection)), arguments = List(Argument("name", name))) } + type Mutations = RootMutation object Mutations { def deleteCharacter(name: String): SelectionBuilder[RootMutation, Boolean] = Field("deleteCharacter", Scalar(), arguments = List(Argument("name", name))) } } + diff --git a/examples/src/main/scala/caliban/client/ExampleApp.scala b/examples/src/main/scala/caliban/client/ExampleApp.scala index 3b69717e2..2f740ca47 100644 --- a/examples/src/main/scala/caliban/client/ExampleApp.scala +++ b/examples/src/main/scala/caliban/client/ExampleApp.scala @@ -1,6 +1,5 @@ package caliban.client -import caliban.client.Client.Role._ import caliban.client.Client._ import sttp.client._ import sttp.client.asynchttpclient.zio.AsyncHttpClientZioBackend