Skip to content

Commit

Permalink
Merge pull request #95 from soil-kt/optional-query
Browse files Browse the repository at this point in the history
Introduce Optional Query
  • Loading branch information
ogaclejapan authored Sep 16, 2024
2 parents d027a36 + adbd2fb commit 2eed406
Show file tree
Hide file tree
Showing 9 changed files with 613 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2024 Soil Contributors
// SPDX-License-Identifier: Apache-2.0

package soil.query.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import soil.query.InfiniteQueryKey
import soil.query.QueryChunks
import soil.query.QueryClient

/**
* Provides a conditional [rememberInfiniteQuery].
*
* Calls [rememberInfiniteQuery] only if [keyFactory] returns a [InfiniteQueryKey] from [value].
*
* @see rememberInfiniteQuery
*/
@Composable
fun <T, S, V> rememberInfiniteQueryIf(
value: V,
keyFactory: (value: V) -> InfiniteQueryKey<T, S>?,
config: InfiniteQueryConfig = InfiniteQueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): InfiniteQueryObject<QueryChunks<T, S>, S>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberInfiniteQuery(key, config, client)
}

/**
* Provides a conditional [rememberInfiniteQuery].
*
* Calls [rememberInfiniteQuery] only if [keyFactory] returns a [InfiniteQueryKey] from [value].
*
* @see rememberInfiniteQuery
*/
@Composable
fun <T, S, U, V> rememberInfiniteQueryIf(
value: V,
keyFactory: (value: V) -> InfiniteQueryKey<T, S>?,
select: (chunks: QueryChunks<T, S>) -> U,
config: InfiniteQueryConfig = InfiniteQueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): InfiniteQueryObject<U, S>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberInfiniteQuery(key, select, config, client)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2024 Soil Contributors
// SPDX-License-Identifier: Apache-2.0

package soil.query.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import soil.query.MutationClient
import soil.query.MutationKey

/**
* Provides a conditional [rememberMutation].
*
* Calls [rememberMutation] only if [keyFactory] returns a [MutationKey] from [value].
*
* @see rememberMutation
*/
@Composable
fun <T, S, V> rememberMutationIf(
value: V,
keyFactory: (value: V) -> MutationKey<T, S>?,
config: MutationConfig = MutationConfig.Default,
client: MutationClient = LocalMutationClient.current
): MutationObject<T, S>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberMutation(key, config, client)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2024 Soil Contributors
// SPDX-License-Identifier: Apache-2.0

package soil.query.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import soil.query.QueryClient
import soil.query.QueryKey
import kotlin.jvm.JvmName

/**
* Provides a conditional [rememberQuery].
*
* Calls [rememberQuery] only if [keyFactory] returns a [QueryKey] from [value].
*
* @see rememberQuery
*/
@Composable
fun <T, V> rememberQueryIf(
value: V,
keyFactory: (value: V) -> QueryKey<T>?,
config: QueryConfig = QueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): QueryObject<T>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberQuery(key, config, client)
}

/**
* Provides a conditional [rememberQuery].
*
* Calls [rememberQuery] only if [keyFactory] returns a [QueryKey] from [value].
*
* @see rememberQuery
*/
@Composable
fun <T, U, V> rememberQueryIf(
value: V,
keyFactory: (value: V) -> QueryKey<T>?,
select: (T) -> U,
config: QueryConfig = QueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): QueryObject<U>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberQuery(key, select, config, client)
}

/**
* Provides a conditional [rememberQuery].
*
* Calls [rememberQuery] only if [keyPairFactory] returns a [Pair] of [QueryKey]s from [value].
*
* @see rememberQuery
*/
@JvmName("rememberQueryIfWithPair")
@Composable
fun <T1, T2, R, V> rememberQueryIf(
value: V,
keyPairFactory: (value: V) -> Pair<QueryKey<T1>, QueryKey<T2>>?,
transform: (T1, T2) -> R,
config: QueryConfig = QueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): QueryObject<R>? {
val keyPair = remember(value) { keyPairFactory(value) } ?: return null
return rememberQuery(keyPair.first, keyPair.second, transform, config, client)
}

/**
* Provides a conditional [rememberQuery].
*
* Calls [rememberQuery] only if [keyTripleFactory] returns a [Triple] of [QueryKey]s from [value].
*
* @see rememberQuery
*/
@JvmName("rememberQueryIfWithTriple")
@Composable
fun <T1, T2, T3, R, V> rememberQueryIf(
value: V,
keyTripleFactory: (value: V) -> Triple<QueryKey<T1>, QueryKey<T2>, QueryKey<T3>>?,
transform: (T1, T2, T3) -> R,
config: QueryConfig = QueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): QueryObject<R>? {
val keyTriple = remember(value) { keyTripleFactory(value) } ?: return null
return rememberQuery(keyTriple.first, keyTriple.second, keyTriple.third, transform, config, client)
}

