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

Change XxxRef class to interface for better testability. #55

Merged
merged 1 commit into from
Aug 10, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import soil.query.QueryChunks
import soil.query.QueryClient
import soil.query.QueryState
import soil.query.QueryStatus
import soil.query.invalidate
import soil.query.loadMore
import soil.query.resume

/**
* Remember a [InfiniteQueryObject] and subscribes to the query state of [key].
Expand All @@ -34,7 +37,7 @@ fun <T, S> rememberInfiniteQuery(
val query = remember(key) { client.getInfiniteQuery(key).also { it.launchIn(scope) } }
val state by query.state.collectAsState()
LaunchedEffect(query) {
query.start()
query.resume()
}
return remember(query, state) {
state.toInfiniteObject(query = query, select = { it })
Expand All @@ -61,7 +64,7 @@ fun <T, S, U> rememberInfiniteQuery(
val query = remember(key) { client.getInfiniteQuery(key).also { it.launchIn(scope) } }
val state by query.state.collectAsState()
LaunchedEffect(query) {
query.start()
query.resume()
}
return remember(query, state) {
state.toInfiniteObject(query = query, select = select)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import soil.query.MutationKey
import soil.query.MutationRef
import soil.query.MutationState
import soil.query.MutationStatus
import soil.query.mutate
import soil.query.mutateAsync
import soil.query.reset

/**
* Remember a [MutationObject] and subscribes to the mutation state of [key].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import soil.query.QueryKey
import soil.query.QueryRef
import soil.query.QueryState
import soil.query.QueryStatus
import soil.query.invalidate
import soil.query.resume

/**
* Remember a [QueryObject] and subscribes to the query state of [key].
Expand All @@ -32,7 +34,7 @@ fun <T> rememberQuery(
val query = remember(key) { client.getQuery(key).also { it.launchIn(scope) } }
val state by query.state.collectAsState()
LaunchedEffect(query) {
query.start()
query.resume()
}
return remember(query, state) {
state.toObject(query = query, select = { it })
Expand All @@ -59,7 +61,7 @@ fun <T, U> rememberQuery(
val query = remember(key) { client.getQuery(key).also { it.launchIn(scope) } }
val state by query.state.collectAsState()
LaunchedEffect(query) {
query.start()
query.resume()
}
return remember(query, state) {
state.toObject(query = query, select = select)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,47 @@

package soil.query

import kotlinx.coroutines.CompletableDeferred
import soil.query.core.toResultCallback
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.flow.StateFlow
import soil.query.core.Actor

/**
* A reference to an [Query] for [InfiniteQueryKey].
* A reference to an Query for [InfiniteQueryKey].
*
* @param T Type of data to retrieve.
* @param S Type of parameter.
* @property key Instance of a class implementing [InfiniteQueryKey].
* @param query Transparently referenced [Query].
* @constructor Creates an [InfiniteQueryRef].
*/
class InfiniteQueryRef<T, S>(
val key: InfiniteQueryKey<T, S>,
val options: QueryOptions,
query: Query<QueryChunks<T, S>>
) : Query<QueryChunks<T, S>> by query {
interface InfiniteQueryRef<T, S> : Actor {

/**
* Starts the [Query].
*
* This function must be invoked when a new mount point (subscriber) is added.
*/
suspend fun start() {
command.send(InfiniteQueryCommands.Connect(key))
event.collect(::handleEvent)
}

/**
* Prefetches the [Query].
*/
suspend fun prefetch(): Boolean {
val deferred = CompletableDeferred<QueryChunks<T, S>>()
command.send(InfiniteQueryCommands.Connect(key, state.value.revision, deferred.toResultCallback()))
return try {
deferred.await()
true
} catch (e: CancellationException) {
throw e
} catch (e: Throwable) {
false
}
}
val key: InfiniteQueryKey<T, S>
val options: QueryOptions
val state: StateFlow<QueryState<QueryChunks<T, S>>>

/**
* Invalidates the [Query].
*
* Calling this function will invalidate the retrieved data of the [Query],
* setting [QueryModel.isInvalidated] to `true` until revalidation is completed.
* Sends a [QueryCommand] to the Actor.
*/
suspend fun invalidate() {
command.send(InfiniteQueryCommands.Invalidate(key, state.value.revision))
}
suspend fun send(command: QueryCommand<QueryChunks<T, S>>)
}

/**
* Resumes the [Query].
*/
private suspend fun resume() {
command.send(InfiniteQueryCommands.Connect(key, state.value.revision))
}
/**
* Invalidates the Query.
*
* Calling this function will invalidate the retrieved data of the Query,
* setting [QueryModel.isInvalidated] to `true` until revalidation is completed.
*/
suspend fun <T, S> InfiniteQueryRef<T, S>.invalidate() {
send(InfiniteQueryCommands.Invalidate(key, state.value.revision))
}

/**
* Fetches data for the [InfiniteQueryKey] using the value of [param].
*/
suspend fun loadMore(param: S) {
command.send(InfiniteQueryCommands.LoadMore(key, param))
}
/**
* Resumes the Query.
*/
suspend fun <T, S> InfiniteQueryRef<T, S>.resume() {
send(InfiniteQueryCommands.Connect(key, state.value.revision))
}

private suspend fun handleEvent(e: QueryEvent) {
when (e) {
QueryEvent.Invalidate -> invalidate()
QueryEvent.Resume -> resume()
}
}
/**
* Fetches data for the [InfiniteQueryKey] using the value of [param].
*/
suspend fun <T, S> InfiniteQueryRef<T, S>.loadMore(param: S) {
send(InfiniteQueryCommands.LoadMore(key, param))
}
68 changes: 36 additions & 32 deletions soil-query-core/src/commonMain/kotlin/soil/query/MutationRef.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,52 @@
package soil.query

import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.StateFlow
import soil.query.core.Actor
import soil.query.core.toResultCallback

/**
* A reference to a [Mutation] for [MutationKey].
* A reference to a Mutation for [MutationKey].
*
* @param T Type of the return value from the mutation.
* @param S Type of the variable to be mutated.
* @property key Instance of a class implementing [MutationKey].
* @param mutation The mutation to perform.
* @constructor Creates a [MutationRef].
*/
class MutationRef<T, S>(
val key: MutationKey<T, S>,
val options: MutationOptions,
mutation: Mutation<T>
) : Mutation<T> by mutation {
interface MutationRef<T, S> : Actor {

/**
* Mutates the variable.
*
* @param variable The variable to be mutated.
* @return The result of the mutation.
*/
suspend fun mutate(variable: S): T {
val deferred = CompletableDeferred<T>()
command.send(MutationCommands.Mutate(key, variable, state.value.revision, deferred.toResultCallback()))
return deferred.await()
}
val key: MutationKey<T, S>
val options: MutationOptions
val state: StateFlow<MutationState<T>>

/**
* Mutates the variable asynchronously.
*
* @param variable The variable to be mutated.
* Sends a [MutationCommand] to the Actor.
*/
suspend fun mutateAsync(variable: S) {
command.send(MutationCommands.Mutate(key, variable, state.value.revision))
}
suspend fun send(command: MutationCommand<T>)
}

/**
* Resets the mutation state.
*/
suspend fun reset() {
command.send(MutationCommands.Reset())
}
/**
* Mutates the variable.
*
* @param variable The variable to be mutated.
* @return The result of the mutation.
*/
suspend fun <T, S> MutationRef<T, S>.mutate(variable: S): T {
val deferred = CompletableDeferred<T>()
send(MutationCommands.Mutate(key, variable, state.value.revision, deferred.toResultCallback()))
return deferred.await()
}

/**
* Mutates the variable asynchronously.
*
* @param variable The variable to be mutated.
*/
suspend fun <T, S> MutationRef<T, S>.mutateAsync(variable: S) {
send(MutationCommands.Mutate(key, variable, state.value.revision))
}

/**
* Resets the mutation state.
*/
suspend fun <T, S> MutationRef<T, S>.reset() {
send(MutationCommands.Reset())
}
80 changes: 24 additions & 56 deletions soil-query-core/src/commonMain/kotlin/soil/query/QueryRef.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,39 @@

package soil.query

import kotlinx.coroutines.CompletableDeferred
import soil.query.core.toResultCallback
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.flow.StateFlow
import soil.query.core.Actor

/**
* A reference to an [Query] for [QueryKey].
* A reference to an Query for [QueryKey].
*
* @param T Type of data to retrieve.
* @property key Instance of a class implementing [QueryKey].
* @param query Transparently referenced [Query].
* @constructor Creates an [QueryRef]
*/
class QueryRef<T>(
val key: QueryKey<T>,
val options: QueryOptions,
query: Query<T>
) : Query<T> by query {
interface QueryRef<T> : Actor {

/**
* Starts the [Query].
*
* This function must be invoked when a new mount point (subscriber) is added.
*/
suspend fun start() {
command.send(QueryCommands.Connect(key))
event.collect(::handleEvent)
}
val key: QueryKey<T>
val options: QueryOptions
val state: StateFlow<QueryState<T>>

/**
* Prefetches the [Query].
* Sends a [QueryCommand] to the Actor.
*/
suspend fun prefetch(): Boolean {
val deferred = CompletableDeferred<T>()
command.send(QueryCommands.Connect(key, state.value.revision, deferred.toResultCallback()))
return try {
deferred.await()
true
} catch (e: CancellationException) {
throw e
} catch (e: Throwable) {
false
}
}

/**
* Invalidates the [Query].
*
* Calling this function will invalidate the retrieved data of the [Query],
* setting [QueryModel.isInvalidated] to `true` until revalidation is completed.
*/
suspend fun invalidate() {
command.send(QueryCommands.Invalidate(key, state.value.revision))
}
suspend fun send(command: QueryCommand<T>)
}

/**
* Resumes the [Query].
*/
internal suspend fun resume() {
command.send(QueryCommands.Connect(key, state.value.revision))
}
/**
* Invalidates the Query.
*
* Calling this function will invalidate the retrieved data of the Query,
* setting [QueryModel.isInvalidated] to `true` until revalidation is completed.
*/
suspend fun <T> QueryRef<T>.invalidate() {
send(QueryCommands.Invalidate(key, state.value.revision))
}

private suspend fun handleEvent(e: QueryEvent) {
when (e) {
QueryEvent.Invalidate -> invalidate()
QueryEvent.Resume -> resume()
}
}
/**
* Resumes the Query.
*/
suspend fun <T> QueryRef<T>.resume() {
send(QueryCommands.Connect(key, state.value.revision))
}
Loading