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 4 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
13 changes: 5 additions & 8 deletions apollo-normalized-cache/api/apollo-normalized-cache.api
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,20 @@ public final class com/apollographql/apollo3/cache/normalized/ClientCacheExtensi
public static final fun cacheHeaders (Lcom/apollographql/apollo3/api/HasMutableExecutionContext;Lcom/apollographql/apollo3/cache/CacheHeaders;)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public static final fun clearNormalizedCache (Lcom/apollographql/apollo3/ApolloClient;)Z
public static final fun doNotStore (Lcom/apollographql/apollo3/api/HasMutableExecutionContext;Z)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public static final fun fetchPolicy (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static final fun fetchPolicy (Lcom/apollographql/apollo3/api/ApolloRequest$Builder;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/api/ApolloRequest$Builder;
public static final fun executeCacheAndNetwork (Lcom/apollographql/apollo3/ApolloQueryCall;)Lkotlinx/coroutines/flow/Flow;
public static final fun fetchPolicy (Lcom/apollographql/apollo3/api/HasMutableExecutionContext;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public static final fun getApolloStore (Lcom/apollographql/apollo3/ApolloClient;)Lcom/apollographql/apollo3/cache/normalized/ApolloStore;
public static final fun getCacheInfo (Lcom/apollographql/apollo3/api/ApolloResponse;)Lcom/apollographql/apollo3/cache/normalized/CacheInfo;
public static final fun isFromCache (Lcom/apollographql/apollo3/api/ApolloResponse;)Z
public static final fun normalizedCache (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/NormalizedCacheFactory;Lcom/apollographql/apollo3/cache/normalized/ObjectIdGenerator;Lcom/apollographql/apollo3/cache/normalized/CacheResolver;Z)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static synthetic fun normalizedCache$default (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/NormalizedCacheFactory;Lcom/apollographql/apollo3/cache/normalized/ObjectIdGenerator;Lcom/apollographql/apollo3/cache/normalized/CacheResolver;ZILjava/lang/Object;)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static final fun optimisticUpdates (Lcom/apollographql/apollo3/ApolloMutationCall;Lcom/apollographql/apollo3/api/Mutation$Data;)Lcom/apollographql/apollo3/ApolloMutationCall;
public static final fun optimisticUpdates (Lcom/apollographql/apollo3/api/ApolloRequest$Builder;Lcom/apollographql/apollo3/api/Mutation$Data;)Lcom/apollographql/apollo3/api/ApolloRequest$Builder;
public static final fun queryCacheAndNetwork (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public static final fun queryCacheAndNetwork (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Query;)Lkotlinx/coroutines/flow/Flow;
public static final fun refetchPolicy (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static final fun refetchPolicy (Lcom/apollographql/apollo3/api/ApolloRequest$Builder;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/api/ApolloRequest$Builder;
public static final fun refetchPolicy (Lcom/apollographql/apollo3/api/HasMutableExecutionContext;Lcom/apollographql/apollo3/cache/normalized/FetchPolicy;)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public static final fun store (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/ApolloStore;Z)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static synthetic fun store$default (Lcom/apollographql/apollo3/ApolloClient$Builder;Lcom/apollographql/apollo3/cache/normalized/ApolloStore;ZILjava/lang/Object;)Lcom/apollographql/apollo3/ApolloClient$Builder;
public static final fun storePartialResponses (Lcom/apollographql/apollo3/api/HasMutableExecutionContext;Z)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public static final fun watch (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public static final fun watch (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Query;)Lkotlinx/coroutines/flow/Flow;
public static final fun watch (Lcom/apollographql/apollo3/ApolloQueryCall;)Lkotlinx/coroutines/flow/Flow;
public static final fun withCacheHeaders (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/cache/CacheHeaders;)Lcom/apollographql/apollo3/ApolloClient;
public static final fun withCacheHeaders (Lcom/apollographql/apollo3/api/ApolloRequest;Lcom/apollographql/apollo3/cache/CacheHeaders;)Lcom/apollographql/apollo3/api/ApolloRequest;
public static final fun withDoNotStore (Lcom/apollographql/apollo3/ApolloClient;Z)Lcom/apollographql/apollo3/ApolloClient;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.apollographql.apollo3.cache.normalized

import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.ApolloMutationCall
import com.apollographql.apollo3.ApolloQueryCall
import com.apollographql.apollo3.api.ApolloRequest
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.ExecutionContext
Expand Down Expand Up @@ -64,16 +66,9 @@ fun ApolloClient.Builder.store(store: ApolloStore, writeToCacheAsynchronously: B
return addInterceptor(ApolloCacheInterceptor(store)).writeToCacheAsynchronously(writeToCacheAsynchronously)
}

fun <D : Query.Data> ApolloClient.watch(query: Query<D>): Flow<ApolloResponse<D>> {
return watch(ApolloRequest.Builder(query).build())
}

fun <D : Query.Data> ApolloClient.watch(queryRequest: ApolloRequest<D>): Flow<ApolloResponse<D>> {
return queryAsFlow(queryRequest.newBuilder().addExecutionContext(WatchContext(true)).build())
}

fun <D : Query.Data> ApolloClient.queryCacheAndNetwork(query: Query<D>): Flow<ApolloResponse<D>> {
return queryCacheAndNetwork(ApolloRequest.Builder(query).build())
fun <D : Query.Data> ApolloQueryCall<D>.watch(): Flow<ApolloResponse<D>> {
return copy().addExecutionContext(WatchContext(true)).executeAsFlow()
}


Expand All @@ -83,18 +78,18 @@ fun <D : Query.Data> ApolloClient.queryCacheAndNetwork(query: Query<D>): Flow<Ap
*
* Any [FetchPolicy] on [queryRequest] will be ignored
*/
fun <D : Query.Data> ApolloClient.queryCacheAndNetwork(queryRequest: ApolloRequest<D>): Flow<ApolloResponse<D>> {
fun <D : Query.Data> ApolloQueryCall<D>.executeCacheAndNetwork(): Flow<ApolloResponse<D>> {
return flow {
var cacheException: ApolloException? = null
var networkException: ApolloException? = null
try {
emit(query(queryRequest.newBuilder().fetchPolicy(FetchPolicy.CacheOnly).build()))
emit(copy().fetchPolicy(FetchPolicy.CacheOnly).execute())
} catch (e: ApolloException) {
cacheException = e
}

try {
emit(query(queryRequest.newBuilder().fetchPolicy(FetchPolicy.NetworkOnly).build()))
emit(copy().fetchPolicy(FetchPolicy.NetworkOnly).execute())
} catch (e: ApolloException) {
networkException = e
}
Expand Down Expand Up @@ -122,48 +117,33 @@ val ApolloClient.apolloStore: ApolloStore
fun ApolloClient.clearNormalizedCache() = apolloStore.clearAll()

/**
* Sets the [FetchPolicy] on this request. D has a bound on [Query.Data] because subscriptions and mutation shouldn't
* read the cache
*/
fun <D : Query.Data> ApolloRequest.Builder<D>.fetchPolicy(fetchPolicy: FetchPolicy) = addExecutionContext(
FetchPolicyContext(fetchPolicy)
)

/**
* Sets the default [FetchPolicy] for the [ApolloClient]. This only affects queries. Mutations and subscriptions will
* always use [FetchPolicy.NetworkFirst]
* Sets the initial [FetchPolicy]
* This only has effects for queries. Mutations and subscriptions always use [FetchPolicy.NetworkOnly]
*/
fun ApolloClient.Builder.fetchPolicy(fetchPolicy: FetchPolicy) = addExecutionContext(
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.fetchPolicy(fetchPolicy: FetchPolicy) = addExecutionContext(
FetchPolicyContext(fetchPolicy)
)

/**
* Sets the [FetchPolicy] used when refetching at the request level. This is only used in combination with [watch].
* Sets the [FetchPolicy] used when watching queries and a cache change has been published
*/
fun <D : Query.Data> ApolloRequest.Builder<D>.refetchPolicy(refetchPolicy: FetchPolicy) = addExecutionContext(
RefetchPolicyContext(refetchPolicy)
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.refetchPolicy(fetchPolicy: FetchPolicy) = addExecutionContext(
RefetchPolicyContext(fetchPolicy)
)

/**
* Sets the [FetchPolicy] used when refetching at the client level. This is only used in combination with [watch].
*/
fun ApolloClient.Builder.refetchPolicy(refetchPolicy: FetchPolicy) = addExecutionContext(
RefetchPolicyContext(refetchPolicy)
)

fun <T> HasMutableExecutionContext<T>.doNotStore(doNotStore: Boolean) where T : HasMutableExecutionContext<T> = addExecutionContext(
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.doNotStore(doNotStore: Boolean) = addExecutionContext(
DoNotStoreContext(doNotStore)
)

fun <T> HasMutableExecutionContext<T>.storePartialResponses(storePartialResponses: Boolean) where T : HasMutableExecutionContext<T> = addExecutionContext(
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.storePartialResponses(storePartialResponses: Boolean) = addExecutionContext(
StorePartialResponsesContext(storePartialResponses)
)

fun <T> HasMutableExecutionContext<T>.cacheHeaders(cacheHeaders: CacheHeaders) where T : HasMutableExecutionContext<T> = addExecutionContext(
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.cacheHeaders(cacheHeaders: CacheHeaders) = addExecutionContext(
CacheHeadersContext(cacheHeaders)
)

fun <T> HasMutableExecutionContext<T>.writeToCacheAsynchronously(writeToCacheAsynchronously: Boolean) where T : HasMutableExecutionContext<T> = addExecutionContext(
fun <T : HasMutableExecutionContext<T>> HasMutableExecutionContext<T>.writeToCacheAsynchronously(writeToCacheAsynchronously: Boolean) = addExecutionContext(
WriteToCacheAsynchronouslyContext(writeToCacheAsynchronously)
)

Expand All @@ -173,6 +153,9 @@ fun <T> HasMutableExecutionContext<T>.writeToCacheAsynchronously(writeToCacheAsy
fun <D : Mutation.Data> ApolloRequest.Builder<D>.optimisticUpdates(data: D) = addExecutionContext(
OptimisticUpdatesContext(data)
)
fun <D : Mutation.Data> ApolloMutationCall<D>.optimisticUpdates(data: D) = addExecutionContext(
OptimisticUpdatesContext(data)
)

internal val <D : Query.Data> ApolloRequest<D>.fetchPolicy
get() = executionContext[FetchPolicyContext]?.value ?: FetchPolicy.CacheFirst
Expand Down
40 changes: 32 additions & 8 deletions apollo-runtime/api/apollo-runtime.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
public abstract class com/apollographql/apollo3/ApolloCall : com/apollographql/apollo3/api/HasMutableExecutionContext {
public fun <init> (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Operation;)V
public fun addExecutionContext (Lcom/apollographql/apollo3/api/ExecutionContext;)Lcom/apollographql/apollo3/api/HasMutableExecutionContext;
public final fun executeAsFlow ()Lkotlinx/coroutines/flow/Flow;
public final fun getApolloClient ()Lcom/apollographql/apollo3/ApolloClient;
public fun getExecutionContext ()Lcom/apollographql/apollo3/api/ExecutionContext;
public final fun getOperation ()Lcom/apollographql/apollo3/api/Operation;
public fun setExecutionContext (Lcom/apollographql/apollo3/api/ExecutionContext;)V
}

public final class com/apollographql/apollo3/ApolloClient : com/apollographql/apollo3/api/HasExecutionContext {
public static final field Companion Lcom/apollographql/apollo3/ApolloClient$Companion;
public fun <init> (Lcom/apollographql/apollo3/network/NetworkTransport;)V
Expand All @@ -10,17 +20,13 @@ public final class com/apollographql/apollo3/ApolloClient : com/apollographql/ap
public synthetic fun <init> (Lcom/apollographql/apollo3/network/NetworkTransport;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lcom/apollographql/apollo3/network/NetworkTransport;Ljava/util/List;Lcom/apollographql/apollo3/api/ExecutionContext;Lkotlinx/coroutines/CoroutineDispatcher;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;)V
public final fun dispose ()V
public final fun executeAsFlow (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public fun getExecutionContext ()Lcom/apollographql/apollo3/api/ExecutionContext;
public final fun getInterceptors ()Ljava/util/List;
public final fun mutate (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun mutate (Lcom/apollographql/apollo3/api/Mutation;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun mutateAsFlow (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public final fun mutate (Lcom/apollographql/apollo3/api/Mutation;)Lcom/apollographql/apollo3/ApolloMutationCall;
public final fun newBuilder ()Lcom/apollographql/apollo3/ApolloClient$Builder;
public final fun query (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun query (Lcom/apollographql/apollo3/api/Query;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun queryAsFlow (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public final fun subscribe (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public final fun subscribe (Lcom/apollographql/apollo3/api/Subscription;)Lkotlinx/coroutines/flow/Flow;
public final fun query (Lcom/apollographql/apollo3/api/Query;)Lcom/apollographql/apollo3/ApolloQueryCall;
public final fun subscribe (Lcom/apollographql/apollo3/api/Subscription;)Lcom/apollographql/apollo3/ApolloSubscriptionCall;
public final fun withCustomScalarAdapter (Lcom/apollographql/apollo3/api/CustomScalarType;Lcom/apollographql/apollo3/api/Adapter;)Lcom/apollographql/apollo3/ApolloClient;
public final fun withExecutionContext (Lcom/apollographql/apollo3/api/ExecutionContext;)Lcom/apollographql/apollo3/ApolloClient;
public final fun withFlowDecorator (Lkotlin/jvm/functions/Function1;)Lcom/apollographql/apollo3/ApolloClient;
Expand Down Expand Up @@ -61,6 +67,24 @@ public final class com/apollographql/apollo3/ApolloClientKt {
public static final fun withSendDocument (Lcom/apollographql/apollo3/ApolloClient;Z)Lcom/apollographql/apollo3/ApolloClient;
}

public final class com/apollographql/apollo3/ApolloMutationCall : com/apollographql/apollo3/ApolloCall {
public fun <init> (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Mutation;)V
public final fun copy ()Lcom/apollographql/apollo3/ApolloMutationCall;
public final fun execute (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class com/apollographql/apollo3/ApolloQueryCall : com/apollographql/apollo3/ApolloCall {
public fun <init> (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Query;)V
public final fun copy ()Lcom/apollographql/apollo3/ApolloQueryCall;
public final fun execute (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class com/apollographql/apollo3/ApolloSubscriptionCall : com/apollographql/apollo3/ApolloCall {
public fun <init> (Lcom/apollographql/apollo3/ApolloClient;Lcom/apollographql/apollo3/api/Subscription;)V
public final fun copy ()Lcom/apollographql/apollo3/ApolloSubscriptionCall;
public final fun execute ()Lkotlinx/coroutines/flow/Flow;
}

public final class com/apollographql/apollo3/AutoPersistedQueryInfo : com/apollographql/apollo3/api/ExecutionContext$Element {
public static final field Key Lcom/apollographql/apollo3/AutoPersistedQueryInfo$Key;
public fun <init> (Z)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.apollographql.apollo3

import com.apollographql.apollo3.api.ApolloRequest
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.ExecutionContext
import com.apollographql.apollo3.api.HasMutableExecutionContext
import com.apollographql.apollo3.api.Mutation
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.api.Query
import com.apollographql.apollo3.api.Subscription
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.single


abstract class ApolloCall<D: Operation.Data, E: HasMutableExecutionContext<E>>
(val apolloClient: ApolloClient, val operation: Operation<D>): HasMutableExecutionContext<E> {
override var executionContext: ExecutionContext = ExecutionContext.Empty

override fun addExecutionContext(executionContext: ExecutionContext): E {
this.executionContext += executionContext
return this as E
}

fun executeAsFlow(): Flow<ApolloResponse<D>> {
val request = ApolloRequest.Builder(operation)
.addExecutionContext(executionContext)
.build()
return apolloClient.executeAsFlow(request)
}
}

/**
* [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) {
/**
* 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) {
/**
* 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) {
/**
* 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)
}
}
Loading