diff --git a/core/src/jsMain/kotlin/CursorStart.kt b/core/src/jsMain/kotlin/CursorStart.kt new file mode 100644 index 0000000..6270b3c --- /dev/null +++ b/core/src/jsMain/kotlin/CursorStart.kt @@ -0,0 +1,26 @@ +package com.juul.indexeddb + +import com.juul.indexeddb.external.IDBCursor + +public sealed class CursorStart { + + internal abstract fun apply(cursor: IDBCursor) + + public data class Advance(val count: Int) : CursorStart() { + override fun apply(cursor: IDBCursor) { + cursor.advance(count) + } + } + + public data class Continue(val key: Key) : CursorStart() { + override fun apply(cursor: IDBCursor) { + cursor.`continue`(key.toJs()) + } + } + + public data class ContinuePrimaryKey(val key: Key, val primaryKey: Key) : CursorStart() { + override fun apply(cursor: IDBCursor) { + cursor.continuePrimaryKey(key.toJs(), primaryKey.toJs()) + } + } +} diff --git a/core/src/jsMain/kotlin/Transaction.kt b/core/src/jsMain/kotlin/Transaction.kt index 578f788..8a5203d 100644 --- a/core/src/jsMain/kotlin/Transaction.kt +++ b/core/src/jsMain/kotlin/Transaction.kt @@ -49,9 +49,11 @@ public open class Transaction internal constructor( public suspend fun Queryable.openCursor( query: Key? = null, direction: Cursor.Direction = Cursor.Direction.Next, + cursorStart: CursorStart? = null, ): Flow = openCursorImpl( query, direction, + cursorStart, open = this::requestOpenCursor, wrap = ::CursorWithValue, ) @@ -59,9 +61,11 @@ public open class Transaction internal constructor( public suspend fun Queryable.openKeyCursor( query: Key? = null, direction: Cursor.Direction = Cursor.Direction.Next, + cursorStart: CursorStart? = null, ): Flow = openCursorImpl( query, direction, + cursorStart, open = this::requestOpenKeyCursor, wrap = ::Cursor, ) @@ -70,14 +74,19 @@ public open class Transaction internal constructor( private suspend fun openCursorImpl( query: Key?, direction: Cursor.Direction, + cursorStart: CursorStart?, open: (Key?, Cursor.Direction) -> Request, wrap: (U) -> T, ): Flow = callbackFlow { + var cursorStartAction = cursorStart val request = open(query, direction).request val onSuccess: (Event) -> Unit = { event -> @Suppress("UNCHECKED_CAST") val cursor = (event.target as IDBRequest).result - if (cursor != null) { + if (cursorStartAction != null && cursor != null) { + cursorStartAction?.apply(cursor) + cursorStartAction = null + } else if (cursor != null) { val result = trySend(wrap(cursor)) when { result.isSuccess -> cursor.`continue`() diff --git a/core/src/jsTest/kotlin/Samples.kt b/core/src/jsTest/kotlin/Samples.kt index b098e00..974fc31 100644 --- a/core/src/jsTest/kotlin/Samples.kt +++ b/core/src/jsTest/kotlin/Samples.kt @@ -2,6 +2,7 @@ package com.juul.indexeddb import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList import kotlin.test.Test import kotlin.test.assertEquals @@ -68,5 +69,25 @@ class Samples { objectStore("customers").index("age").count(upperBound(32)) } assertEquals(2, countBelowThirtyTwo) + + val skipTwoYoungest = database.transaction("customers") { + objectStore("customers") + .index("age") + .openCursor(cursorStart = CursorStart.Advance(2)) + .map { it.value as Customer } + .map { it.name } + .toList() + } + assertEquals(listOf("Alice", "Bill"), skipTwoYoungest) + + val skipUntil33 = database.transaction("customers") { + objectStore("customers") + .index("age") + .openCursor(cursorStart = CursorStart.Continue(Key(33))) + .map { it.value as Customer } + .map { it.name } + .toList() + } + assertEquals(listOf("Alice", "Bill"), skipUntil33) } } diff --git a/external/src/jsMain/kotlin/IDBCursor.kt b/external/src/jsMain/kotlin/IDBCursor.kt index 5a9322e..eb7b913 100644 --- a/external/src/jsMain/kotlin/IDBCursor.kt +++ b/external/src/jsMain/kotlin/IDBCursor.kt @@ -6,6 +6,12 @@ public external interface IDBCursor { public val primaryKey: dynamic public fun `continue`() + + public fun advance(count: Int) + + public fun `continue`(key: dynamic) + + public fun continuePrimaryKey(key: dynamic, primaryKey: dynamic) } /** https://developer.mozilla.org/en-US/docs/Web/API/IDBCursorWithValue */