Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix deleteDatabase blocking due to open connections #144

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions core/src/jsMain/kotlin/Database.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,25 @@ 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) {
private var database: IDBDatabase? = database

init {
// listen for database structure changes (e.g., upgradeneeded while DB is open or deleteDatabase)
database.addEventListener("versionchange", { close() })
// listen for force close, e.g., browser profile on a USB drive that's ejected or db deleted through dev tools
database.addEventListener("close", { close() })
}

internal fun ensureDatabase(): IDBDatabase = checkNotNull(database) { "database is closed" }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea, love that it gives us a description


/**
* Inside the [action] block, you must not call any `suspend` functions except for:
Expand All @@ -68,7 +78,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)),
ensureDatabase().transaction(arrayOf(*store), "readonly", transactionOptions(durability)),
)
val result = transaction.action()
transaction.awaitCompletion()
Expand All @@ -87,7 +97,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)),
ensureDatabase().transaction(arrayOf(*store), "readwrite", transactionOptions(durability)),
)
with(transaction) {
// Force overlapping transactions to not call `action` until prior transactions complete.
Expand All @@ -101,7 +111,8 @@ public class Database internal constructor(internal val database: IDBDatabase) {
}

public fun close() {
database.close()
database?.close()
database = null
}
}

Expand Down
8 changes: 4 additions & 4 deletions core/src/jsMain/kotlin/Transaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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(ensureDatabase().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(ensureDatabase().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(ensureDatabase().createObjectStore(name, autoIncrement.toJs()))

public fun Database.deleteObjectStore(name: String) {
database.deleteObjectStore(name)
ensureDatabase().deleteObjectStore(name)
}

public fun ObjectStore.createIndex(name: String, keyPath: KeyPath, unique: Boolean): Index =
Expand Down