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

Add support for @catch and @semanticNonNull #5405

Merged
merged 42 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6007ad1
add nullability foreign schema
martinbonnin Nov 25, 2023
7aaeed7
add FieldResult and various catchTo adapters
martinbonnin Nov 25, 2023
231242d
Add IrType.result
martinbonnin Nov 25, 2023
5eac8da
add catch test
martinbonnin Nov 26, 2023
9f6e026
support for @nullOnlyOnError and @catch
martinbonnin Nov 26, 2023
6f3370a
Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Nov 27, 2023
c6970a4
Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Nov 27, 2023
acdb970
Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Nov 27, 2023
e7eb8c7
findCatch -> findCatches
martinbonnin Nov 27, 2023
e21ccd3
use the presence of the `@catch` directive definition to enable codegen
martinbonnin Nov 27, 2023
c141ad3
Add @ignoreErrors and ErrorAwareAdapter. Remove CatchToThrowAdapter
martinbonnin Nov 27, 2023
884c95e
update test fixtures
martinbonnin Nov 27, 2023
4ea6131
fix test
martinbonnin Nov 27, 2023
f265e27
fix nullable + catchToNull
martinbonnin Nov 27, 2023
540317a
nullOnlyOnError -> semanticNonNull
martinbonnin Nov 29, 2023
efbe797
add ApolloExperimental
martinbonnin Nov 29, 2023
932cc4b
fix api dump
martinbonnin Nov 29, 2023
1c425e4
allow setting a default on the schema for @catch
martinbonnin Nov 29, 2023
2f66e4f
add catch(to: THROW)
martinbonnin Nov 29, 2023
e8de0ac
enforce chosing a default CatchTo
martinbonnin Nov 29, 2023
96b710d
add validation for @catch
martinbonnin Nov 30, 2023
bc1d52d
add validation for @catch
martinbonnin Nov 30, 2023
eea2763
update api dump
martinbonnin Nov 30, 2023
466df99
fix ParserTest
martinbonnin Nov 30, 2023
411c64b
fix tests
martinbonnin Nov 30, 2023
23e753b
FieldResult.error -> FieldResult.exception
martinbonnin Nov 30, 2023
29c413d
update message
martinbonnin Nov 30, 2023
fd899d4
simpler
martinbonnin Nov 30, 2023
2fe76c3
Update libraries/apollo-api/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Dec 1, 2023
402d4d7
Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Dec 1, 2023
1a1ffe3
Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/a…
martinbonnin Dec 1, 2023
e3d6fae
nooe -> semanticNonNull
martinbonnin Dec 1, 2023
e92a2a6
fix bad copy paste
martinbonnin Dec 1, 2023
da4a0ad
update apiDump
martinbonnin Dec 1, 2023
a5f4d74
hide some more symbol
martinbonnin Dec 1, 2023
adf97ff
allow to catch non-ApolloGraphQLException
martinbonnin Dec 1, 2023
5f803f2
comment + reorder code
martinbonnin Dec 1, 2023
01fb5e5
valueOrNull -> getOrNull for consistency
martinbonnin Dec 1, 2023
3d5e6cf
API visibility
martinbonnin Dec 1, 2023
a28b606
simplify code and does not generate errorAware() adapter wrappers for…
martinbonnin Dec 1, 2023
c0f5048
add an quick test
martinbonnin Dec 1, 2023
f69d3c5
fix tests
martinbonnin Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .idea/runConfigurations/CodegenTest.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions build-logic/src/main/kotlin/Testing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent

fun Project.configureTesting() {
tasks.withType(Test::class.java) {
systemProperty("updateTestFixtures", System.getProperty("updateTestFixtures"))
systemProperty("testFilter", System.getProperty("testFilter"))
systemProperty("codegenModels", System.getProperty("codegenModels"))

forwardEnv("updateTestFixtures")
forwardEnv("testFilter")
forwardEnv("codegenModels")
}

pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
Expand All @@ -35,6 +34,16 @@ fun Project.configureTesting() {
}
}

