Skip to content

Commit

Permalink
#78: add support for out-of-line keys (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
cedrickcooke authored Nov 16, 2022
1 parent 67faae2 commit 936d692
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
build/
.DS_Store
local.properties
yarn.lock
64 changes: 56 additions & 8 deletions core/src/jsMain/kotlin/Transaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -158,37 +158,78 @@ public open class WriteTransaction internal constructor(
) : Transaction(transaction) {

/**
* Adds a new item to the database. If an item with the same key already exists, this will fail.
* Adds a new item to the database using an in-line or auto-incrementing key. If an item with the same
* key already exists, this will fail.
*
* This API is delicate. If you're passing in Kotlin objects directly, you're probably doing it wrong.
*
* Generally, you'll want to create an explicit `external interface` and pass that in, to guarantee that Kotlin
* doesn't mangle, prefix, or otherwise mess with your field names.
*/
public suspend fun ObjectStore.add(item: dynamic) {
public suspend fun ObjectStore.add(item: dynamic): dynamic {
val request = objectStore.add(item)
request.onNextEvent("success", "error") { event ->
return request.onNextEvent("success", "error") { event ->
when (event.type) {
"error" -> throw ErrorEventException(event)
else -> Unit
else -> request.result
}
}
}

/**
* Adds a new item to the database using an explicit out-of-line key. If an item with the same key already
* exists, this will fail.
*
* This API is delicate. If you're passing in Kotlin objects directly, you're probably doing it wrong.
*
* Generally, you'll want to create an explicit `external interface` and pass that in, to guarantee that Kotlin
* doesn't mangle, prefix, or otherwise mess with your field names.
*/
public suspend fun ObjectStore.add(item: dynamic, key: Key): dynamic {
val request = objectStore.add(item, key.toJs())
return request.onNextEvent("success", "error") { event ->
when (event.type) {
"error" -> throw ErrorEventException(event)
else -> request.result
}
}
}

/**
* Adds an item to, or updates an item in, the database. If an item with the same key already exists, this will replace that item.
* Adds an item to or updates an item in the database using an in-line or auto-incrementing key. If an item
* with the same key already exists, this will replace that item. Note that with auto-incrementing keys a new
* item will always be inserted.
*
* This API is delicate. If you're passing in Kotlin objects directly, you're probably doing it wrong.
*
* Generally, you'll want to create an explicit `external interface` and pass that in, to guarantee that Kotlin
* doesn't mangle, prefix, or otherwise mess with your field names.
*/
public suspend fun ObjectStore.put(item: dynamic) {
public suspend fun ObjectStore.put(item: dynamic): dynamic {
val request = objectStore.put(item)
request.onNextEvent("success", "error") { event ->
return request.onNextEvent("success", "error") { event ->
when (event.type) {
"error" -> throw ErrorEventException(event)
else -> Unit
else -> request.result
}
}
}

/**
* Adds an item to or updates an item in the database using an explicit out-of-line key. If an item with the
* same key already exists, this will replace that item.
*
* This API is delicate. If you're passing in Kotlin objects directly, you're probably doing it wrong.
*
* Generally, you'll want to create an explicit `external interface` and pass that in, to guarantee that Kotlin
* doesn't mangle, prefix, or otherwise mess with your field names.
*/
public suspend fun ObjectStore.put(item: dynamic, key: Key): dynamic {
val request = objectStore.put(item, key.toJs())
return request.onNextEvent("success", "error") { event ->
when (event.type) {
"error" -> throw ErrorEventException(event)
else -> request.result
}
}
}
Expand Down Expand Up @@ -237,9 +278,16 @@ public open class WriteTransaction internal constructor(
public class VersionChangeTransaction internal constructor(
transaction: IDBTransaction,
) : WriteTransaction(transaction) {

/** Creates an object-store that uses explicit out-of-line keys. */
public fun Database.createObjectStore(name: String): ObjectStore =
ObjectStore(database.createObjectStore(name))

/** Creates an object-store that uses in-line keys. */
public fun Database.createObjectStore(name: String, keyPath: KeyPath): ObjectStore =
ObjectStore(database.createObjectStore(name, keyPath.toWrappedJs()))

/** Creates an object-store that uses out-of-line keys with a key-generator. */
public fun Database.createObjectStore(name: String, autoIncrement: AutoIncrement): ObjectStore =
ObjectStore(database.createObjectStore(name, autoIncrement.toJs()))

Expand Down
30 changes: 30 additions & 0 deletions core/src/jsTest/kotlin/AutoIncrementKeyObjectStore.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.juul.indexeddb

import kotlin.test.Test
import kotlin.test.assertEquals

class AutoIncrementKeyObjectStore {

@Test
fun simpleReadWrite() = runTest {
val database = openDatabase("auto-increment-keys", 1) { database, oldVersion, newVersion ->
if (oldVersion < 1) {
database.createObjectStore("users", AutoIncrement)
}
}
onCleanup {
database.close()
deleteDatabase("auto-increment-keys")
}

val id = database.writeTransaction("users") {
objectStore("users").add(jso { username = "Username" }) as Double
}

val user = database.transaction("users") {
objectStore("users")
.get(Key(id))
}
assertEquals("Username", user.username)
}
}
30 changes: 30 additions & 0 deletions core/src/jsTest/kotlin/InLineKeyObjectStore.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.juul.indexeddb

import kotlin.test.Test
import kotlin.test.assertEquals

class InLineKeyObjectStore {

@Test
fun simpleReadWrite() = runTest {
val database = openDatabase("in-line-keys", 1) { database, oldVersion, newVersion ->
if (oldVersion < 1) {
database.createObjectStore("users", KeyPath("id"))
}
}
onCleanup {
database.close()
deleteDatabase("in-line-keys")
}

database.writeTransaction("users") {
objectStore("users").add(jso { id = "7740f7c4-f889-498a-bc6d-f88dabdcfb9a"; username = "Username" })
}

val user = database.transaction("users") {
objectStore("users")
.get(Key("7740f7c4-f889-498a-bc6d-f88dabdcfb9a"))
}
assertEquals("Username", user.username)
}
}
30 changes: 30 additions & 0 deletions core/src/jsTest/kotlin/OutOfLineKeyObjectStore.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.juul.indexeddb

import kotlin.test.Test
import kotlin.test.assertEquals

class OutOfLineKeyObjectStore {

@Test
fun simpleReadWrite() = runTest {
val database = openDatabase("out-of-line-keys", 1) { database, oldVersion, newVersion ->
if (oldVersion < 1) {
database.createObjectStore("users")
}
}
onCleanup {
database.close()
deleteDatabase("out-of-line-keys")
}

database.writeTransaction("users") {
objectStore("users").add(jso { username = "Username" }, Key("7740f7c4-f889-498a-bc6d-f88dabdcfb9a"))
}

val user = database.transaction("users") {
objectStore("users")
.get(Key("7740f7c4-f889-498a-bc6d-f88dabdcfb9a"))
}
assertEquals("Username", user.username)
}
}
1 change: 1 addition & 0 deletions external/src/jsMain/kotlin/IDBDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public external class IDBDatabase : EventTarget {
public val version: Int
public val objectStoreNames: Array<String>
public fun close()
public fun createObjectStore(name: String): IDBObjectStore
public fun createObjectStore(name: String, options: dynamic): IDBObjectStore
public fun deleteObjectStore(name: String)
public fun transaction(storeNames: Array<String>, mode: String): IDBTransaction
Expand Down

0 comments on commit 936d692

Please sign in to comment.