Skip to content

Introduce Service.generateApolloEnums to generate enums with a __Known interface #6611

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions libraries/apollo-annotations/api/apollo-annotations.api
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public abstract interface annotation class com/apollographql/apollo/annotations/
public abstract interface annotation class com/apollographql/apollo/annotations/ApolloInternal : java/lang/annotation/Annotation {
}

public abstract interface annotation class com/apollographql/apollo/annotations/ApolloPrivateEnumConstructor : java/lang/annotation/Annotation {
}

public abstract interface annotation class com/apollographql/apollo/annotations/ApolloRequiresOptIn : java/lang/annotation/Annotation {
}

Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ open annotation class com.apollographql.apollo.annotations/ApolloInternal : kotl
constructor <init>() // com.apollographql.apollo.annotations/ApolloInternal.<init>|<init>(){}[0]
}

open annotation class com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor : kotlin/Annotation { // com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor|null[0]
constructor <init>() // com.apollographql.apollo.annotations/ApolloPrivateEnumConstructor.<init>|<init>(){}[0]
}

open annotation class com.apollographql.apollo.annotations/ApolloRequiresOptIn : kotlin/Annotation { // com.apollographql.apollo.annotations/ApolloRequiresOptIn|null[0]
constructor <init>() // com.apollographql.apollo.annotations/ApolloRequiresOptIn.<init>|<init>(){}[0]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.apollographql.apollo.annotations

/**
* Kotlin has no static factory functions like Java so we rely on an OptIn marker to prevent public usage.
* See https://youtrack.jetbrains.com/issue/KT-19400/Allow-access-to-private-members-between-nested-classes-of-the-same-class
*/
@RequiresOptIn(
level = RequiresOptIn.Level.ERROR,
message = "The `__Unknown` constructor is public for technical reasons only. Use `${'$'}YourEnum.safeValueOf(String)` instead."
)
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CONSTRUCTOR)
annotation class ApolloPrivateEnumConstructor
8 changes: 5 additions & 3 deletions libraries/apollo-compiler/api/apollo-compiler.api
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ public final class com/apollographql/apollo/compiler/CodegenMetadata$Companion {

public final class com/apollographql/apollo/compiler/CodegenOptions : com/apollographql/apollo/compiler/OperationsCodegenOptions, com/apollographql/apollo/compiler/SchemaCodegenOptions {
public static final field Companion Lcom/apollographql/apollo/compiler/CodegenOptions$Companion;
public fun <init> (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;)V
public fun <init> (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;)V
public fun getAddDefaultArgumentForInputObjects ()Ljava/lang/Boolean;
public fun getAddJvmOverloads ()Ljava/lang/Boolean;
public fun getAddUnknownForEnums ()Ljava/lang/Boolean;
public fun getClassesForEnumsMatching ()Ljava/util/List;
public fun getDecapitalizeFields ()Ljava/lang/Boolean;
public fun getGenerateApolloEnums ()Ljava/lang/Boolean;
public fun getGenerateAsInternal ()Ljava/lang/Boolean;
public fun getGenerateFilterNotNull ()Ljava/lang/Boolean;
public fun getGenerateFragmentImplementations ()Ljava/lang/Boolean;
Expand Down Expand Up @@ -352,6 +353,7 @@ public abstract interface class com/apollographql/apollo/compiler/KotlinCodegenO
public abstract fun getAddDefaultArgumentForInputObjects ()Ljava/lang/Boolean;
public abstract fun getAddJvmOverloads ()Ljava/lang/Boolean;
public abstract fun getAddUnknownForEnums ()Ljava/lang/Boolean;
public abstract fun getGenerateApolloEnums ()Ljava/lang/Boolean;
public abstract fun getGenerateAsInternal ()Ljava/lang/Boolean;
public abstract fun getGenerateFilterNotNull ()Ljava/lang/Boolean;
public abstract fun getGenerateInputBuilders ()Ljava/lang/Boolean;
Expand Down Expand Up @@ -393,8 +395,8 @@ public final class com/apollographql/apollo/compiler/OptionsKt {
public static final field MODELS_OPERATION_BASED Ljava/lang/String;
public static final field MODELS_OPERATION_BASED_WITH_INTERFACES Ljava/lang/String;
public static final field MODELS_RESPONSE_BASED Ljava/lang/String;
public static final fun buildCodegenOptions (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;)Lcom/apollographql/apollo/compiler/CodegenOptions;
public static synthetic fun buildCodegenOptions$default (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/CodegenOptions;
public static final fun buildCodegenOptions (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;)Lcom/apollographql/apollo/compiler/CodegenOptions;
public static synthetic fun buildCodegenOptions$default (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/CodegenOptions;
public static final fun buildIrOptions (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;)Lcom/apollographql/apollo/compiler/IrOptions;
public static synthetic fun buildIrOptions$default (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/IrOptions;
public static final fun validate (Lcom/apollographql/apollo/compiler/CodegenOptions;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ interface KotlinCodegenOpt {
*/
val addUnknownForEnums: Boolean?

/**
* Whether to generate enums as ApolloEnum<E>.
*
* Experimental, see https://github.com/apollographql/apollo-kotlin/issues/6243.
*/
@ApolloExperimental
val generateApolloEnums: Boolean?

/**
* Whether to add default arguments for input objects.
*/
Expand Down Expand Up @@ -521,6 +529,7 @@ class CodegenOptions(
override val generateSchema: Boolean?,
override val generatedSchemaName: String?,
override val sealedClassesForEnumsMatching: List<String>?,
override val generateApolloEnums: Boolean?,
override val generateAsInternal: Boolean?,
override val addUnknownForEnums: Boolean?,
override val addDefaultArgumentForInputObjects: Boolean?,
Expand Down Expand Up @@ -548,6 +557,7 @@ fun buildCodegenOptions(
sealedClassesForEnumsMatching: List<String>? = null,
generateAsInternal: Boolean? = null,
addUnknownForEnums: Boolean? = null,
generateApolloEnums: Boolean? = null,
addDefaultArgumentForInputObjects: Boolean? = null,
generateFilterNotNull: Boolean? = null,
generateInputBuilders: Boolean? = null,
Expand All @@ -573,6 +583,7 @@ fun buildCodegenOptions(
sealedClassesForEnumsMatching = sealedClassesForEnumsMatching,
generateAsInternal = generateAsInternal,
addUnknownForEnums = addUnknownForEnums,
generateApolloEnums = generateApolloEnums,
addDefaultArgumentForInputObjects = addDefaultArgumentForInputObjects,
generateFilterNotNull = generateFilterNotNull,
generateInputBuilders = generateInputBuilders,
Expand Down Expand Up @@ -703,6 +714,7 @@ internal val defaultAddUnkownForEnums = true
internal val defaultAddDefaultArgumentForInputObjects = true
internal val defaultCodegenModels = "operationBased"
internal val defaultTargetLanguage = TargetLanguage.KOTLIN_1_9
internal val defaultGenerateApolloEnums = false

internal fun defaultTargetLanguage(targetLanguage: TargetLanguage?, upstreamCodegenMetadata: List<CodegenMetadata>): TargetLanguage {
val upstreamTargetLanguage = upstreamCodegenMetadata.map { it.targetLanguage }.distinct().run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ internal object Identifier {
const val copy = "copy"
const val Data = "Data"

const val cacheKeyForObject = "cacheKeyForObject"
const val field = "field"
const val __map = "__map"
const val __path = "__path"
const val __fields = "__fields"

Expand All @@ -63,11 +61,17 @@ internal object Identifier {
const val knownValues = "knownValues"
const val knownEntries = "knownEntries"

// extra underscores at the end to prevent potential name clashes
/**
* UNKNOWN__ should probably have been __UNKNOWN because GraphQL reserves the leading __ but it's too late now.
*
* All in all it's not too bad because typing 'U', 'N', ... is usually more intuitive and in the very unlikely event that
* there is a name clash, it can always be resolved with `@targetName`
*/
const val UNKNOWN__ = "UNKNOWN__"
const val __Unknown = "__Unknown"
const val __Known = "__Known"
const val rawValue = "rawValue"
const val types = "types"
const val testResolver = "testResolver"
const val block = "block"
const val resolver = "resolver"
const val newBuilder = "newBuilder"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import com.apollographql.apollo.compiler.codegen.kotlin.operations.OperationResp
import com.apollographql.apollo.compiler.codegen.kotlin.operations.OperationSelectionsBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.operations.OperationVariablesAdapterBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.CustomScalarAdaptersBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsApolloEnumBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsApolloEnumSupportBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsEnumBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsSealedBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumAsSealedInterfaceBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.EnumResponseAdapterBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.InlineClassBuilder
import com.apollographql.apollo.compiler.codegen.kotlin.schema.InputObjectAdapterBuilder
Expand All @@ -43,6 +45,7 @@ import com.apollographql.apollo.compiler.codegen.kotlin.schema.asTargetClassName
import com.apollographql.apollo.compiler.defaultAddDefaultArgumentForInputObjects
import com.apollographql.apollo.compiler.defaultAddJvmOverloads
import com.apollographql.apollo.compiler.defaultAddUnkownForEnums
import com.apollographql.apollo.compiler.defaultGenerateApolloEnums
import com.apollographql.apollo.compiler.defaultGenerateAsInternal
import com.apollographql.apollo.compiler.defaultGenerateFilterNotNull
import com.apollographql.apollo.compiler.defaultGenerateFragmentImplementations
Expand Down Expand Up @@ -161,6 +164,7 @@ internal object KotlinCodegen {
val jsExport = codegenOptions.jsExport ?: defaultJsExport
val requiresOptInAnnotation = codegenOptions.requiresOptInAnnotation ?: defaultRequiresOptInAnnotation
val sealedClassesForEnumsMatching = codegenOptions.sealedClassesForEnumsMatching ?: defaultSealedClassesForEnumsMatching
val generateApolloEnums = codegenOptions.generateApolloEnums ?: defaultGenerateApolloEnums
val addUnknownForEnums = codegenOptions.addUnknownForEnums ?: defaultAddUnkownForEnums
val addDefaultArgumentForInputObjects = codegenOptions.addDefaultArgumentForInputObjects
?: defaultAddDefaultArgumentForInputObjects
Expand Down Expand Up @@ -188,9 +192,14 @@ internal object KotlinCodegen {
}
builders.add(ScalarBuilder(context, irScalar, inlineClassBuilder?.className))
}
if (generateApolloEnums) {
builders.add(EnumAsApolloEnumSupportBuilder(context))
}
irSchema.irEnums.forEach { irEnum ->
if (sealedClassesForEnumsMatching.any { Regex(it).matches(irEnum.name) }) {
builders.add(EnumAsSealedBuilder(context, irEnum))
if(generateApolloEnums) {
builders.add(EnumAsApolloEnumBuilder(context, irEnum))
} else if (sealedClassesForEnumsMatching.any { Regex(it).matches(irEnum.name) }) {
builders.add(EnumAsSealedInterfaceBuilder(context, irEnum))
} else {
builders.add(EnumAsEnumBuilder(context, irEnum, addUnknownForEnums))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ internal object KotlinSymbols {

val ApolloAdaptableWith = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloAdaptableWith")
val ApolloExperimental = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloExperimental")
val ApolloPrivateEnumConstructor = ClassName(ClassNames.apolloAnnotationsPackageName, "ApolloPrivateEnumConstructor")

val JsExport = ClassName("kotlin.js", "JsExport")
val ExecutableDefinition = ClassNames.ExecutableDefinition.toKotlinPoetClassName()
Expand Down
Loading
Loading