/**
* Provides a conditional [rememberQuery].
*
* Calls [rememberQuery] only if [keyListFactory] returns a [List] of [QueryKey]s from [value].
*
* @see rememberQuery
*/
@JvmName("rememberQueryIfWithList")
@Composable
fun <T, R, V> rememberQueryIf(
value: V,
keyListFactory: (value: V) -> List<QueryKey<T>>?,
transform: (List<T>) -> R,
config: QueryConfig = QueryConfig.Default,
client: QueryClient = LocalQueryClient.current
): QueryObject<R>? {
val keys = remember(value) { keyListFactory(value) } ?: return null
return rememberQuery(keys, transform, config, client)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2024 Soil Contributors
// SPDX-License-Identifier: Apache-2.0

package soil.query.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import soil.query.SubscriptionClient
import soil.query.SubscriptionKey
import soil.query.annotation.ExperimentalSoilQueryApi

/**
* Provides a conditional [rememberSubscription].
*
* Calls [rememberSubscription] only if [keyFactory] returns a [SubscriptionKey] from [value].
*
* @see rememberSubscription
*/
@ExperimentalSoilQueryApi
@Composable
fun <T, V> rememberSubscriptionIf(
value: V,
keyFactory: (value: V) -> SubscriptionKey<T>?,
config: SubscriptionConfig = SubscriptionConfig.Default,
client: SubscriptionClient = LocalSubscriptionClient.current
): SubscriptionObject<T>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberSubscription(key, config, client)
}

/**
* Provides a conditional [rememberSubscription].
*
* Calls [rememberSubscription] only if [keyFactory] returns a [SubscriptionKey] from [value].
*
* @see rememberSubscription
*/
@ExperimentalSoilQueryApi
@Composable
fun <T, U, V> rememberSubscriptionIf(
value: V,
keyFactory: (value: V) -> SubscriptionKey<T>?,
select: (T) -> U,
config: SubscriptionConfig = SubscriptionConfig.Default,
client: SubscriptionClient = LocalSubscriptionClient.current
): SubscriptionObject<U>? {
val key = remember(value) { keyFactory(value) } ?: return null
return rememberSubscription(key, select, config, client)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ package soil.query.compose
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ExperimentalTestApi
Expand All @@ -32,6 +36,7 @@ import soil.query.compose.tooling.QueryPreviewClient
import soil.query.compose.tooling.SwrPreviewClient
import soil.query.core.Marker
import soil.query.core.Reply
import soil.query.core.orNone
import soil.testing.UnitTest
import kotlin.test.Test

Expand Down Expand Up @@ -249,6 +254,79 @@ class InfiniteQueryComposableTest : UnitTest() {
onNodeWithTag("query").assertTextEquals("ChunkSize: 1")
}

@Test
fun testRememberInfiniteQueryIf() = runComposeUiTest {
val key = TestInfiniteQueryKey()
val client = SwrCache(coroutineScope = SwrCacheScope())
setContent {
SwrClientProvider(client) {
var enabled by remember { mutableStateOf(false) }
val query = rememberInfiniteQueryIf(enabled, keyFactory = { if (it) key else null })
Column {
Button(onClick = { enabled = !enabled }, modifier = Modifier.testTag("toggle")) {
Text("Toggle")
}
when (val reply = query?.reply.orNone()) {
is Reply.Some -> {
reply.value.forEach { chunk ->
Text(
"Size: ${chunk.data.size} - Page: ${chunk.param.page}",
modifier = Modifier.testTag("query")
)
}
}

is Reply.None -> Unit
}
}
}
}

waitForIdle()
onNodeWithTag("query").assertDoesNotExist()
onNodeWithTag("toggle").performClick()

waitUntilAtLeastOneExists(hasTestTag("query"))
onNodeWithTag("query").assertTextEquals("Size: 10 - Page: 0")
}

@Test
fun testRememberInfiniteQueryIf_select() = runComposeUiTest {
val key = TestInfiniteQueryKey()
val client = SwrCache(coroutineScope = SwrCacheScope())
setContent {
SwrClientProvider(client) {
var enabled by remember { mutableStateOf(false) }
val query = rememberInfiniteQueryIf(
value = enabled,
keyFactory = { if (it) key else null },
select = { it.chunkedData })
Column {
Button(onClick = { enabled = !enabled }, modifier = Modifier.testTag("toggle")) {
Text("Toggle")
}
when (val reply = query?.reply.orNone()) {
is Reply.Some -> {
reply.value.forEach { data ->
Text(data, modifier = Modifier.testTag("query"))
}
}

is Reply.None -> Unit
}
}
}
}

waitForIdle()
onNodeWithTag("query").assertDoesNotExist()
onNodeWithTag("toggle").performClick()

waitUntilAtLeastOneExists(hasTestTag("query"))
onAllNodes(hasTestTag("query")).assertCountEquals(10)
}


private class TestInfiniteQueryKey : InfiniteQueryKey<List<String>, PageParam> by buildInfiniteQueryKey(
id = Id,
fetch = { param ->
Expand Down
Loading

0 comments on commit 2eed406

Please sign in to comment.