/**
* forwards an environment variable to a test task and mark it as input
*/
fun Test.forwardEnv(name: String) {
System.getenv(name)?.let { value ->
environment(name, value)
inputs.property(name, value)
}
}

// See https://github.com/gradle/gradle/issues/23456
fun Test.addRelativeInput(name: String, dirPath: Any) {
this.inputs.dir(dirPath).withPropertyName(name).withPathSensitivity(PathSensitivity.RELATIVE)
Expand Down
35 changes: 33 additions & 2 deletions libraries/apollo-api/api/apollo-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public final class com/apollographql/apollo3/api/Adapters {
public static final field NullableStringAdapter Lcom/apollographql/apollo3/api/NullableAdapter;
public static final field StringAdapter Lcom/apollographql/apollo3/api/Adapter;
public static final field UploadAdapter Lcom/apollographql/apollo3/api/Adapter;
public static final fun -catchToNull (Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/api/Adapter;
public static final fun -catchToResult (Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/api/Adapter;
public static final fun -errorAware (Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/api/Adapter;
public static final fun -list (Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/api/ListAdapter;
public static final fun -nullable (Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/api/NullableAdapter;
public static final fun -obj (Lcom/apollographql/apollo3/api/Adapter;Z)Lcom/apollographql/apollo3/api/ObjectAdapter;
Expand Down Expand Up @@ -382,8 +385,9 @@ public final class com/apollographql/apollo3/api/CustomScalarAdapters : com/apol
public static final field Key Lcom/apollographql/apollo3/api/CustomScalarAdapters$Key;
public static final field PassThrough Lcom/apollographql/apollo3/api/CustomScalarAdapters;
public final field deferredFragmentIdentifiers Ljava/util/Set;
public final field errors Ljava/util/List;
public final field falseVariables Ljava/util/Set;
public synthetic fun <init> (Ljava/util/Map;Ljava/util/Set;Ljava/util/Set;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/util/Map;Ljava/util/Set;Ljava/util/Set;Ljava/util/List;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun adapterFor (Ljava/lang/String;)Lcom/apollographql/apollo3/api/Adapter;
public fun getKey ()Lcom/apollographql/apollo3/api/ExecutionContext$Key;
public final fun newBuilder ()Lcom/apollographql/apollo3/api/CustomScalarAdapters$Builder;
Expand All @@ -398,6 +402,7 @@ public final class com/apollographql/apollo3/api/CustomScalarAdapters$Builder {
public final fun build ()Lcom/apollographql/apollo3/api/CustomScalarAdapters;
public final fun clear ()V
public final fun deferredFragmentIdentifiers (Ljava/util/Set;)Lcom/apollographql/apollo3/api/CustomScalarAdapters$Builder;
public final fun errors (Ljava/util/List;)Lcom/apollographql/apollo3/api/CustomScalarAdapters$Builder;
public final fun falseVariables (Ljava/util/Set;)Lcom/apollographql/apollo3/api/CustomScalarAdapters$Builder;
}

Expand Down Expand Up @@ -494,6 +499,7 @@ public final class com/apollographql/apollo3/api/Error$Location {

public abstract interface class com/apollographql/apollo3/api/Executable {
public abstract fun adapter ()Lcom/apollographql/apollo3/api/Adapter;
public abstract fun getIgnoreErrors ()Z
public abstract fun rootField ()Lcom/apollographql/apollo3/api/CompiledField;
public abstract fun serializeVariables (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Z)V
}
Expand All @@ -512,7 +518,8 @@ public final class com/apollographql/apollo3/api/Executables {
public static final fun parseData (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lcom/apollographql/apollo3/api/Executable$Data;
public static final fun parseData (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/util/Set;)Lcom/apollographql/apollo3/api/Executable$Data;
public static final fun parseData (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/util/Set;Ljava/util/Set;)Lcom/apollographql/apollo3/api/Executable$Data;
public static synthetic fun parseData$default (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/util/Set;Ljava/util/Set;ILjava/lang/Object;)Lcom/apollographql/apollo3/api/Executable$Data;
public static final fun parseData (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/util/Set;Ljava/util/Set;Ljava/util/List;)Lcom/apollographql/apollo3/api/Executable$Data;
public static synthetic fun parseData$default (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/util/Set;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lcom/apollographql/apollo3/api/Executable$Data;
public static final fun variables (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lcom/apollographql/apollo3/api/Executable$Variables;
public static final fun variablesJson (Lcom/apollographql/apollo3/api/Executable;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/String;
}
Expand Down Expand Up @@ -574,6 +581,28 @@ public final class com/apollographql/apollo3/api/FakeResolverKt {
public static final fun buildData (Lcom/apollographql/apollo3/api/BuilderFactory;Lkotlin/jvm/functions/Function1;Lcom/apollographql/apollo3/api/Adapter;Ljava/util/List;Ljava/lang/String;Lcom/apollographql/apollo3/api/FakeResolver;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object;
}

public abstract interface class com/apollographql/apollo3/api/FieldResult {
}

public final class com/apollographql/apollo3/api/FieldResult$Failure : com/apollographql/apollo3/api/FieldResult {
public fun <init> (Lcom/apollographql/apollo3/exception/ApolloException;)V
public final fun getException ()Lcom/apollographql/apollo3/exception/ApolloException;
}

public final class com/apollographql/apollo3/api/FieldResult$Success : com/apollographql/apollo3/api/FieldResult {
public fun <init> (Ljava/lang/Object;)V
public final fun getValue ()Ljava/lang/Object;
}

public final class com/apollographql/apollo3/api/FieldResultKt {
public static final fun exceptionOrNull (Lcom/apollographql/apollo3/api/FieldResult;)Ljava/lang/Exception;
public static final fun getOrElse (Lcom/apollographql/apollo3/api/FieldResult;Ljava/lang/Object;)Ljava/lang/Object;
public static final fun getOrNull (Lcom/apollographql/apollo3/api/FieldResult;)Ljava/lang/Object;
public static final fun getOrThrow (Lcom/apollographql/apollo3/api/FieldResult;)Ljava/lang/Object;
public static final fun graphQLErrorOrNull (Lcom/apollographql/apollo3/api/FieldResult;)Lcom/apollographql/apollo3/api/Error;
public static final fun isSuccess (Lcom/apollographql/apollo3/api/FieldResult;)Z
}

public final class com/apollographql/apollo3/api/FileUpload {
public static final fun toUpload (Ljava/io/File;Ljava/lang/String;)Lcom/apollographql/apollo3/api/DefaultUpload;
}
Expand Down Expand Up @@ -1174,7 +1203,9 @@ public final class com/apollographql/apollo3/exception/ApolloExceptionHandlerKt
}

public final class com/apollographql/apollo3/exception/ApolloGraphQLException : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (Lcom/apollographql/apollo3/api/Error;)V
public fun <init> (Ljava/util/List;)V
public final fun getError ()Lcom/apollographql/apollo3/api/Error;
public final fun getErrors ()Ljava/util/List;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.apollographql.apollo3.api.json.MapJsonWriter
import com.apollographql.apollo3.api.json.buildJsonString
import com.apollographql.apollo3.api.json.readAny
import com.apollographql.apollo3.api.json.writeAny
import com.apollographql.apollo3.exception.ApolloException
import com.apollographql.apollo3.exception.ApolloGraphQLException
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads
Expand Down Expand Up @@ -80,7 +82,7 @@ class OptionalAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter<Optio
}

/**
* PresentAdapter can only express something that's present. Absent values are handled outside of the adapter.
* PresentAdapter can only express something that's present. Absent values are handled outside the adapter.
*
* This adapter is used to handle optional arguments in operations and optional fields in Input objects.
*/
Expand Down Expand Up @@ -118,9 +120,6 @@ class ApolloOptionalAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter
}
}

@JvmName("-obj")
fun <T> Adapter<T>.obj(buffered: Boolean = false) = ObjectAdapter(this, buffered)

@JvmField
val StringAdapter = object : Adapter<String> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): String {
Expand Down Expand Up @@ -283,12 +282,6 @@ val ApolloOptionalBooleanAdapter = ApolloOptionalAdapter(BooleanAdapter)
@JvmField
val ApolloOptionalAnyAdapter = ApolloOptionalAdapter(AnyAdapter)

@JvmName("-nullable")
fun <T : Any> Adapter<T>.nullable() = NullableAdapter(this)

@JvmName("-list")
fun <T> Adapter<T>.list() = ListAdapter(this)

/**
* Note that Arrays require their type to be known at compile time, so we construct an anonymous object with reference to
* function with reified type parameters as a workaround.
Expand All @@ -297,7 +290,11 @@ fun <T> Adapter<T>.list() = ListAdapter(this)
@JvmName("-array")
inline fun <reified T> Adapter<T>.array() = object : Adapter<Array<T>> {

private inline fun <reified T> arrayFromJson(wrappedAdapter: Adapter<T>, reader: JsonReader, customScalarAdapters: CustomScalarAdapters): Array<T> {
private inline fun <reified T> arrayFromJson(
wrappedAdapter: Adapter<T>,
reader: JsonReader,
customScalarAdapters: CustomScalarAdapters,
): Array<T> {
reader.beginArray()
val list = mutableListOf<T>()
while (reader.hasNext()) {
Expand All @@ -311,7 +308,7 @@ inline fun <reified T> Adapter<T>.array() = object : Adapter<Array<T>> {
wrappedAdapter: Adapter<T>,
writer: JsonWriter,
customScalarAdapters: CustomScalarAdapters,
value: Array<T>
value: Array<T>,
) {
writer.beginArray()
value.forEach {
Expand Down Expand Up @@ -363,14 +360,14 @@ class ObjectAdapter<T>(
}
}

override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: T, ) {
override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: T) {
if (buffered && writer !is MapJsonWriter) {
/**
* Convert to a Map first
*/
val mapWriter = MapJsonWriter()
mapWriter.beginObject()
wrappedAdapter.toJson(mapWriter, customScalarAdapters, value, )
wrappedAdapter.toJson(mapWriter, customScalarAdapters, value)
mapWriter.endObject()

/**
Expand All @@ -379,8 +376,80 @@ class ObjectAdapter<T>(
writer.writeAny(mapWriter.root()!!)
} else {
writer.beginObject()
wrappedAdapter.toJson(writer, customScalarAdapters, value,)
wrappedAdapter.toJson(writer, customScalarAdapters, value)
writer.endObject()
}
}
}
}

private class ErrorAwareAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter<T> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): T {
if (reader.peek() == JsonReader.Token.NULL) {
val error = customScalarAdapters.firstErrorStartingWith(reader.getPath())
if (error != null) {
reader.skipValue()
throw ApolloGraphQLException(error)
}
}

return wrappedAdapter.fromJson(reader, customScalarAdapters)
}

override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: T) {
wrappedAdapter.toJson(writer, customScalarAdapters, value)
}
}

private class CatchToResultAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter<FieldResult<T>> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): FieldResult<T> {
return try {
FieldResult.Success(wrappedAdapter.fromJson(reader, customScalarAdapters))
} catch (e: ApolloException) {
FieldResult.Failure(e)
}
}

override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: FieldResult<T>) {
when (value) {
is FieldResult.Success -> wrappedAdapter.toJson(writer, customScalarAdapters, value.getOrThrow())
else -> Unit // ignore errors
}
}
}

private class CatchToNullAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter<@JvmSuppressWildcards T?> {
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): T? {
return try {
wrappedAdapter.fromJson(reader, customScalarAdapters)
} catch (e: ApolloException) {
null
}
}

override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: T?) {
if (value == null) {
// XXX: this potentially writes null instead of an error
writer.nullValue()
} else {
wrappedAdapter.toJson(writer, customScalarAdapters, value)
}
}
}

@JvmName("-nullable")
fun <T : Any> Adapter<T>.nullable() = NullableAdapter(this)

@JvmName("-list")
fun <T> Adapter<T>.list() = ListAdapter(this)

@JvmName("-obj")
fun <T> Adapter<T>.obj(buffered: Boolean = false) = ObjectAdapter(this, buffered)

@JvmName("-catchToResult")
fun <T> Adapter<T>.catchToResult(): Adapter<FieldResult<T>> = CatchToResultAdapter(this)

@JvmName("-errorAware")
fun <T> Adapter<T>.errorAware(): Adapter<T> = ErrorAwareAdapter(this)

@JvmName("-catchToNull")
fun <T> Adapter<T>.catchToNull(): Adapter<T?> = CatchToNullAdapter(this)
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import kotlin.jvm.JvmName
*/
fun checkFieldNotMissing(value: Any?, name: String) {
if (value == null) {
throw DefaultApolloException("Field '$name' is missing")
throw DefaultApolloException("Field '$name' is missing or null")
}
}

Expand All @@ -35,5 +35,5 @@ fun assertOneOf(vararg args: Optional<*>) {
* Helper function for the Kotlin codegen
*/
fun missingField(jsonReader: JsonReader, name: String): Nothing {
throw DefaultApolloException("Field '$name' is missing at path ${jsonReader.getPath()}")
throw DefaultApolloException("Field '$name' is missing or null at path ${jsonReader.getPath()}")
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class CustomScalarAdapters private constructor(
*/
@JvmField
val deferredFragmentIdentifiers: Set<DeferredFragmentIdentifier>?,
/**
* Errors to use with @catch
*/
@JvmField
val errors: List<Error>?,

private val unsafe: Boolean,
) : ExecutionContext.Element {

Expand Down Expand Up @@ -97,6 +103,26 @@ class CustomScalarAdapters private constructor(
val PassThrough = Builder().unsafe(true).build()
}

@ApolloExperimental
fun firstErrorStartingWith(path: List<Any>): Error? {
return errors?.firstOrNull {
it.path?.startsWith(path) == true
}
}

private fun List<Any>.startsWith(responsePath: List<Any>): Boolean {
// start at 1 to drop the `data.`
for (i in 1.until(responsePath.size)) {
if (i - 1 >= this.size) {
return false
}
if (responsePath[i] != this[i - 1]) {
return false
}
}
return true
}

fun newBuilder(): Builder {
return Builder().addAll(this)
.falseVariables(falseVariables)
Expand All @@ -108,6 +134,7 @@ class CustomScalarAdapters private constructor(
private var unsafe = false
private var falseVariables: Set<String>? = null
private var deferredFragmentIdentifiers: Set<DeferredFragmentIdentifier>? = null
private var errors: List<Error>? = null

fun falseVariables(falseVariables: Set<String>?) = apply {
this.falseVariables = falseVariables
Expand All @@ -117,6 +144,10 @@ class CustomScalarAdapters private constructor(
this.deferredFragmentIdentifiers = deferredFragmentIdentifiers
}

fun errors(errors: List<Error>?) = apply {
this.errors = errors
}

fun <T> add(
name: String,
adapter: Adapter<T>,
Expand Down Expand Up @@ -148,8 +179,9 @@ class CustomScalarAdapters private constructor(
fun build(): CustomScalarAdapters {
return CustomScalarAdapters(
adaptersMap,
falseVariables ,
falseVariables,
deferredFragmentIdentifiers,
errors,
unsafe,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ interface Executable<D: Executable.Data> {
*/
fun rootField(): CompiledField

/**
* A flag to disable error checking for the whole operation.
* Used for backward compatibility.
*/
val ignoreErrors: Boolean

/**
* Marker interface for generated models
*/
Expand Down
Loading
Loading