/
QueryPagingSource.kt
67 lines (52 loc) · 1.7 KB
/
QueryPagingSource.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.fededri.kmmfts
import app.cash.sqldelight.Query
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
data class LoadResult<T>(
val data: List<T>,
val nextKey: Int?
)
class QueryPagingSource<T : Any>(
private val countQuery: Query<Long>,
private val searchQueryGetter: (offset: Long, limit: Int) -> Query<T>,
private val pageSize: Int
) {
private var backingCount: Long = -1
private val mutex = Mutex()
private val loadedPages: MutableMap<Int, List<T>> = mutableMapOf()
private var callback: ((Int) -> Unit)? = null
suspend fun load(pageNumber: Int): LoadResult<T> {
if (count() == 0L) return LoadResult(emptyList(), null)
val moreData = pageNumber <= (count() / pageSize)
val page = mutex.withLock {
val savedPage = loadedPages[pageNumber]
if (savedPage != null) return@withLock savedPage
val page = searchQueryGetter(getOffset(pageNumber), pageSize).executeAsList()
loadedPages[pageNumber] = page
page
}
callback?.invoke(pageNumber)
return if (moreData) {
LoadResult(page, pageNumber + 1)
} else {
LoadResult(page, null)
}
}
private fun getOffset(pageNumber: Int): Long {
return if (pageNumber == 1) {
0L
} else {
pageNumber.toLong() * pageSize
}
}
fun setLoadCallback(callback: (index: Int) -> Unit) {
this.callback = callback
}
suspend fun count(): Long {
if (backingCount < 0) {
val count = countQuery.executeAsOne()
backingCount = count
}
return backingCount
}
}