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

Fluent query API #3447

Merged
merged 6 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,87 @@ abstract class ApolloCall<D: Operation.Data, E: HasMutableExecutionContext<E>>
}
}

/**
* [ApolloQueryCall] contains everything needed to execute an [ApolloRequest] with the given [ApolloClient]
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
*
* [ApolloQueryCall] is mutable. You can customize it before calling [execute]
*/
class ApolloQueryCall<D: Query.Data>(apolloClient: ApolloClient, query: Query<D>)
: ApolloCall<D, ApolloQueryCall<D>>(apolloClient, query) {
fun copy(): ApolloQueryCall<D> {
return ApolloQueryCall(apolloClient, operation as Query<D>).addExecutionContext(executionContext)
}
/**
* Executes the [ApolloQueryCall]
* [ApolloQueryCall] can be executed several times
*
* Example:
* ```
* val response = apolloClient.query(HeroQuery())
* .httpHeader("Authorization", myToken)
* .fetchPolicy(FetchPolicy.NetworkOnly)
* .execute()
* ```
*/
suspend fun execute(): ApolloResponse<D> {
return executeAsFlow().single()
}

fun copy(): ApolloQueryCall<D> {
return ApolloQueryCall(apolloClient, operation as Query<D>).addExecutionContext(executionContext)
}
}

/**
* [ApolloMutationCall] contains everything needed to execute an [ApolloRequest] with the given [ApolloClient]
*
* [ApolloMutationCall] is mutable. You can customize it before calling [execute]
*/
class ApolloMutationCall<D: Mutation.Data>(apolloClient: ApolloClient, mutation: Mutation<D>)
: ApolloCall<D, ApolloMutationCall<D>>(apolloClient, mutation) {
fun copy(): ApolloMutationCall<D> {
return ApolloMutationCall(apolloClient, operation as Mutation<D>).addExecutionContext(executionContext)
}
/**
* Executes the [ApolloMutationCall]
* [ApolloMutationCall] can be executed several times
*
* Example:
* ```
* val response = apolloClient.mutate(SetHeroName("Luke"))
* .httpHeader("Authorization", myToken)
* .optimisticData(data)
* .execute()
* ```
*/
suspend fun execute(): ApolloResponse<D> {
return executeAsFlow().single()
}

fun copy(): ApolloMutationCall<D> {
return ApolloMutationCall(apolloClient, operation as Mutation<D>).addExecutionContext(executionContext)
}
}

/**
* [ApolloSubscriptionCall] contains everything needed to execute an [ApolloRequest] with the given [ApolloClient]
*
* [ApolloSubscriptionCall] is mutable. You can customize it before calling [execute]
*/
class ApolloSubscriptionCall<D: Subscription.Data>(apolloClient: ApolloClient, subscription: Subscription<D>)
: ApolloCall<D, ApolloSubscriptionCall<D>>(apolloClient, subscription) {
fun copy(): ApolloSubscriptionCall<D> {
return ApolloSubscriptionCall(apolloClient, operation as Subscription<D>).addExecutionContext(executionContext)
}
/**
* Executes the [ApolloSubscriptionCall]
* [ApolloSubscriptionCall] can be executed several times
*
* Example:
* ```
* apolloClient.subscribe(NewOrders())
* .execute()
* .collect {
* println("order received: ${it.data?.order?.id"})
* }
* ```
*/
fun execute(): Flow<ApolloResponse<D>> {
return executeAsFlow()
}

fun copy(): ApolloSubscriptionCall<D> {
return ApolloSubscriptionCall(apolloClient, operation as Subscription<D>).addExecutionContext(executionContext)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,21 @@ class ApolloClient @JvmOverloads @Deprecated("Please use ApolloClient.Builder in
)

/**
* Executes the given query and returns a response or throws on transport errors
* use [query] ([ApolloRequest]) to customize the request
* Creates a new [ApolloQueryCall] that you can customize and/or execute.
*/
fun <D : Query.Data> query(query: Query<D>): ApolloQueryCall<D> {
return ApolloQueryCall(this, query)
}

/**
* Executes the given mutation and returns a response or throws on transport errors
* use [mutation] ([ApolloRequest]) to customize the request
* Creates a new [ApolloMutationCall] that you can customize and/or execute.
*/
fun <D : Mutation.Data> mutate(mutation: Mutation<D>): ApolloMutationCall<D> {
return ApolloMutationCall(this, mutation)
}

/**
* Subscribes to the given subscription. The subscription is cancelled when the coroutine collecting the flow is canceled
* Creates a new [ApolloSubscriptionCall] that you can customize and/or execute.
*/
fun <D : Subscription.Data> subscribe(subscription: Subscription<D>): ApolloSubscriptionCall<D> {
return ApolloSubscriptionCall(this, subscription)
Expand Down Expand Up @@ -144,6 +142,17 @@ class ApolloClient @JvmOverloads @Deprecated("Please use ApolloClient.Builder in
)
}

/**
* Low lebel API to execute the given [apolloRequest] and return a [Flow].
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
*
* Prefer [query], [mutate] or [subscribe] when possible.
*
* For simple queries, the returned [Flow] will contain only one element.
* For more advanced use cases like watchers or subscriptions, it may contain any number of elements and never
* finish. You can cancel the corresponding coroutine to terminate the [Flow] in this case.
*
*
*/
@OptIn(ExperimentalCoroutinesApi::class, kotlinx.coroutines.FlowPreview::class)
fun <D : Operation.Data> executeAsFlow(apolloRequest: ApolloRequest<D>): Flow<ApolloResponse<D>> {
assertMainThreadOnNative()
Expand Down