From ead7323bd8029ff40819e80119a18ac3c8c2976f Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski Date: Tue, 23 Jan 2024 10:37:48 +0100 Subject: [PATCH] Fix deleteDatabase blocking due to open connections - Automatically close database connections on delete - Handle "blocked" event in deleteDatabase --- core/src/jsMain/kotlin/Database.kt | 19 +++++++++++++------ core/src/jsMain/kotlin/Transaction.kt | 8 ++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/core/src/jsMain/kotlin/Database.kt b/core/src/jsMain/kotlin/Database.kt index 4c6c9bd..eb23b22 100644 --- a/core/src/jsMain/kotlin/Database.kt +++ b/core/src/jsMain/kotlin/Database.kt @@ -46,15 +46,21 @@ public suspend fun openDatabase( public suspend fun deleteDatabase(name: String) { val factory = checkNotNull(window.indexedDB) { "Your browser doesn't support IndexedDB." } val request = factory.deleteDatabase(name) - request.onNextEvent("success", "error") { event -> + request.onNextEvent("success", "error", "blocked") { event -> when (event.type) { - "error" -> throw ErrorEventException(event) + "error", "blocked" -> throw ErrorEventException(event) else -> null } } } -public class Database internal constructor(internal val database: IDBDatabase) { +public class Database internal constructor(database: IDBDatabase) { + internal var database: IDBDatabase? = database + + init { + database.addEventListener("versionchange", { close() }) + database.addEventListener("close", { close() }) + } /** * Inside the [action] block, you must not call any `suspend` functions except for: @@ -68,7 +74,7 @@ public class Database internal constructor(internal val database: IDBDatabase) { action: suspend Transaction.() -> T, ): T = withContext(Dispatchers.Unconfined) { val transaction = Transaction( - database.transaction(arrayOf(*store), "readonly", transactionOptions(durability)), + database!!.transaction(arrayOf(*store), "readonly", transactionOptions(durability)), ) val result = transaction.action() transaction.awaitCompletion() @@ -87,7 +93,7 @@ public class Database internal constructor(internal val database: IDBDatabase) { action: suspend WriteTransaction.() -> T, ): T = withContext(Dispatchers.Unconfined) { val transaction = WriteTransaction( - database.transaction(arrayOf(*store), "readwrite", transactionOptions(durability)), + database!!.transaction(arrayOf(*store), "readwrite", transactionOptions(durability)), ) with(transaction) { // Force overlapping transactions to not call `action` until prior transactions complete. @@ -101,7 +107,8 @@ public class Database internal constructor(internal val database: IDBDatabase) { } public fun close() { - database.close() + database?.close() + database = null } } diff --git a/core/src/jsMain/kotlin/Transaction.kt b/core/src/jsMain/kotlin/Transaction.kt index 58ee691..37440ec 100644 --- a/core/src/jsMain/kotlin/Transaction.kt +++ b/core/src/jsMain/kotlin/Transaction.kt @@ -300,18 +300,18 @@ public class VersionChangeTransaction internal constructor( /** Creates an object-store that uses explicit out-of-line keys. */ public fun Database.createObjectStore(name: String): ObjectStore = - ObjectStore(database.createObjectStore(name)) + 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())) + 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())) + ObjectStore(database!!.createObjectStore(name, autoIncrement.toJs())) public fun Database.deleteObjectStore(name: String) { - database.deleteObjectStore(name) + database!!.deleteObjectStore(name) } public fun ObjectStore.createIndex(name: String, keyPath: KeyPath, unique: Boolean): Index =