From 0d4f08c567a83e1c6e1266df4df79afa6cec20ef Mon Sep 17 00:00:00 2001 From: AlixBa Date: Tue, 19 Oct 2021 15:54:06 +0200 Subject: [PATCH] Option to disable default implementation on interface types selection builder --- .../scala/caliban/codegen/CalibanCli.scala | 2 +- .../caliban/codegen/CalibanSettings.scala | 2 + .../caliban/tools/CalibanCommonSettings.scala | 13 ++- .../scala/caliban/tools/ClientWriter.scala | 45 +++++---- .../main/scala/caliban/tools/Codegen.scala | 88 +++++++++--------- .../main/scala/caliban/tools/Options.scala | 9 +- .../caliban/tools/compiletime/Config.scala | 9 +- .../caliban/tools/ClientWriterSpec.scala | 92 ++++++++++++++++++- .../scala/caliban/tools/OptionsSpec.scala | 42 ++++++++- .../tools/compiletime/ConfigSpec.scala | 15 ++- vuepress/docs/docs/client.md | 5 +- 11 files changed, 238 insertions(+), 84 deletions(-) diff --git a/codegen-sbt/src/main/scala/caliban/codegen/CalibanCli.scala b/codegen-sbt/src/main/scala/caliban/codegen/CalibanCli.scala index a8671b8fd3..34ce48a5fd 100644 --- a/codegen-sbt/src/main/scala/caliban/codegen/CalibanCli.scala +++ b/codegen-sbt/src/main/scala/caliban/codegen/CalibanCli.scala @@ -70,7 +70,7 @@ object CalibanCli { private val genClientHelpMsg = s""" - |calibanGenClient schemaPath outputPath [--scalafmtPath path] [--headers name:value,name2:value2] [--packageName name] [--clientName name] [--genView true|false] + |calibanGenClient schemaPath outputPath [--scalafmtPath path] [--headers name:value,name2:value2] [--packageName name] [--clientName name] [--genView true|false] [--defaultOnInterfaceTypes true|false] | |This command will create a Scala file in `outputPath` containing client code for all the |typed defined in the provided GraphQL schema defined at `schemaPath`. Instead of a path, diff --git a/codegen-sbt/src/main/scala/caliban/codegen/CalibanSettings.scala b/codegen-sbt/src/main/scala/caliban/codegen/CalibanSettings.scala index 25c30c036f..6148a0e94f 100644 --- a/codegen-sbt/src/main/scala/caliban/codegen/CalibanSettings.scala +++ b/codegen-sbt/src/main/scala/caliban/codegen/CalibanSettings.scala @@ -19,6 +19,7 @@ final case class CalibanFileSettings(file: File, settings: CalibanCommonSettings def splitFiles(value: Boolean): CalibanFileSettings = this.copy(settings = this.settings.splitFiles(value)) def enableFmt(value: Boolean): CalibanFileSettings = this.copy(settings = this.settings.enableFmt(value)) def extensibleEnums(value: Boolean): CalibanFileSettings = this.copy(settings = this.settings.extensibleEnums(value)) + def defaultOnInterfaceTypes(value: Boolean): CalibanFileSettings = this.copy(settings = this.settings.defaultOnInterfaceTypes(value)) } final case class CalibanUrlSettings(url: URL, settings: CalibanCommonSettings) extends CalibanSettings { @@ -34,4 +35,5 @@ final case class CalibanUrlSettings(url: URL, settings: CalibanCommonSettings) e def splitFiles(value: Boolean): CalibanUrlSettings = this.copy(settings = this.settings.splitFiles(value)) def enableFmt(value: Boolean): CalibanUrlSettings = this.copy(settings = this.settings.enableFmt(value)) def extensibleEnums(value: Boolean): CalibanUrlSettings = this.copy(settings = this.settings.extensibleEnums(value)) + def defaultOnInterfaceTypes(value: Boolean): CalibanUrlSettings = this.copy(settings = this.settings.defaultOnInterfaceTypes(value)) } diff --git a/tools/src/main/scala/caliban/tools/CalibanCommonSettings.scala b/tools/src/main/scala/caliban/tools/CalibanCommonSettings.scala index b1b30d961d..9d30b02f15 100644 --- a/tools/src/main/scala/caliban/tools/CalibanCommonSettings.scala +++ b/tools/src/main/scala/caliban/tools/CalibanCommonSettings.scala @@ -10,7 +10,8 @@ final case class CalibanCommonSettings( imports: Seq[String], splitFiles: Option[Boolean], enableFmt: Option[Boolean], - extensibleEnums: Option[Boolean] + extensibleEnums: Option[Boolean], + defaultOnInterfaceTypes: Option[Boolean] ) { private[caliban] def toOptions(schemaPath: String, toPath: String): Options = @@ -28,7 +29,8 @@ final case class CalibanCommonSettings( abstractEffectType = Option.empty, splitFiles = splitFiles, enableFmt = enableFmt, - extensibleEnums = extensibleEnums + extensibleEnums = extensibleEnums, + defaultOnInterfaceTypes = defaultOnInterfaceTypes ) private[caliban] def combine(r: => CalibanCommonSettings): CalibanCommonSettings = @@ -42,7 +44,8 @@ final case class CalibanCommonSettings( imports = this.imports ++ r.imports, splitFiles = r.splitFiles.orElse(this.splitFiles), enableFmt = r.enableFmt.orElse(this.enableFmt), - extensibleEnums = r.extensibleEnums.orElse(this.extensibleEnums) + extensibleEnums = r.extensibleEnums.orElse(this.extensibleEnums), + defaultOnInterfaceTypes = r.genView.orElse(this.defaultOnInterfaceTypes) ) def clientName(value: String): CalibanCommonSettings = this.copy(clientName = Some(value)) @@ -56,6 +59,7 @@ final case class CalibanCommonSettings( def splitFiles(value: Boolean): CalibanCommonSettings = this.copy(splitFiles = Some(value)) def enableFmt(value: Boolean): CalibanCommonSettings = this.copy(enableFmt = Some(value)) def extensibleEnums(value: Boolean): CalibanCommonSettings = this.copy(extensibleEnums = Some(value)) + def defaultOnInterfaceTypes(value: Boolean): CalibanCommonSettings = this.copy(defaultOnInterfaceTypes = Some(value)) } object CalibanCommonSettings { @@ -70,6 +74,7 @@ object CalibanCommonSettings { imports = Seq.empty, splitFiles = None, enableFmt = None, - extensibleEnums = None + extensibleEnums = None, + defaultOnInterfaceTypes = None ) } diff --git a/tools/src/main/scala/caliban/tools/ClientWriter.scala b/tools/src/main/scala/caliban/tools/ClientWriter.scala index 854276dc5c..6fc35fd8d7 100644 --- a/tools/src/main/scala/caliban/tools/ClientWriter.scala +++ b/tools/src/main/scala/caliban/tools/ClientWriter.scala @@ -21,7 +21,8 @@ object ClientWriter { genView: Boolean = false, additionalImports: Option[List[String]] = None, splitFiles: Boolean = false, - extensibleEnums: Boolean = false + extensibleEnums: Boolean = false, + defaultOnInterfaceTypes: Boolean = true )(implicit scalarMappings: ScalarMappings): List[(String, String)] = { require(packageName.isDefined || !splitFiles, "splitFiles option requires a package name") @@ -72,7 +73,7 @@ object ClientWriter { schemaDef.exists(_.subscription.getOrElse("Subscription") == obj.name) ) .map { typedef => - val content = writeObject(typedef, genView) + val content = writeObject(typedef, genView, defaultOnInterfaceTypes) val fullContent = if (splitFiles) s"""import caliban.client.FieldBuilder._ @@ -133,7 +134,7 @@ object ClientWriter { val queries = schema .objectTypeDefinition(schemaDef.flatMap(_.query).getOrElse("Query")) .map { typedef => - val content = writeRootQuery(typedef) + val content = writeRootQuery(typedef, defaultOnInterfaceTypes) val fullContent = if (splitFiles) s"""import caliban.client.FieldBuilder._ @@ -159,7 +160,7 @@ object ClientWriter { val mutations = schema .objectTypeDefinition(schemaDef.flatMap(_.mutation).getOrElse("Mutation")) .map { typedef => - val content = writeRootMutation(typedef) + val content = writeRootMutation(typedef, defaultOnInterfaceTypes) val fullContent = if (splitFiles) s"""import caliban.client.FieldBuilder._ @@ -185,7 +186,7 @@ object ClientWriter { val subscriptions = schema .objectTypeDefinition(schemaDef.flatMap(_.subscription).getOrElse("Subscription")) .map { typedef => - val content = writeRootSubscription(typedef) + val content = writeRootSubscription(typedef, defaultOnInterfaceTypes) val fullContent = if (splitFiles) s"""import caliban.client.FieldBuilder._ @@ -290,14 +291,14 @@ object ClientWriter { ): String = s"type ${typedef.name} = _root_.caliban.client.Operations.RootQuery" - def writeRootQuery(typedef: ObjectTypeDefinition)(implicit + def writeRootQuery(typedef: ObjectTypeDefinition, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings ): String = s"""object ${typedef.name} { | ${typedef.fields - .map(writeField(_, "_root_.caliban.client.Operations.RootQuery", optionalUnion = false)) + .map(writeField(_, "_root_.caliban.client.Operations.RootQuery", optionalUnion = false,defaultOnInterfaceTypes)) .mkString("\n ")} |} |""".stripMargin @@ -307,14 +308,14 @@ object ClientWriter { ): String = s"type ${typedef.name} = _root_.caliban.client.Operations.RootMutation" - def writeRootMutation(typedef: ObjectTypeDefinition)(implicit + def writeRootMutation(typedef: ObjectTypeDefinition, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings ): String = s"""object ${typedef.name} { | ${typedef.fields - .map(writeField(_, "_root_.caliban.client.Operations.RootMutation", optionalUnion = false)) + .map(writeField(_, "_root_.caliban.client.Operations.RootMutation", optionalUnion = false, defaultOnInterfaceTypes)) .mkString("\n ")} |} |""".stripMargin @@ -324,14 +325,14 @@ object ClientWriter { ): String = s"type ${typedef.name} = _root_.caliban.client.Operations.RootSubscription" - def writeRootSubscription(typedef: ObjectTypeDefinition)(implicit + def writeRootSubscription(typedef: ObjectTypeDefinition, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings ): String = s"""object ${typedef.name} { | ${typedef.fields - .map(writeField(_, "_root_.caliban.client.Operations.RootSubscription", optionalUnion = false)) + .map(writeField(_, "_root_.caliban.client.Operations.RootSubscription", optionalUnion = false, defaultOnInterfaceTypes)) .mkString("\n ")} |} |""".stripMargin @@ -346,7 +347,7 @@ object ClientWriter { s"type $objectName" } - def writeObject(typedef: ObjectTypeDefinition, genView: Boolean)(implicit + def writeObject(typedef: ObjectTypeDefinition, genView: Boolean, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings @@ -356,10 +357,10 @@ object ClientWriter { val unionTypes = typesMap.typesMap.collect { case (key, _: UnionTypeDefinition) => key } val optionalUnionTypeFields = typedef.fields.flatMap { field => val isOptionalUnionType = unionTypes.exists(_.compareToIgnoreCase(field.ofType.toString) == 0) - if (isOptionalUnionType) Some(collectFieldInfo(field, objectName, optionalUnion = true)) + if (isOptionalUnionType) Some(collectFieldInfo(field, objectName, optionalUnion = true, defaultOnInterfaceTypes)) else None } - val fields = typedef.fields.map(collectFieldInfo(_, objectName, optionalUnion = false)) + val fields = typedef.fields.map(collectFieldInfo(_, objectName, optionalUnion = false, defaultOnInterfaceTypes)) val view = if (genView) "\n " + writeView(typedef.name, fields.map(_.typeInfo)) else "" val allFields = fields ++ optionalUnionTypeFields @@ -611,12 +612,12 @@ object ClientWriter { private val tripleQuotes = "\"\"\"" private val doubleQuotes = "\"" - def writeField(field: FieldDefinition, typeName: String, optionalUnion: Boolean)(implicit + def writeField(field: FieldDefinition, typeName: String, optionalUnion: Boolean, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings ): String = - writeFieldInfo(collectFieldInfo(field, typeName, optionalUnion)) + writeFieldInfo(collectFieldInfo(field, typeName, optionalUnion, defaultOnInterfaceTypes)) def writeFieldInfo(fieldInfo: FieldInfo): String = { val FieldInfo( @@ -639,7 +640,7 @@ object ClientWriter { s"""$description${deprecated}def $safeName$typeParam$args$innerSelection$implicits: SelectionBuilder[$typeName, $outputType] = _root_.caliban.client.SelectionBuilder.Field("$name", $builder$argBuilder)""" } - def collectFieldInfo(field: FieldDefinition, typeName: String, optionalUnion: Boolean)(implicit + def collectFieldInfo(field: FieldDefinition, typeName: String, optionalUnion: Boolean, defaultOnInterfaceTypes: Boolean)(implicit typesMap: TypesMap, mappingClashedTypeNames: MappingClashedTypeNames, scalarMappings: ScalarMappings @@ -724,7 +725,15 @@ object ClientWriter { } else if (interfaceTypes.nonEmpty) { ( s"[$typeLetter]", - s"(${interfaceTypes.map(t => s"""on${t.name}: Option[SelectionBuilder[${safeTypeName(t.name)}, $typeLetter]] = None""").mkString(", ")})", + s"(${interfaceTypes.map { t => + val base = s"""on${t.name}: Option[SelectionBuilder[${safeTypeName(t.name)}, $typeLetter]]""" + val default = { + if (defaultOnInterfaceTypes) { " = None" } + else { "" } + } + base + default + } + .mkString(", ")})", writeType(field.ofType).replace(fieldType, typeLetter), writeTypeBuilder( field.ofType, diff --git a/tools/src/main/scala/caliban/tools/Codegen.scala b/tools/src/main/scala/caliban/tools/Codegen.scala index f1628f01c5..b659935306 100644 --- a/tools/src/main/scala/caliban/tools/Codegen.scala +++ b/tools/src/main/scala/caliban/tools/Codegen.scala @@ -24,50 +24,52 @@ object Codegen { genType: GenType ): RIO[Blocking, List[File]] = for { - schema <- loader.load - s = ".*/[scala|play.*|app][^/]*/(.*)/(.*).scala".r.findFirstMatchIn(arguments.toPath) - packageName = arguments.packageName.orElse(s.map(_.group(1).split("/").mkString("."))) - objectName = arguments.clientName.orElse(s.map(_.group(2))).getOrElse("Client") - abstractEffectType = arguments.abstractEffectType.getOrElse(false) - effect = arguments.effect.getOrElse { - if (abstractEffectType) "F" else "zio.UIO" - } - genView = arguments.genView.getOrElse(false) - scalarMappings = arguments.scalarMappings - splitFiles = arguments.splitFiles.getOrElse(false) - enableFmt = arguments.enableFmt.getOrElse(true) - extensibleEnums = arguments.extensibleEnums.getOrElse(false) - code = genType match { - case GenType.Schema => - List( - objectName -> SchemaWriter.write(schema, packageName, effect, arguments.imports, abstractEffectType)( - ScalarMappings(scalarMappings) - ) - ) - case GenType.Client => - ClientWriter.write( - schema, - objectName, - packageName, - genView, - arguments.imports, - splitFiles, - extensibleEnums - )( - ScalarMappings(scalarMappings) - ) - } - formatted <- if (enableFmt) Formatter.format(code, arguments.fmtPath) else Task.succeed(code) - paths <- ZIO.foreach(formatted) { case (objectName, objectCode) => - effectBlocking { - val path = Path.of( - if (splitFiles) s"${arguments.toPath.reverse.dropWhile(_ != '/').reverse}$objectName.scala" - else arguments.toPath - ) + schema <- loader.load + s = ".*/[scala|play.*|app][^/]*/(.*)/(.*).scala".r.findFirstMatchIn(arguments.toPath) + packageName = arguments.packageName.orElse(s.map(_.group(1).split("/").mkString("."))) + objectName = arguments.clientName.orElse(s.map(_.group(2))).getOrElse("Client") + abstractEffectType = arguments.abstractEffectType.getOrElse(false) + effect = arguments.effect.getOrElse { + if (abstractEffectType) "F" else "zio.UIO" + } + genView = arguments.genView.getOrElse(false) + scalarMappings = arguments.scalarMappings + splitFiles = arguments.splitFiles.getOrElse(false) + enableFmt = arguments.enableFmt.getOrElse(true) + extensibleEnums = arguments.extensibleEnums.getOrElse(false) + defaultOnInterfaceTypes = arguments.defaultOnInterfaceTypes.getOrElse(false) + code = genType match { + case GenType.Schema => + List( + objectName -> SchemaWriter.write(schema, packageName, effect, arguments.imports, abstractEffectType)( + ScalarMappings(scalarMappings) + ) + ) + case GenType.Client => + ClientWriter.write( + schema, + objectName, + packageName, + genView, + arguments.imports, + splitFiles, + extensibleEnums, + defaultOnInterfaceTypes + )( + ScalarMappings(scalarMappings) + ) + } + formatted <- if (enableFmt) Formatter.format(code, arguments.fmtPath) else Task.succeed(code) + paths <- ZIO.foreach(formatted) { case (objectName, objectCode) => + effectBlocking { + val path = Path.of( + if (splitFiles) s"${arguments.toPath.reverse.dropWhile(_ != '/').reverse}$objectName.scala" + else arguments.toPath + ) - Files.writeString(path, objectCode, StandardCharsets.UTF_8).toFile - } - } + Files.writeString(path, objectCode, StandardCharsets.UTF_8).toFile + } + } } yield paths def generate(arguments: Options, genType: GenType): RIO[Blocking, List[File]] = diff --git a/tools/src/main/scala/caliban/tools/Options.scala b/tools/src/main/scala/caliban/tools/Options.scala index da75df6bdf..1b3bb3d311 100644 --- a/tools/src/main/scala/caliban/tools/Options.scala +++ b/tools/src/main/scala/caliban/tools/Options.scala @@ -17,7 +17,8 @@ final case class Options( abstractEffectType: Option[Boolean], splitFiles: Option[Boolean], enableFmt: Option[Boolean], - extensibleEnums: Option[Boolean] + extensibleEnums: Option[Boolean], + defaultOnInterfaceTypes: Option[Boolean] ) object Options { @@ -34,7 +35,8 @@ object Options { abstractEffectType: Option[Boolean], splitFiles: Option[Boolean], enableFmt: Option[Boolean], - extensibleEnums: Option[Boolean] + extensibleEnums: Option[Boolean], + defaultOnInterfaceTypes: Option[Boolean] ) def fromArgs(args: List[String]): Option[Options] = @@ -77,7 +79,8 @@ object Options { rawOpts.abstractEffectType, rawOpts.splitFiles, rawOpts.enableFmt, - rawOpts.extensibleEnums + rawOpts.extensibleEnums, + rawOpts.defaultOnInterfaceTypes ) } case _ => None diff --git a/tools/src/main/scala/caliban/tools/compiletime/Config.scala b/tools/src/main/scala/caliban/tools/compiletime/Config.scala index 91cb0758be..4df3fcf6bf 100644 --- a/tools/src/main/scala/caliban/tools/compiletime/Config.scala +++ b/tools/src/main/scala/caliban/tools/compiletime/Config.scala @@ -12,7 +12,8 @@ trait Config { imports: List[String] = List.empty, splitFiles: Boolean = false, enableFmt: Boolean = true, - extensibleEnums: Boolean = false + extensibleEnums: Boolean = false, + defaultOnInterfaceTypes: Boolean = true ) { private[caliban] def toCalibanCommonSettings: CalibanCommonSettings = CalibanCommonSettings( @@ -25,7 +26,8 @@ trait Config { imports = imports, splitFiles = Some(splitFiles), enableFmt = Some(enableFmt), - extensibleEnums = Some(extensibleEnums) + extensibleEnums = Some(extensibleEnums), + defaultOnInterfaceTypes = Some(defaultOnInterfaceTypes) ) private[caliban] def asScalaCode: String = { @@ -40,7 +42,8 @@ trait Config { | imports = ${toScalaCode(imports)(v => s""""$v"""")}, | splitFiles = $splitFiles, | enableFmt = $enableFmt, - | extensibleEnums = $extensibleEnums + | extensibleEnums = $extensibleEnums, + | defaultOnInterfaceTypes = $defaultOnInterfaceTypes |) """.stripMargin.trim } diff --git a/tools/src/test/scala/caliban/tools/ClientWriterSpec.scala b/tools/src/test/scala/caliban/tools/ClientWriterSpec.scala index 57dc40b423..0b98c6e38b 100644 --- a/tools/src/test/scala/caliban/tools/ClientWriterSpec.scala +++ b/tools/src/test/scala/caliban/tools/ClientWriterSpec.scala @@ -14,15 +14,19 @@ object ClientWriterSpec extends DefaultRunnableSpec { schema: String, scalarMappings: Map[String, String] = Map.empty, additionalImports: List[String] = List.empty, - extensibleEnums: Boolean = false + extensibleEnums: Boolean = false, + defaultOnInterfaceTypes: Boolean = true ): RIO[Blocking, String] = Parser .parseQuery(schema) .flatMap(doc => Formatter.format( ClientWriter - .write(doc, additionalImports = Some(additionalImports), extensibleEnums = extensibleEnums)( - ScalarMappings(Some(scalarMappings)) - ) + .write( + doc, + additionalImports = Some(additionalImports), + extensibleEnums = extensibleEnums, + defaultOnInterfaceTypes = defaultOnInterfaceTypes + )(ScalarMappings(Some(scalarMappings))) .head ._2, None @@ -843,6 +847,86 @@ object Client { ) ) ) + }, + testM("default implementation on interface types selection") { + val schema = + """ + interface Order { + name: String! + } + + type Ascending implements Order { + name: String! + } + + type Sort { + order: Order! + } + """.stripMargin + + assertM(gen(schema, Map.empty, List.empty)) { + equalTo( + """import caliban.client.FieldBuilder._ +import caliban.client._ + +object Client { + + type Ascending + object Ascending { + def name: SelectionBuilder[Ascending, String] = _root_.caliban.client.SelectionBuilder.Field("name", Scalar()) + } + + type Sort + object Sort { + def order[A](onAscending: Option[SelectionBuilder[Ascending, A]] = None): SelectionBuilder[Sort, A] = + _root_.caliban.client.SelectionBuilder + .Field("order", ChoiceOf(Map("Ascending" -> onAscending).collect { case (k, Some(v)) => k -> Obj(v) })) + } + +} +""" + ) + } + }, + testM("no implementation on interface types selection") { + val schema = + """ + interface Order { + name: String! + } + + type Ascending implements Order { + name: String! + } + + type Sort { + order: Order! + } + """.stripMargin + + assertM(gen(schema, Map.empty, List.empty, defaultOnInterfaceTypes = false)) { + equalTo( + """import caliban.client.FieldBuilder._ +import caliban.client._ + +object Client { + + type Ascending + object Ascending { + def name: SelectionBuilder[Ascending, String] = _root_.caliban.client.SelectionBuilder.Field("name", Scalar()) + } + + type Sort + object Sort { + def order[A](onAscending: Option[SelectionBuilder[Ascending, A]]): SelectionBuilder[Sort, A] = + _root_.caliban.client.SelectionBuilder + .Field("order", ChoiceOf(Map("Ascending" -> onAscending).collect { case (k, Some(v)) => k -> Obj(v) })) + } + +} +""" + ) + } } ) @@ TestAspect.sequential } diff --git a/tools/src/test/scala/caliban/tools/OptionsSpec.scala b/tools/src/test/scala/caliban/tools/OptionsSpec.scala index c52494c0a0..ec8d88a3ee 100644 --- a/tools/src/test/scala/caliban/tools/OptionsSpec.scala +++ b/tools/src/test/scala/caliban/tools/OptionsSpec.scala @@ -28,6 +28,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -54,6 +55,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -66,7 +68,7 @@ object OptionsSpec extends DefaultRunnableSpec { assert(result)( equalTo( Some( - Options("schema", "output", None, None, None, None, None, None, None, None, None, None, None, None) + Options("schema", "output", None, None, None, None, None, None, None, None, None, None, None, None, None) ) ) ) @@ -105,6 +107,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -131,6 +134,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -157,6 +161,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -183,6 +188,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -209,7 +215,8 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, - Some(true) + Some(true), + None ) ) ) @@ -235,6 +242,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -261,6 +269,7 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) @@ -287,6 +296,7 @@ object OptionsSpec extends DefaultRunnableSpec { Some(true), None, None, + None, None ) ) @@ -313,11 +323,39 @@ object OptionsSpec extends DefaultRunnableSpec { None, None, None, + None, None ) ) ) ) + }, + test("provide defaultOnInterfaceTypes") { + val input = List("schema", "output", "--defaultOnInterfaceTypes", "false") + val result = Options.fromArgs(input) + assert(result)( + equalTo( + Some( + Options( + "schema", + "output", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(false) + ) + ) + ) + ) } ) } diff --git a/tools/src/test/scala/caliban/tools/compiletime/ConfigSpec.scala b/tools/src/test/scala/caliban/tools/compiletime/ConfigSpec.scala index feacec6c4d..09aac7020c 100644 --- a/tools/src/test/scala/caliban/tools/compiletime/ConfigSpec.scala +++ b/tools/src/test/scala/caliban/tools/compiletime/ConfigSpec.scala @@ -17,7 +17,8 @@ object ConfigSpec extends DefaultRunnableSpec { imports = List("zio.test._", "caliban.tools.compiletime._"), splitFiles = true, enableFmt = false, - extensibleEnums = true + extensibleEnums = true, + defaultOnInterfaceTypes = false ) private val toCalibanCommonSettingsSpec = @@ -35,7 +36,8 @@ object ConfigSpec extends DefaultRunnableSpec { imports = List("zio.test._", "caliban.tools.compiletime._"), splitFiles = Some(true), enableFmt = Some(false), - extensibleEnums = Some(true) + extensibleEnums = Some(true), + defaultOnInterfaceTypes = Some(false) ) ) ) @@ -56,7 +58,8 @@ object ConfigSpec extends DefaultRunnableSpec { | imports = List.empty, | splitFiles = false, | enableFmt = true, - | extensibleEnums = false + | extensibleEnums = false, + | defaultOnInterfaceTypes = true |) """.stripMargin.trim ) @@ -74,7 +77,8 @@ object ConfigSpec extends DefaultRunnableSpec { | imports = List("zio.test._","caliban.tools.compiletime._"), | splitFiles = true, | enableFmt = false, - | extensibleEnums = true + | extensibleEnums = true, + | defaultOnInterfaceTypes = false |) """.stripMargin.trim ) @@ -95,7 +99,8 @@ object ConfigSpec extends DefaultRunnableSpec { imports = List.empty, splitFiles = false, enableFmt = true, - extensibleEnums = false + extensibleEnums = false, + defaultOnInterfaceTypes = true ) ) ) diff --git a/vuepress/docs/docs/client.md b/vuepress/docs/docs/client.md index 0734cdb7dd..a2e518fa87 100644 --- a/vuepress/docs/docs/client.md +++ b/vuepress/docs/docs/client.md @@ -92,6 +92,7 @@ The settings available on the `cs` (`CalibanSettings`) builder are: def splitFiles(value: Boolean): CalibanSettings // Split single client object into multiple files (default: false) def enableFmt(value: Boolean): CalibanSettings // Enable code formatting with scalafmt (default: true) def extensibleEnums(value: Boolean): CalibanSettings // Generate a fallback case class for unknown enum values (default: false) + def defaultOnInterfaceTypes(value: Boolean): CalibanSettings // Provide a default implementation on interface types SelectionBuilder (default: true) // Only defined for `url` settings, for use in supplying extra headers when fetching the schema itself def headers(pairs: (String,String)*): CalibanSettings @@ -102,7 +103,7 @@ The settings available on the `cs` (`CalibanSettings`) builder are: If you prefer to generate the client explicitly rather than automatically, you can use `calibanGenClient` on the SBT CLI as follows: ```scala -calibanGenClient schemaPath outputPath [--scalafmtPath path] [--headers name:value,name2:value2] [--genView true|false] [--scalarMappings gqlType:f.q.d.n.Type,gqlType2:f.q.d.n.Type2] [--imports a.b.c._,c.d.E] [--splitFiles true|false] [--enableFmt true|false] +calibanGenClient schemaPath outputPath [--scalafmtPath path] [--headers name:value,name2:value2] [--genView true|false] [--scalarMappings gqlType:f.q.d.n.Type,gqlType2:f.q.d.n.Type2] [--imports a.b.c._,c.d.E] [--splitFiles true|false] [--enableFmt true|false] [--defaultOnInterfaceTypes true|false] calibanGenClient project/schema.graphql src/main/client/Client.scala --genView true ``` @@ -123,6 +124,7 @@ In this case the filename part of the `outputPath` will be ignored, but the valu This can be helpful with large GraphQL schemas and incremental compilation. Provide `--enableFmt false` option if you don't need to format generated files. Provide `--extensibleEnums true` option if you want to generate a fallback case class for unknown enum values. +Provide `--defaultOnInterfaceTypes false` option if you want to disable default implementation on interface types SelectionBuilder. ### CompileTimeCalibanPlugin @@ -194,6 +196,7 @@ This `ClientGenerationSettings` case class gives you the following configuration - `splitFiles: Boolean`: Split single client object into multiple files (default: `false`) - `enableFmt: Boolean`: Enable code formatting with scalafmt (default: `true`) - `extensibleEnums: Boolean`: Generate a fallback case class for unknown enum values (default: `false`) + - `defaultOnInterfaceTypes: Boolean`: Provide a default implementation on interface types SelectionBuilder. (default: `true`) Let's take a example: ```scala