From 750ab90c61567db62deb684b9a316f174a8b1d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 8 Oct 2024 21:55:24 +0200 Subject: [PATCH] Paging and Filtering --- .../common/network/graphql/CursorPredicate.kt | 32 --------------- .../network/graphql/GraphQLRepresentable.kt | 5 --- .../sdk/feature/store/NotificationStore.kt | 23 ++++------- .../sdk/feature/store/StoreContext.kt | 15 +------ .../sdk/feature/store/StorePagePredicate.kt | 6 +++ .../sdk/feature/store/StorePredicate.kt | 40 +------------------ .../store/data/StoreNetworkDataSource.kt | 3 +- .../sdk/feature/store/data/StoreQuery.kt | 14 ++----- .../feature/store/data/StoreQueryParameter.kt | 31 ++++++++++++++ .../interactor/FetchStorePageInteractor.kt | 8 ++-- .../interactor/GetStorePagesInteractor.kt | 9 ++--- 11 files changed, 61 insertions(+), 125 deletions(-) delete mode 100644 sdk/src/main/java/com/magicbell/sdk/common/network/graphql/CursorPredicate.kt delete mode 100644 sdk/src/main/java/com/magicbell/sdk/common/network/graphql/GraphQLRepresentable.kt create mode 100644 sdk/src/main/java/com/magicbell/sdk/feature/store/StorePagePredicate.kt create mode 100644 sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQueryParameter.kt diff --git a/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/CursorPredicate.kt b/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/CursorPredicate.kt deleted file mode 100644 index 3357452..0000000 --- a/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/CursorPredicate.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.magicbell.sdk.common.network.graphql - -internal class CursorPredicate(val cursor: Cursor = Cursor.Unspecified, val size: Int? = null) : GraphQLRepresentable { - sealed class Cursor { - class Next(val value: String) : Cursor() - class Previous(val value: String) : Cursor() - object Unspecified : Cursor() - } - - override val graphQLValue: String - get() { - val cursorParams = mutableListOf() - - when (cursor) { - is Cursor.Next -> { - cursorParams.add("after: \"${cursor.value}\"") - } - is Cursor.Previous -> { - cursorParams.add("before: \"${cursor.value}\"") - } - Cursor.Unspecified -> { - // Do nothing - } - } - - size?.also { - cursorParams.add("first: $it") - } - - return cursorParams.joinToString(", ") - } -} \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/GraphQLRepresentable.kt b/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/GraphQLRepresentable.kt deleted file mode 100644 index b75e749..0000000 --- a/sdk/src/main/java/com/magicbell/sdk/common/network/graphql/GraphQLRepresentable.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.magicbell.sdk.common.network.graphql - -interface GraphQLRepresentable { - val graphQLValue: String -} \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/NotificationStore.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/NotificationStore.kt index c10c39b..1f8d353 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/NotificationStore.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/NotificationStore.kt @@ -2,8 +2,6 @@ package com.magicbell.sdk.feature.store import androidx.annotation.VisibleForTesting import com.magicbell.sdk.common.error.MagicBellError -import com.magicbell.sdk.common.network.graphql.CursorPredicate -import com.magicbell.sdk.common.network.graphql.CursorPredicate.Cursor.Next import com.magicbell.sdk.common.query.UserQuery import com.magicbell.sdk.common.threading.MainThread import com.magicbell.sdk.feature.notification.Notification @@ -115,7 +113,7 @@ class NotificationStore internal constructor( var hasNextPage: Boolean = true private set - private var nextPageCursor: String? = null + private var nextPage: Int = 1 private val mutableContentFlow = MutableSharedFlow() @@ -320,8 +318,8 @@ class NotificationStore internal constructor( suspend fun refresh(): Result> { return runCatching { withContext(coroutineContext) { - val cursorPredicate = CursorPredicate(size = pageSize) - val storePage = fetchStorePageInteractor(predicate, cursorPredicate, userQuery) + val storePagePredicate = StorePagePredicate(1, pageSize) + val storePage = fetchStorePageInteractor(predicate, storePagePredicate, userQuery) clear(false) configurePagination(storePage) configureCount(storePage) @@ -345,13 +343,8 @@ class NotificationStore internal constructor( if (!hasNextPage) { return@withContext listOf() } - val cursorPredicate: CursorPredicate = nextPageCursor?.let { after -> - CursorPredicate(Next(after), pageSize) - } ?: run { - CursorPredicate(size = pageSize) - } - - val storePage = fetchStorePageInteractor(predicate, cursorPredicate, userQuery) + val storePagePredicate = StorePagePredicate(nextPage, pageSize) + val storePage = fetchStorePageInteractor(predicate, storePagePredicate, userQuery) configurePagination(storePage) configureCount(storePage) @@ -482,7 +475,7 @@ class NotificationStore internal constructor( setTotalCount(0, notifyChanges) setUnreadCount(0, notifyChanges) setUnseenCount(0, notifyChanges) - nextPageCursor = null + nextPage = 1 setHasNextPage(true) if (notifyChanges) { val indexes = 0 until notificationCount @@ -524,9 +517,7 @@ class NotificationStore internal constructor( } private fun configurePagination(storePage: StorePage) { - // TODO: pagination -// val pageInfo = storePage.pageInfo -// nextPageCursor = pageInfo.endCursor + nextPage = storePage.currentPage + 1 setHasNextPage(storePage.currentPage < storePage.totalPages) } diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/StoreContext.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/StoreContext.kt index 19641ff..d7cf138 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/StoreContext.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/StoreContext.kt @@ -1,17 +1,6 @@ package com.magicbell.sdk.feature.store -import com.magicbell.sdk.common.network.graphql.CursorPredicate -import com.magicbell.sdk.common.network.graphql.GraphQLRepresentable - internal class StoreContext( val storePredicate: StorePredicate, - val cursorPredicate: CursorPredicate, -) : GraphQLRepresentable { - override val graphQLValue: String - get() { - val storePredicateString = storePredicate.graphQLValue - val cursorPredicateString = cursorPredicate.graphQLValue - - return " data: notifications ($storePredicateString, $cursorPredicateString) { ...notification }" - } -} \ No newline at end of file + val storePagePredicate: StorePagePredicate, +) \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePagePredicate.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePagePredicate.kt new file mode 100644 index 0000000..26abb1d --- /dev/null +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePagePredicate.kt @@ -0,0 +1,6 @@ +package com.magicbell.sdk.feature.store + +internal data class StorePagePredicate( + val page: Int, + val size: Int, +) \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePredicate.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePredicate.kt index e8103e4..2077c25 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePredicate.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/StorePredicate.kt @@ -1,6 +1,5 @@ package com.magicbell.sdk.feature.store -import com.magicbell.sdk.common.network.graphql.GraphQLRepresentable import com.magicbell.sdk.feature.notification.Notification /** @@ -17,44 +16,7 @@ data class StorePredicate( val archived: Boolean = false, val category: String? = null, val topic: String? = null, -) : GraphQLRepresentable { - override val graphQLValue: String - get() { - val storePredicateParams = mutableListOf() - - read?.also { - if (it) { - storePredicateParams.add("read: true") - } else { - storePredicateParams.add("read: false") - } - } - - seen?.also { - if (it) { - storePredicateParams.add("seen: true") - } else { - storePredicateParams.add("seen: false") - } - } - - if (archived) { - storePredicateParams.add("archived: true") - } else { - storePredicateParams.add("archived: false") - } - - category?.let { - storePredicateParams.add("categories:[$it]") - } - - topic?.let { - storePredicateParams.add("topics:[$it]") - } - - return storePredicateParams.joinToString(", ") - } -} +) internal fun StorePredicate.match(notification: Notification): Boolean { val validator = NotificationValidator(this) diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreNetworkDataSource.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreNetworkDataSource.kt index 1e7edbf..4a4dcb5 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreNetworkDataSource.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreNetworkDataSource.kt @@ -21,7 +21,8 @@ internal class StoreNetworkDataSource( "notifications", query.userQuery.externalId, query.userQuery.email, - query.userQuery.hmac + query.userQuery.hmac, + HttpClient.HttpMethod.Get(query.context.asQueryParameters()) ) httpClient.performRequest(request)?.let { diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQuery.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQuery.kt index 013acb9..4a1aab4 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQuery.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQuery.kt @@ -1,25 +1,19 @@ package com.magicbell.sdk.feature.store.data import com.mobilejazz.harmony.data.query.Query -import com.magicbell.sdk.common.network.graphql.CursorPredicate -import com.magicbell.sdk.common.network.graphql.GraphQLRepresentable import com.magicbell.sdk.common.query.UserQuery import com.magicbell.sdk.feature.store.StoreContext +import com.magicbell.sdk.feature.store.StorePagePredicate import com.magicbell.sdk.feature.store.StorePredicate internal class StoreQuery( val context: StoreContext, val userQuery: UserQuery, -) : Query(), GraphQLRepresentable { +) : Query() { constructor( storePredicate: StorePredicate, - cursorPredicate: CursorPredicate, + storePagePredicate: StorePagePredicate, userQuery: UserQuery, - ) : this(StoreContext(storePredicate, cursorPredicate), userQuery) - - override val graphQLValue: String - get() { - return context.graphQLValue - } + ) : this(StoreContext(storePredicate, storePagePredicate), userQuery) } \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQueryParameter.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQueryParameter.kt new file mode 100644 index 0000000..6077e91 --- /dev/null +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/data/StoreQueryParameter.kt @@ -0,0 +1,31 @@ +package com.magicbell.sdk.feature.store.data + +import com.magicbell.sdk.feature.store.StoreContext +import com.magicbell.sdk.feature.store.StorePagePredicate +import com.magicbell.sdk.feature.store.StorePredicate + +internal fun StoreContext.asQueryParameters(): Map { + return storePredicate.asQueryParameters() + storePagePredicate.asQueryParameters() +} + +private fun StorePredicate.asQueryParameters(): Map { + val result: MutableMap = mutableMapOf() + read?.let { + result["read"] = "$read" + } + seen?.let { + result["seen"] = "$seen" + } + result["archived"] = "$archived" + + + return result +} + +private fun StorePagePredicate.asQueryParameters(): Map { + return mapOf( + "page" to "$page", + "per_page" to "$size", + ) +} + diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/FetchStorePageInteractor.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/FetchStorePageInteractor.kt index 7b2085c..b1aca7d 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/FetchStorePageInteractor.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/FetchStorePageInteractor.kt @@ -1,8 +1,8 @@ package com.magicbell.sdk.feature.store.interactor -import com.magicbell.sdk.common.network.graphql.CursorPredicate import com.magicbell.sdk.common.query.UserQuery import com.magicbell.sdk.feature.store.StorePage +import com.magicbell.sdk.feature.store.StorePagePredicate import com.magicbell.sdk.feature.store.StorePredicate import kotlinx.coroutines.withContext import kotlin.coroutines.CoroutineContext @@ -10,7 +10,7 @@ import kotlin.coroutines.CoroutineContext internal interface FetchStorePageInteractor { suspend operator fun invoke( storePredicate: StorePredicate, - cursorPredicate: CursorPredicate, + storePagePredicate: StorePagePredicate, userQuery: UserQuery, ): StorePage } @@ -22,11 +22,11 @@ internal class FetchStorePageDefaultInteractor( override suspend operator fun invoke( storePredicate: StorePredicate, - cursorPredicate: CursorPredicate, + storePagePredicate: StorePagePredicate, userQuery: UserQuery, ): StorePage { return withContext(interactorCoroutineContext) { - getStorePagesInteractor(storePredicate, cursorPredicate, userQuery) + getStorePagesInteractor(storePredicate, storePagePredicate, userQuery) } } } \ No newline at end of file diff --git a/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/GetStorePagesInteractor.kt b/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/GetStorePagesInteractor.kt index ab527a9..b4bfa96 100644 --- a/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/GetStorePagesInteractor.kt +++ b/sdk/src/main/java/com/magicbell/sdk/feature/store/interactor/GetStorePagesInteractor.kt @@ -1,13 +1,12 @@ package com.magicbell.sdk.feature.store.interactor -import com.mobilejazz.harmony.domain.interactor.GetInteractor -import com.magicbell.sdk.common.error.MagicBellError -import com.magicbell.sdk.common.network.graphql.CursorPredicate import com.magicbell.sdk.common.query.UserQuery import com.magicbell.sdk.feature.store.StoreContext import com.magicbell.sdk.feature.store.StorePage +import com.magicbell.sdk.feature.store.StorePagePredicate import com.magicbell.sdk.feature.store.StorePredicate import com.magicbell.sdk.feature.store.data.StoreQuery +import com.mobilejazz.harmony.domain.interactor.GetInteractor import kotlinx.coroutines.withContext import kotlin.coroutines.CoroutineContext @@ -18,10 +17,10 @@ internal class GetStorePagesInteractor( suspend operator fun invoke( storePredicate: StorePredicate, - cursorPredicate: CursorPredicate, + storePagePredicate: StorePagePredicate, userQuery: UserQuery, ): StorePage { - val context = StoreContext(storePredicate, cursorPredicate) + val context = StoreContext(storePredicate, storePagePredicate) return withContext(coroutineContext) { getStoreNotificationInteractor(StoreQuery(context, userQuery)) }