From e4fb3023278b451f22550b7fc6b51775c98194c7 Mon Sep 17 00:00:00 2001 From: Veyndan Stuart Date: Thu, 4 Aug 2022 15:05:41 +0200 Subject: [PATCH 1/2] Allow construction of OffsetQueryPagingSource with Long --- .../paging3/OffsetQueryPagingSourceTest.kt | 42 +++++++++++++++++-- .../sqldelight/paging3/QueryPagingSource.kt | 30 +++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt b/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt index f72725eb3a5..0348aacf18b 100644 --- a/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt +++ b/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt @@ -629,14 +629,40 @@ class OffsetQueryPagingSourceTest { assertTrue(pagingSource.jumpingSupported) } - private fun query(limit: Int, offset: Int) = object : Query( + @Test + fun load_initialEmptyLoad_QueryPagingSourceLong() = runTest { + val pagingSource = QueryPagingSourceLong( + countQueryLong(), + transacter, + EmptyCoroutineContext, + ::queryLong, + ) + val result = pagingSource.refresh() as LoadResult.Page + + assertTrue(result.data.isEmpty()) + + // now add items + insertItems(ITEMS_LIST) + + // invalidate pagingSource to imitate invalidation from running refreshVersionSync + pagingSource.invalidate() + assertTrue(pagingSource.invalid) + + // this refresh should check pagingSource's invalid status, realize it is invalid, and + // return a LoadResult.Invalid + assertThat(pagingSource.refresh()).isInstanceOf(LoadResult.Invalid::class.java) + } + + private fun query(limit: Int, offset: Int) = queryLong(limit.toLong(), offset.toLong()) + + private fun queryLong(limit: Long, offset: Long) = object : Query( { cursor -> TestItem(cursor.getLong(0)!!) }, ) { override fun execute(mapper: (SqlCursor) -> R) = driver.executeQuery(1, "SELECT id FROM TestItem LIMIT ? OFFSET ?", mapper, 2) { - bindLong(0, limit.toLong()) - bindLong(1, offset.toLong()) + bindLong(0, limit) + bindLong(1, offset) } override fun addListener(listener: Listener) = driver.addListener(listener, arrayOf("TestItem")) @@ -653,6 +679,16 @@ class OffsetQueryPagingSourceTest { { it.getLong(0)!!.toInt() }, ) + private fun countQueryLong() = Query( + 2, + arrayOf("TestItem"), + driver, + "Test.sq", + "count", + "SELECT count(*) FROM TestItem", + { it.getLong(0)!! }, + ) + private fun insertItems(items: List) { items.forEach { driver.execute(0, "INSERT INTO TestItem (id) VALUES (?)", 1) { diff --git a/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt b/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt index ec90db5fcec..a65e6dd6240 100644 --- a/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt +++ b/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt @@ -19,6 +19,7 @@ import androidx.paging.PagingConfig import androidx.paging.PagingSource import app.cash.sqldelight.Query import app.cash.sqldelight.Transacter +import app.cash.sqldelight.db.SqlCursor import kotlinx.coroutines.Dispatchers import kotlin.coroutines.CoroutineContext import kotlin.properties.Delegates @@ -70,6 +71,35 @@ fun QueryPagingSource( context, ) +/** + * Variant of [QueryPagingSource] that accepts a [Long] instead of an [Int] for [countQuery] + * and [queryProvider]. + * + * If the result of [countQuery] exceeds [Int.MAX_VALUE], then the count will be truncated + * to the least significant 32 bits of this [Long] value. + * + * @see toInt + */ +@Suppress("FunctionName") +fun QueryPagingSourceLong( + countQuery: Query, + transacter: Transacter, + context: CoroutineContext = Dispatchers.IO, + queryProvider: (limit: Long, offset: Long) -> Query, +): PagingSource = OffsetQueryPagingSource( + { limit, offset -> queryProvider(limit.toLong(), offset.toLong()) }, + countQuery.toInt(), + transacter, + context, +) + +private fun Query.toInt(): Query = + object : Query({ cursor -> mapper(cursor).toInt() }) { + override fun execute(mapper: (SqlCursor) -> R) = this@toInt.execute(mapper) + override fun addListener(listener: Listener) = this@toInt.addListener(listener) + override fun removeListener(listener: Listener) = this@toInt.removeListener(listener) + } + /** * Create a [PagingSource] that pages through results according to queries generated by * [queryProvider]. Queries returned by [queryProvider] should expected to do keyset paging. From 35f38e67ecf764a4fb1f28c45fabc63175cb8fb1 Mon Sep 17 00:00:00 2001 From: Veyndan Stuart Date: Thu, 4 Aug 2022 17:28:47 +0200 Subject: [PATCH 2/2] Name function constructors the same --- .../cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt | 2 +- .../java/app/cash/sqldelight/paging3/QueryPagingSource.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt b/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt index 0348aacf18b..95eb76fc0a8 100644 --- a/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt +++ b/extensions/android-paging3/android-test/src/test/java/app/cash/sqldelight/paging3/OffsetQueryPagingSourceTest.kt @@ -631,7 +631,7 @@ class OffsetQueryPagingSourceTest { @Test fun load_initialEmptyLoad_QueryPagingSourceLong() = runTest { - val pagingSource = QueryPagingSourceLong( + val pagingSource = QueryPagingSource( countQueryLong(), transacter, EmptyCoroutineContext, diff --git a/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt b/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt index a65e6dd6240..19936d89e18 100644 --- a/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt +++ b/extensions/android-paging3/src/main/java/app/cash/sqldelight/paging3/QueryPagingSource.kt @@ -59,6 +59,7 @@ internal abstract class QueryPagingSource : * Queries will be executed on [context]. */ @Suppress("FunctionName") +@JvmName("QueryPagingSourceInt") fun QueryPagingSource( countQuery: Query, transacter: Transacter, @@ -81,7 +82,8 @@ fun QueryPagingSource( * @see toInt */ @Suppress("FunctionName") -fun QueryPagingSourceLong( +@JvmName("QueryPagingSourceLong") +fun QueryPagingSource( countQuery: Query, transacter: Transacter, context: CoroutineContext = Dispatchers.IO,