Skip to content

Commit

Permalink
Handle case class reserved fields in codegen (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostdogpr authored Jul 11, 2020
1 parent 1eda75a commit e04ef89
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 17 deletions.
9 changes: 7 additions & 2 deletions tools/src/main/scala/caliban/tools/ClientWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ object ClientWriter {
"""

def safeName(name: String): String =
if (reservedKeywords.contains(name)) s"`$name`" else name
if (reservedKeywords.contains(name)) s"`$name`"
else if (caseClassReservedFields.contains(name)) s"${name}_"
else name

@tailrec
def getTypeLetter(typesMap: Map[String, TypeDefinition], letter: String = "A"): String =
Expand Down Expand Up @@ -289,7 +291,7 @@ object ClientWriter {
}

def writeArgumentFields(args: List[InputValueDefinition]): String =
s"${args.map(arg => s"${safeName(arg.name)}: ${writeType(arg.ofType)}${writeDefaultArgument(arg)}").mkString(", ")}"
s"${args.map(arg => s"${safeName(arg.name)} : ${writeType(arg.ofType)}${writeDefaultArgument(arg)}").mkString(", ")}"

def writeDefaultArgument(arg: InputValueDefinition): String =
arg.ofType match {
Expand Down Expand Up @@ -380,4 +382,7 @@ object ClientWriter {
"yield",
"_"
)

val caseClassReservedFields =
Set("wait", "notify", "toString", "notifyAll", "hashCode", "getClass", "finalize", "equals", "clone")
}
14 changes: 7 additions & 7 deletions tools/src/main/scala/caliban/tools/SchemaWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ object SchemaWriter {

def writeRootField(field: FieldDefinition, effect: String): String = {
val argsName = if (field.args.nonEmpty) s" ${field.name.capitalize}Args =>" else ""
s"${safeName(field.name)}:$argsName $effect[${writeType(field.ofType)}]"
s"${safeName(field.name)} :$argsName $effect[${writeType(field.ofType)}]"
}

def writeRootQueryOrMutationDef(op: ObjectTypeDefinition, effect: String): String =
Expand Down Expand Up @@ -122,7 +122,7 @@ object SchemaWriter {

def writeInputObject(typedef: InputObjectTypeDefinition): String =
s"""${writeDescription(typedef.description)}case class ${typedef.name}(${typedef.fields
.map(writeInputValue(_, typedef))
.map(writeInputValue)
.mkString(", ")})"""

def writeEnum(typedef: EnumTypeDefinition): String =
Expand All @@ -147,17 +147,17 @@ object SchemaWriter {

def writeField(field: FieldDefinition, of: ObjectTypeDefinition): String =
if (field.args.nonEmpty) {
s"${writeDescription(field.description)}${safeName(field.name)}: ${of.name.capitalize}${field.name.capitalize}Args => ${writeType(field.ofType)}"
s"${writeDescription(field.description)}${safeName(field.name)} : ${of.name.capitalize}${field.name.capitalize}Args => ${writeType(field.ofType)}"
} else {
s"""${writeDescription(field.description)}${safeName(field.name)}: ${writeType(field.ofType)}"""
s"""${writeDescription(field.description)}${safeName(field.name)} : ${writeType(field.ofType)}"""
}

def writeInputValue(value: InputValueDefinition, of: InputObjectTypeDefinition): String =
s"""${writeDescription(value.description)}${safeName(value.name)}: ${writeType(value.ofType)}"""
def writeInputValue(value: InputValueDefinition): String =
s"""${writeDescription(value.description)}${safeName(value.name)} : ${writeType(value.ofType)}"""

def writeArguments(field: FieldDefinition): String = {
def fields(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)}").mkString(", ")}"

if (field.args.nonEmpty) {
s"case class ${field.name.capitalize}Args(${fields(field.args)})"
Expand Down
31 changes: 30 additions & 1 deletion tools/src/test/scala/caliban/tools/ClientWriterSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,35 @@ object Client {
}
}
}
"""
)
)
},
testM("input object with reserved name") {
val schema =
"""
input CharacterInput {
wait: String!
}
""".stripMargin

assertM(gen(schema))(
equalTo(
"""import caliban.client._
import caliban.client.Value._
object Client {
case class CharacterInput(wait_ : String)
object CharacterInput {
implicit val encoder: ArgEncoder[CharacterInput] = new ArgEncoder[CharacterInput] {
override def encode(value: CharacterInput): Value =
ObjectValue(List("wait" -> implicitly[ArgEncoder[String]].encode(value.wait_)))
override def typeName: String = "CharacterInput"
}
}
}
"""
)
Expand Down Expand Up @@ -377,7 +406,7 @@ object Client {
/**
* name
*/
@deprecated(${tripleQuotes}foo\nbar${tripleQuotes}, "")
@deprecated(${tripleQuotes}foo\nbar$tripleQuotes, "")
def name: SelectionBuilder[Character, String] = Field("name", Scalar())
}

Expand Down
35 changes: 28 additions & 7 deletions tools/src/test/scala/caliban/tools/SchemaWriterSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ object SchemaWriterSpec extends DefaultRunnableSpec {
val typeCaseClass = Parser
.parseQuery(schema)
.map(_.objectTypeDefinitions.map(SchemaWriter.writeObject).mkString("\n"))
.flatMap(Formatter.format(_, None).map(_.trim))

val typeCaseClassArgs = Parser
.parseQuery(schema)
Expand All @@ -38,6 +39,7 @@ object SchemaWriterSpec extends DefaultRunnableSpec {
argClass = SchemaWriter.writeArguments(typeDefField) if argClass.length > 0
} yield argClass).mkString("\n")
}
.flatMap(Formatter.format(_, None).map(_.trim))

assertM(typeCaseClass)(
equalTo(
Expand Down Expand Up @@ -67,13 +69,13 @@ object SchemaWriterSpec extends DefaultRunnableSpec {
.map(
_.objectTypeDefinition("Query").map(SchemaWriter.writeRootQueryOrMutationDef(_, "zio.UIO")).mkString("\n")
)
.flatMap(Formatter.format(_, None).map(_.trim))

assertM(result)(
equalTo(
"""
case class Query(
user: UserArgs => zio.UIO[Option[User]],
userList: zio.UIO[List[Option[User]]]
"""case class Query(
user: UserArgs => zio.UIO[Option[User]],
userList: zio.UIO[List[Option[User]]]
)""".stripMargin
)
)
Expand All @@ -92,12 +94,12 @@ userList: zio.UIO[List[Option[User]]]
.map(SchemaWriter.writeRootQueryOrMutationDef(_, "zio.UIO"))
.mkString("\n")
)
.flatMap(Formatter.format(_, None).map(_.trim))

assertM(result)(
equalTo(
"""
|case class Mutation(
|setMessage: SetMessageArgs => zio.UIO[Option[String]]
"""case class Mutation(
| setMessage: SetMessageArgs => zio.UIO[Option[String]]
|)""".stripMargin
)
)
Expand Down Expand Up @@ -338,6 +340,25 @@ object Types {
case class Character(`private`: String, `object`: String, `type`: String)
}
"""
)
)
},
testM("case class reserved field name used") {
val schema =
"""
type Character {
wait: String!
}
""".stripMargin

assertM(gen(schema))(
equalTo(
"""object Types {
case class Character(wait_ : String)
}
"""
)
Expand Down

0 comments on commit e04ef89

Please sign in to comment.