Skip to content

Commit 44f8899

Browse files
VelikovPetarclaude
andcommitted
Keep QueryChannelsIdentifier off the public QueryChannelsRepository ABI.
Replace selectBy(QueryChannelsIdentifier) with two primitive overloads on the public interface so the @InternalStreamChatApi identifier type stops leaking into the supported API surface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7b8506b commit 44f8899

7 files changed

Lines changed: 51 additions & 57 deletions

File tree

stream-chat-android-client/api/stream-chat-android-client.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,10 +3091,10 @@ public abstract interface class io/getstream/chat/android/client/persistance/rep
30913091
public abstract interface class io/getstream/chat/android/client/persistance/repository/QueryChannelsRepository {
30923092
public abstract fun clear (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
30933093
public abstract fun insertQueryChannels (Lio/getstream/chat/android/client/query/QueryChannelsSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3094-
public fun selectBy (Lio/getstream/chat/android/client/internal/state/plugin/QueryChannelsIdentifier;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
30953094
public fun selectBy (Lio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3096-
public static synthetic fun selectBy$suspendImpl (Lio/getstream/chat/android/client/persistance/repository/QueryChannelsRepository;Lio/getstream/chat/android/client/internal/state/plugin/QueryChannelsIdentifier;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3095+
public fun selectBy (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
30973096
public static synthetic fun selectBy$suspendImpl (Lio/getstream/chat/android/client/persistance/repository/QueryChannelsRepository;Lio/getstream/chat/android/models/FilterObject;Lio/getstream/chat/android/models/querysort/QuerySorter;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3097+
public static synthetic fun selectBy$suspendImpl (Lio/getstream/chat/android/client/persistance/repository/QueryChannelsRepository;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
30983098
}
30993099

31003100
public abstract interface class io/getstream/chat/android/client/persistance/repository/ReactionRepository {

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/persistance/repository/QueryChannelsRepository.kt

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package io.getstream.chat.android.client.persistance.repository
1818

19-
import io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdentifier
2019
import io.getstream.chat.android.client.query.QueryChannelsSpec
2120
import io.getstream.chat.android.models.Channel
2221
import io.getstream.chat.android.models.FilterObject
@@ -35,36 +34,28 @@ public interface QueryChannelsRepository {
3534
public suspend fun insertQueryChannels(queryChannelsSpec: QueryChannelsSpec)
3635

3736
/**
38-
* Selects by a filter and query sort. Kept for backwards compatibility with custom
39-
* implementations written before predefined filters existed.
37+
* Selects a query spec persisted for a classic query identified by [filter] and [querySort].
4038
*
4139
* @param filter [FilterObject]
4240
* @param querySort [QuerySorter]
4341
*/
44-
@Deprecated(
45-
message = "Use selectBy(QueryChannelsIdentifier) instead. " +
46-
"This overload cannot represent server-side predefined-filter queries.",
47-
replaceWith = ReplaceWith(
48-
"selectBy(QueryChannelsIdentifier.Standard(filter, querySort))",
49-
"io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdentifier",
50-
),
51-
)
5242
public suspend fun selectBy(filter: FilterObject, querySort: QuerySorter<Channel>): QueryChannelsSpec? = null
5343

5444
/**
55-
* Selects a query spec by its identifier. Default implementation delegates to the legacy
56-
* [selectBy(filter, querySort)] for [QueryChannelsIdentifier.Standard] (so existing custom
57-
* implementations of the legacy overload keep working) and returns `null` for
58-
* [QueryChannelsIdentifier.Predefined] (no offline data — falls back to network).
45+
* Selects a query spec persisted for a server-side predefined-filter query identified by
46+
* [predefinedFilterName] and its interpolation values.
5947
*
60-
* @param identifier The query spec identifier.
48+
* @param predefinedFilterName Name of the predefined filter registered on the backend.
49+
* @param filterValues Values interpolated into the predefined filter template. `null` and an
50+
* empty map are treated as equivalent — pass normalized maps for stable identity.
51+
* @param sortValues Values interpolated into the predefined sort template. Same normalization
52+
* contract as [filterValues].
6153
*/
62-
public suspend fun selectBy(identifier: QueryChannelsIdentifier): QueryChannelsSpec? = when (identifier) {
63-
is QueryChannelsIdentifier.Standard ->
64-
@Suppress("DEPRECATION")
65-
selectBy(identifier.filter, identifier.sort)
66-
is QueryChannelsIdentifier.Predefined -> null
67-
}
54+
public suspend fun selectBy(
55+
predefinedFilterName: String,
56+
filterValues: Map<String, Any>?,
57+
sortValues: Map<String, Any>?,
58+
): QueryChannelsSpec? = null
6859

6960
/**
7061
* Clear QueryChannels of this repository.

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/persistance/repository/noop/NoOpQueryChannelsRepository.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package io.getstream.chat.android.client.persistance.repository.noop
1818

19-
import io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdentifier
2019
import io.getstream.chat.android.client.persistance.repository.QueryChannelsRepository
2120
import io.getstream.chat.android.client.query.QueryChannelsSpec
2221
import io.getstream.chat.android.models.Channel
@@ -28,15 +27,11 @@ import io.getstream.chat.android.models.querysort.QuerySorter
2827
*/
2928
internal object NoOpQueryChannelsRepository : QueryChannelsRepository {
3029
override suspend fun insertQueryChannels(queryChannelsSpec: QueryChannelsSpec) { /* No-Op */ }
31-
32-
@Deprecated(
33-
message = "Use selectBy(QueryChannelsIdentifier) instead.",
34-
replaceWith = ReplaceWith(
35-
"selectBy(QueryChannelsIdentifier.Standard(filter, querySort))",
36-
"io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdentifier",
37-
),
38-
)
3930
override suspend fun selectBy(filter: FilterObject, querySort: QuerySorter<Channel>): QueryChannelsSpec? = null
40-
override suspend fun selectBy(identifier: QueryChannelsIdentifier): QueryChannelsSpec? = null
31+
override suspend fun selectBy(
32+
predefinedFilterName: String,
33+
filterValues: Map<String, Any>?,
34+
sortValues: Map<String, Any>?,
35+
): QueryChannelsSpec? = null
4136
override suspend fun clear() { /* No-Op */ }
4237
}

stream-chat-android-offline/src/main/java/io/getstream/chat/android/offline/repository/domain/queryChannels/internal/DatabaseQueryChannelsRepository.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdent
2020
import io.getstream.chat.android.client.internal.state.plugin.identifier
2121
import io.getstream.chat.android.client.persistance.repository.QueryChannelsRepository
2222
import io.getstream.chat.android.client.query.QueryChannelsSpec
23+
import io.getstream.chat.android.models.Channel
24+
import io.getstream.chat.android.models.FilterObject
25+
import io.getstream.chat.android.models.querysort.QuerySorter
2326

2427
/**
2528
* Repository for queries of channels. This implementation uses the database.
@@ -37,8 +40,17 @@ internal class DatabaseQueryChannelsRepository(
3740
queryChannelsDao.insert(toEntity(queryChannelsSpec))
3841
}
3942

40-
override suspend fun selectBy(identifier: QueryChannelsIdentifier): QueryChannelsSpec? {
41-
return queryChannelsDao.select(generateId(identifier))?.let(Companion::toModel)
43+
override suspend fun selectBy(filter: FilterObject, querySort: QuerySorter<Channel>): QueryChannelsSpec? {
44+
return queryChannelsDao.select(generateId(QueryChannelsIdentifier.Standard(filter, querySort)))?.let(::toModel)
45+
}
46+
47+
override suspend fun selectBy(
48+
predefinedFilterName: String,
49+
filterValues: Map<String, Any>?,
50+
sortValues: Map<String, Any>?,
51+
): QueryChannelsSpec? {
52+
val identifier = QueryChannelsIdentifier.Predefined(predefinedFilterName, filterValues, sortValues)
53+
return queryChannelsDao.select(generateId(identifier))?.let(::toModel)
4254
}
4355

4456
override suspend fun clear() {

stream-chat-android-offline/src/test/java/io/getstream/chat/android/offline/repository/QueryChannelsImplRepositoryTest.kt

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package io.getstream.chat.android.offline.repository
1818

19-
import io.getstream.chat.android.client.internal.state.plugin.QueryChannelsIdentifier
2019
import io.getstream.chat.android.client.test.randomQueryChannelsSpec
2120
import io.getstream.chat.android.models.ContainsFilterObject
2221
import io.getstream.chat.android.models.Filters
@@ -77,18 +76,14 @@ internal class QueryChannelsImplRepositoryTest {
7776

7877
@Test
7978
fun `Given query channels spec in DB When select by id Should return not null result`() = runTest {
80-
val identifier = QueryChannelsIdentifier.Standard(
81-
filter = Filters.contains("cid", "cid1"),
82-
sort = QuerySortByField(),
83-
)
8479
whenever(dao.select(any())) doReturn randomQueryChannelsEntity(
8580
id = "id1",
8681
filter = Filters.contains("cid", "cid1"),
8782
querySort = QuerySortByField(),
8883
cids = listOf("cid1"),
8984
)
9085

91-
val result = sut.selectBy(identifier)
86+
val result = sut.selectBy(Filters.contains("cid", "cid1"), QuerySortByField())
9287

9388
result.shouldNotBeNull()
9489
result.filter.shouldBeInstanceOf<ContainsFilterObject>()
@@ -101,18 +96,15 @@ internal class QueryChannelsImplRepositoryTest {
10196
fun `Given no row in DB with such id When select by id Should return null`() = runTest {
10297
whenever(dao.select(any())) doReturn null
10398

104-
val result = sut.selectBy(QueryChannelsIdentifier.Standard(NeutralFilterObject, QuerySortByField()))
99+
val result = sut.selectBy(NeutralFilterObject, QuerySortByField())
105100

106101
result.shouldBeNull()
107102
}
108103

109104
@Test
110105
fun `Two Predefined identifiers with same name but different filterValues produce different DB ids`() = runTest {
111-
val identifierA = QueryChannelsIdentifier.Predefined("p", mapOf("a" to 1), null)
112-
val identifierB = QueryChannelsIdentifier.Predefined("p", mapOf("a" to 2), null)
113-
114-
sut.selectBy(identifierA)
115-
sut.selectBy(identifierB)
106+
sut.selectBy("p", mapOf("a" to 1), null)
107+
sut.selectBy("p", mapOf("a" to 2), null)
116108

117109
val captor = argumentCaptor<String>()
118110
verify(dao, times(2)).select(captor.capture())
@@ -122,7 +114,6 @@ internal class QueryChannelsImplRepositoryTest {
122114

123115
@Test
124116
fun `selectBy with Predefined identifier round-trips predefined fields from the entity`() = runTest {
125-
val identifier = QueryChannelsIdentifier.Predefined("p", mapOf("a" to 1), mapOf("b" to 2))
126117
whenever(dao.select(any())) doReturn randomQueryChannelsEntity(
127118
id = "id-predefined",
128119
filter = NeutralFilterObject,
@@ -133,7 +124,7 @@ internal class QueryChannelsImplRepositoryTest {
133124
predefinedSortValues = mapOf("b" to 2),
134125
)
135126

136-
val spec = sut.selectBy(identifier)
127+
val spec = sut.selectBy("p", mapOf("a" to 1), mapOf("b" to 2))
137128

138129
spec.shouldNotBeNull()
139130
assertEquals("p", spec.predefinedFilterName)

stream-chat-android-state/src/main/java/io/getstream/chat/android/state/plugin/logic/querychannels/internal/QueryChannelsDatabaseLogic.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ internal class QueryChannelsDatabaseLogic(
6161
pagination: AnyChannelPaginationRequest,
6262
identifier: QueryChannelsIdentifier,
6363
): CachedQueryChannels? {
64-
val spec = queryChannelsRepository.selectBy(identifier) ?: return null
64+
val spec = when (identifier) {
65+
is QueryChannelsIdentifier.Standard ->
66+
queryChannelsRepository.selectBy(identifier.filter, identifier.sort)
67+
is QueryChannelsIdentifier.Predefined ->
68+
queryChannelsRepository.selectBy(identifier.name, identifier.filterValues, identifier.sortValues)
69+
} ?: return null
6570
val channels = repositoryFacade
6671
.selectChannels(spec.cids.toList(), pagination)
6772
.applyPagination(pagination)

stream-chat-android-state/src/test/java/io/getstream/chat/android/state/plugin/logic/querychannels/internal/QueryChannelsDatabaseLogicTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ internal class QueryChannelsDatabaseLogicTest {
7676
val identifier = QueryChannelsIdentifier.Standard(filter, sort)
7777
val pagination = AnyChannelPaginationRequest()
7878

79-
whenever(queryChannelsRepository.selectBy(identifier)) doReturn null
79+
whenever(queryChannelsRepository.selectBy(filter, sort)) doReturn null
8080

8181
// When
8282
val result = logic.fetchChannelsFromCache(pagination, identifier)
8383

8484
// Then
8585
assertNull(result)
86-
verify(queryChannelsRepository).selectBy(identifier)
86+
verify(queryChannelsRepository).selectBy(filter, sort)
8787
}
8888

8989
@Test
@@ -112,7 +112,7 @@ internal class QueryChannelsDatabaseLogicTest {
112112
val channel3 = randomChannel(id = "channel3", type = "messaging")
113113
val expectedChannels = listOf(channel1, channel2, channel3)
114114

115-
whenever(queryChannelsRepository.selectBy(identifier)) doReturn cachedSpec
115+
whenever(queryChannelsRepository.selectBy(filter, sort)) doReturn cachedSpec
116116
whenever(repositoryFacade.selectChannels(listOf(cid1, cid2, cid3), pagination)) doReturn expectedChannels
117117

118118
// When
@@ -121,7 +121,7 @@ internal class QueryChannelsDatabaseLogicTest {
121121
// Then
122122
assertEquals(cachedSpec, result?.spec)
123123
assertEquals(expectedChannels, result?.channels)
124-
verify(queryChannelsRepository).selectBy(identifier)
124+
verify(queryChannelsRepository).selectBy(filter, sort)
125125
verify(repositoryFacade).selectChannels(listOf(cid1, cid2, cid3), pagination)
126126
}
127127

@@ -139,7 +139,7 @@ internal class QueryChannelsDatabaseLogicTest {
139139
cids = emptySet(),
140140
)
141141

142-
whenever(queryChannelsRepository.selectBy(identifier)) doReturn cachedSpec
142+
whenever(queryChannelsRepository.selectBy(filter, sort)) doReturn cachedSpec
143143
whenever(repositoryFacade.selectChannels(emptyList(), pagination)) doReturn emptyList()
144144

145145
// When
@@ -148,7 +148,7 @@ internal class QueryChannelsDatabaseLogicTest {
148148
// Then
149149
assertEquals(cachedSpec, result?.spec)
150150
assertEquals(emptyList<Channel>(), result?.channels)
151-
verify(queryChannelsRepository).selectBy(identifier)
151+
verify(queryChannelsRepository).selectBy(filter, sort)
152152
verify(repositoryFacade).selectChannels(emptyList(), pagination)
153153
}
154154

0 commit comments

Comments
 (0)