-
Notifications
You must be signed in to change notification settings - Fork 655
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
feat: add Mutiny support #3198
Merged
Merged
feat: add Mutiny support #3198
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Signature format: 4.0 | ||
package com.apollographql.apollo.mutiny { | ||
|
||
public final class KotlinExtensions { | ||
} | ||
|
||
public class MutinyApollo { | ||
method public static <T> io.smallrye.mutiny.Uni<com.apollographql.apollo.api.Response<T!>!> from(com.apollographql.apollo.ApolloQueryWatcher<T!>); | ||
method public static <T> io.smallrye.mutiny.Uni<com.apollographql.apollo.api.Response<T!>!> from(com.apollographql.apollo.ApolloCall<T!>); | ||
method public static io.smallrye.mutiny.Uni<java.lang.Void!> from(com.apollographql.apollo.ApolloPrefetch); | ||
method public static <T> io.smallrye.mutiny.Multi<com.apollographql.apollo.api.Response<T!>!> from(com.apollographql.apollo.ApolloSubscriptionCall<T!>); | ||
method public static <T> io.smallrye.mutiny.Multi<com.apollographql.apollo.api.Response<T!>!> from(com.apollographql.apollo.ApolloSubscriptionCall<T!>, io.smallrye.mutiny.subscription.BackPressureStrategy); | ||
method public static <T> io.smallrye.mutiny.Uni<T!> from(com.apollographql.apollo.cache.normalized.ApolloStoreOperation<T!>); | ||
} | ||
|
||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
plugins { | ||
`java-library` | ||
kotlin("jvm") | ||
} | ||
|
||
dependencies { | ||
add("implementation", project(":apollo-api")) | ||
add("api", groovy.util.Eval.x(project, "x.dep.mutiny")) | ||
add("api", project(":apollo-runtime")) | ||
} | ||
|
||
tasks.withType<Javadoc> { | ||
options.encoding = "UTF-8" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
POM_ARTIFACT_ID=apollo-mutiny-support | ||
POM_NAME=Apollo GraphQL Mutiny Support | ||
POM_DESCRIPTION=Apollo GraphQL Mutiny bindings | ||
POM_PACKAGING=jar |
181 changes: 181 additions & 0 deletions
181
apollo-mutiny-support/src/main/java/com/apollographql/apollo/mutiny/MutinyApollo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
package com.apollographql.apollo.mutiny; | ||
|
||
import com.apollographql.apollo.ApolloCall; | ||
import com.apollographql.apollo.ApolloPrefetch; | ||
import com.apollographql.apollo.ApolloQueryWatcher; | ||
import com.apollographql.apollo.ApolloSubscriptionCall; | ||
import com.apollographql.apollo.api.Response; | ||
import com.apollographql.apollo.cache.normalized.ApolloStoreOperation; | ||
import com.apollographql.apollo.exception.ApolloException; | ||
import com.apollographql.apollo.internal.subscription.ApolloSubscriptionTerminatedException; | ||
import io.smallrye.mutiny.Multi; | ||
import io.smallrye.mutiny.Uni; | ||
import io.smallrye.mutiny.subscription.BackPressureStrategy; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import static com.apollographql.apollo.api.internal.Utils.checkNotNull; | ||
|
||
/** | ||
* The MutinyApollo class provides methods for converting ApolloCall, ApolloPrefetch and ApolloWatcher types to Mutiny sources. | ||
*/ | ||
public class MutinyApollo { | ||
|
||
private MutinyApollo() { | ||
throw new AssertionError("This class cannot be instantiated"); | ||
} | ||
|
||
/** | ||
* Converts an {@link ApolloQueryWatcher} to an asynchronous Uni. | ||
* | ||
* @param watcher the ApolloQueryWatcher to convert. | ||
* @param <T> the value type | ||
* @return the converted Uni | ||
* @throws NullPointerException if watcher == null | ||
*/ | ||
@NotNull | ||
public static <T> Uni<Response<T>> from(@NotNull final ApolloQueryWatcher<T> watcher) { | ||
checkNotNull(watcher, "watcher == null"); | ||
return Uni.createFrom().emitter(emitter -> { | ||
ApolloQueryWatcher<T> clone = watcher.clone(); | ||
emitter.onTermination(clone::cancel); | ||
clone.enqueueAndWatch(new ApolloCall.Callback<T>() { | ||
@Override public void onResponse(@NotNull Response<T> response) { | ||
emitter.complete(response); | ||
} | ||
|
||
@Override public void onFailure(@NotNull ApolloException e) { | ||
emitter.fail(e); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Converts an {@link ApolloCall} to an {@link Uni}. The number of emissions this Uni will have is based on the {@link | ||
* com.apollographql.apollo.fetcher.ResponseFetcher} used with the call. | ||
* | ||
* @param call the ApolloCall to convert | ||
* @param <T> the value type. | ||
* @return the converted Uni | ||
* @throws NullPointerException if originalCall == null | ||
*/ | ||
@NotNull | ||
public static <T> Uni<Response<T>> from(@NotNull final ApolloCall<T> call) { | ||
checkNotNull(call, "call == null"); | ||
return Uni.createFrom().emitter(emitter -> { | ||
ApolloCall<T> clone = call.toBuilder().build(); | ||
emitter.onTermination(clone::cancel); | ||
clone.enqueue(new ApolloCall.Callback<T>() { | ||
@Override public void onResponse(@NotNull Response<T> response) { | ||
emitter.complete(response); | ||
} | ||
|
||
@Override public void onFailure(@NotNull ApolloException e) { | ||
emitter.fail(e); | ||
} | ||
|
||
@Override public void onStatusEvent(@NotNull ApolloCall.StatusEvent event) { | ||
if (event == ApolloCall.StatusEvent.COMPLETED) { | ||
emitter.complete(null); | ||
} | ||
} | ||
} | ||
); | ||
} | ||
); | ||
} | ||
|
||
/** | ||
* Converts an {@link ApolloPrefetch} to a synchronous Uni<Void> | ||
* | ||
* @param prefetch the ApolloPrefetch to convert | ||
* @return the converted Uni<Void> | ||
* @throws NullPointerException if prefetch == null | ||
*/ | ||
@NotNull | ||
public static Uni<Void> from(@NotNull final ApolloPrefetch prefetch) { | ||
checkNotNull(prefetch, "prefetch == null"); | ||
return Uni.createFrom().emitter(emitter -> { | ||
ApolloPrefetch clone = prefetch.clone(); | ||
emitter.onTermination(clone::cancel); | ||
clone.enqueue(new ApolloPrefetch.Callback() { | ||
@Override public void onSuccess() { | ||
emitter.complete(null); | ||
} | ||
|
||
@Override public void onFailure(@NotNull ApolloException e) { | ||
emitter.fail(e); | ||
} | ||
} | ||
); | ||
}); | ||
} | ||
|
||
@NotNull | ||
public static <T> Multi<Response<T>> from(@NotNull ApolloSubscriptionCall<T> call) { | ||
return from(call, BackPressureStrategy.LATEST); | ||
} | ||
|
||
@NotNull | ||
public static <T> Multi<Response<T>> from(@NotNull final ApolloSubscriptionCall<T> call, | ||
@NotNull BackPressureStrategy backpressureStrategy) { | ||
checkNotNull(call, "originalCall == null"); | ||
checkNotNull(backpressureStrategy, "backpressureStrategy == null"); | ||
return Multi.createFrom().emitter(emitter -> { | ||
ApolloSubscriptionCall<T> clone = call.clone(); | ||
emitter.onTermination(clone::cancel); | ||
clone.execute( | ||
new ApolloSubscriptionCall.Callback<T>() { | ||
@Override public void onResponse(@NotNull Response<T> response) { | ||
if (!emitter.isCancelled()) { | ||
emitter.emit(response); | ||
} | ||
} | ||
|
||
@Override public void onFailure(@NotNull ApolloException e) { | ||
if (!emitter.isCancelled()) { | ||
emitter.fail(e); | ||
} | ||
} | ||
|
||
@Override public void onCompleted() { | ||
if (!emitter.isCancelled()) { | ||
emitter.complete(); | ||
} | ||
} | ||
|
||
@Override public void onTerminated() { | ||
onFailure(new ApolloSubscriptionTerminatedException("Subscription server unexpectedly terminated connection")); | ||
} | ||
|
||
@Override public void onConnected() { | ||
//Do nothing when GraphQL subscription server connection is opened | ||
} | ||
} | ||
); | ||
}, backpressureStrategy); | ||
} | ||
|
||
/** | ||
* Converts an {@link ApolloStoreOperation} to a Uni. | ||
* | ||
* @param operation the ApolloStoreOperation to convert | ||
* @param <T> the value type | ||
* @return the converted Uni | ||
*/ | ||
@NotNull | ||
public static <T> Uni<T> from(@NotNull final ApolloStoreOperation<T> operation) { | ||
checkNotNull(operation, "operation == null"); | ||
return Uni.createFrom().emitter(emitter -> operation.enqueue(new ApolloStoreOperation.Callback<T>() { | ||
@Override | ||
public void onSuccess(T result) { | ||
emitter.complete(result); | ||
} | ||
|
||
@Override | ||
public void onFailure(@NotNull Throwable t) { | ||
emitter.fail(t); | ||
} | ||
})); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
apollo-mutiny-support/src/main/java/com/apollographql/apollo/mutiny/MutinyExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
@file:Suppress("NOTHING_TO_INLINE") | ||
@file:JvmName("KotlinExtensions") | ||
|
||
package com.apollographql.apollo.mutiny | ||
|
||
import com.apollographql.apollo.ApolloCall | ||
import com.apollographql.apollo.ApolloClient | ||
import com.apollographql.apollo.ApolloMutationCall | ||
import com.apollographql.apollo.ApolloPrefetch | ||
import com.apollographql.apollo.ApolloQueryCall | ||
import com.apollographql.apollo.ApolloQueryWatcher | ||
import com.apollographql.apollo.ApolloSubscriptionCall | ||
import com.apollographql.apollo.api.Mutation | ||
import com.apollographql.apollo.api.Operation | ||
import com.apollographql.apollo.api.Query | ||
import com.apollographql.apollo.api.Response | ||
import com.apollographql.apollo.api.Subscription | ||
import com.apollographql.apollo.cache.normalized.ApolloStoreOperation | ||
|
||
import io.smallrye.mutiny.Multi | ||
import io.smallrye.mutiny.Uni | ||
import io.smallrye.mutiny.subscription.BackPressureStrategy | ||
|
||
@JvmSynthetic | ||
inline fun ApolloPrefetch.mutiny(): Uni<Void> = | ||
MutinyApollo.from(this) | ||
|
||
@JvmSynthetic | ||
inline fun <T> ApolloStoreOperation<T>.mutiny(): Uni<T> = | ||
MutinyApollo.from(this) | ||
|
||
@JvmSynthetic | ||
inline fun <T> ApolloQueryWatcher<T>.mutiny(): Uni<Response<T>> = | ||
MutinyApollo.from(this) | ||
|
||
@JvmSynthetic | ||
inline fun <T> ApolloCall<T>.mutiny(): Uni<Response<T>> = | ||
MutinyApollo.from(this) | ||
|
||
@JvmSynthetic | ||
inline fun <T> ApolloSubscriptionCall<T>.mutiny( | ||
backpressureStrategy: BackPressureStrategy = BackPressureStrategy.LATEST | ||
): Multi<Response<T>> = MutinyApollo.from(this, backpressureStrategy) | ||
|
||
/** | ||
* Creates a new [ApolloQueryCall] call and then converts it to an [Uni]. | ||
* | ||
* The number of emissions this Uni will have is based on the | ||
* [com.apollographql.apollo.fetcher.ResponseFetcher] used with the call. | ||
*/ | ||
@JvmSynthetic | ||
inline fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.mutinyQuery( | ||
query: Query<D, T, V>, | ||
configure: ApolloQueryCall<T>.() -> ApolloQueryCall<T> = { this } | ||
): Uni<Response<T>> = query(query).configure().mutiny() | ||
|
||
/** | ||
* Creates a new [ApolloMutationCall] call and then converts it to a [Uni]. | ||
*/ | ||
@JvmSynthetic | ||
inline fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.mutinyMutate( | ||
mutation: Mutation<D, T, V>, | ||
configure: ApolloMutationCall<T>.() -> ApolloMutationCall<T> = { this } | ||
): Uni<Response<T>> = mutate(mutation).configure().mutiny() | ||
|
||
/** | ||
* Creates a new [ApolloMutationCall] call and then converts it to a [Uni]. | ||
* | ||
* Provided optimistic updates will be stored in [com.apollographql.apollo.cache.normalized.ApolloStore] | ||
* immediately before mutation execution. Any [ApolloQueryWatcher] dependent on the changed cache records will | ||
* be re-fetched. | ||
*/ | ||
@JvmSynthetic | ||
inline fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.mutinyMutate( | ||
mutation: Mutation<D, T, V>, | ||
withOptimisticUpdates: D, | ||
configure: ApolloMutationCall<T>.() -> ApolloMutationCall<T> = { this } | ||
): Uni<Response<T>> = mutate(mutation, withOptimisticUpdates).configure().mutiny() | ||
|
||
/** | ||
* Creates the [ApolloPrefetch] by wrapping the operation object inside and then converts it to a [Uni]. | ||
*/ | ||
@JvmSynthetic | ||
inline fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.mutinyPrefetch( | ||
operation: Operation<D, T, V> | ||
): Uni<Void> = prefetch(operation).mutiny() | ||
|
||
/** | ||
* Creates a new [ApolloSubscriptionCall] call and then converts it to a [Multi]. | ||
* | ||
* Back-pressure strategy can be provided via [backpressureStrategy] parameter. The default value is [BackPressureStrategy.LATEST] | ||
*/ | ||
@JvmSynthetic | ||
inline fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.mutinySubscribe( | ||
subscription: Subscription<D, T, V>, | ||
backpressureStrategy: BackPressureStrategy = BackPressureStrategy.LATEST | ||
): Multi<Response<T>> = subscribe(subscription).mutiny(backpressureStrategy) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the subscriber already got the response, this call will be dropped. I believe it's ok but better double-check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In RxJava we have:
I don't know how to achieve the same check in Mutiny.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may register a callback for terminatIon: https://javadoc.io/static/io.smallrye.reactive/mutiny/0.18.1/io/smallrye/mutiny/subscription/UniEmitter.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than that agreed with @cescoffier