Skip to content

Commit

Permalink
Commonize
Browse files Browse the repository at this point in the history
  • Loading branch information
eygraber committed Sep 1, 2024
1 parent 7c2f77d commit 4e2d6d5
Show file tree
Hide file tree
Showing 98 changed files with 988 additions and 1,554 deletions.
21 changes: 11 additions & 10 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask

plugins {
kotlin("multiplatform")
Expand All @@ -23,28 +24,28 @@ kotlin {

sourceSets {
commonMain.dependencies {
implementation(project(":external"))

api(libs.coroutines.core)
}

commonTest.dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}

jsMain.dependencies {
implementation(project(":external"))
implementation(kotlin("test"))
implementation(libs.coroutines.test)
}

jsTest.dependencies {
implementation(kotlin("test-js"))
}

wasmJsMain.dependencies {
implementation(project(":external"))
}

wasmJsTest.dependencies {
implementation(kotlin("test-wasm-js"))
}
}
}

tasks.withType<KotlinCompilationTask<*>>().configureEach {
compilerOptions {
freeCompilerArgs.add("-Xexpect-actual-classes")
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBCursor
import com.juul.indexeddb.external.IDBCursorWithValue
import com.juul.indexeddb.external.IDBKey
import com.juul.indexeddb.external.JsAny
import kotlinx.coroutines.channels.SendChannel

public open class Cursor internal constructor(
internal open val cursor: IDBCursor,
private val channel: SendChannel<*>,
) {
public val key: JsAny
public val key: IDBKey
get() = cursor.key

public val primaryKey: JsAny
public val primaryKey: IDBKey
get() = cursor.primaryKey

public fun close() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBCursor

public sealed class CursorStart {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBDatabase
import com.juul.indexeddb.external.IDBFactory
import com.juul.indexeddb.external.IDBTransactionDurability
import com.juul.indexeddb.external.IDBTransactionOptions
import com.juul.indexeddb.external.IDBVersionChangeEvent
import com.juul.indexeddb.external.indexedDB
import kotlinx.browser.window
import com.juul.indexeddb.external.window
import com.juul.indexeddb.selfIndexedDB
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

Expand Down Expand Up @@ -91,9 +90,7 @@ public class Database internal constructor(

val transaction = Transaction(
ensureDatabase().transaction(
storeNames = ReadonlyArray(
*store.map { it.toJsString() }.toTypedArray(),
),
storeNames = store.toReadonlyArray(),
mode = "readonly",
options = IDBTransactionOptions(durability),
),
Expand Down Expand Up @@ -121,9 +118,7 @@ public class Database internal constructor(
val transaction = WriteTransaction(
ensureDatabase()
.transaction(
storeNames = ReadonlyArray(
*store.map { it.toJsString() }.toTypedArray(),
),
storeNames = store.toReadonlyArray(),
mode = "readwrite",
options = IDBTransactionOptions(durability),
),
Expand All @@ -145,6 +140,3 @@ public class Database internal constructor(
database = null
}
}

@Suppress("RedundantNullableReturnType")
private val selfIndexedDB: IDBFactory? = js("self.indexedDB || self.webkitIndexedDB")
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package com.juul.indexeddb

import org.w3c.dom.events.Event
import com.juul.indexeddb.external.Event

public abstract class EventException(
message: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBCursor
import com.juul.indexeddb.external.IDBCursorWithValue
import com.juul.indexeddb.external.IDBIndex
import com.juul.indexeddb.external.JsNumber
import com.juul.indexeddb.external.ReadonlyArray

public class Index internal constructor(
Expand All @@ -14,10 +13,16 @@ public class Index internal constructor(
override fun requestGetAll(query: Key?): Request<ReadonlyArray<*>> =
Request(index.getAll(query?.toJs()))

override fun requestOpenCursor(query: Key?, direction: Cursor.Direction): Request<IDBCursorWithValue?> =
override fun requestOpenCursor(
query: Key?,
direction: Cursor.Direction,
): Request<IDBCursorWithValue?> =
Request(index.openCursor(query?.toJs(), direction.constant))

override fun requestOpenKeyCursor(query: Key?, direction: Cursor.Direction): Request<IDBCursor?> =
override fun requestOpenKeyCursor(
query: Key?,
direction: Cursor.Direction,
): Request<IDBCursor?> =
Request(index.openKeyCursor(query?.toJs(), direction.constant))

override fun requestCount(query: Key?): Request<JsNumber> =
Expand Down
29 changes: 29 additions & 0 deletions core/src/commonMain/kotlin/JsArray.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import com.juul.indexeddb.external.JsAny
import com.juul.indexeddb.external.JsArray
import com.juul.indexeddb.external.JsString
import com.juul.indexeddb.external.ReadonlyArray
import com.juul.indexeddb.external.set
import com.juul.indexeddb.external.toJsString
import com.juul.indexeddb.toReadonlyArray

internal fun Array<out String>.toReadonlyArray(): ReadonlyArray<JsString> =
JsArray<JsString>()
.apply {
forEachIndexed { index, s ->
set(index, s.toJsString())
}
}.toReadonlyArray()

internal fun Iterable<String?>.toJsArray(): JsArray<JsString?> =
JsArray<JsString?>().apply {
forEachIndexed { index, s ->
set(index, s?.toJsString())
}
}

internal fun <T : JsAny?> JsArray(vararg values: T): JsArray<T> =
JsArray<T>().apply {
for (i in values.indices) {
set(i, values[i])
}
}
9 changes: 9 additions & 0 deletions core/src/commonMain/kotlin/Jso.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.JsAny

// Copied from:
// https://github.com/JetBrains/kotlin-wrappers/blob/91b2c1568ec6f779af5ec10d89b5e2cbdfe785ff/kotlin-extensions/src/main/kotlin/kotlinx/js/jso.kt

internal expect fun <T : JsAny> jso(): T
internal fun <T : JsAny> jso(block: T.() -> Unit): T = jso<T>().apply(block)
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBKey
import com.juul.indexeddb.external.IDBKeyRange
import org.khronos.webgl.Uint8Array

public external class Date(
value: JsString,
) : JsAny

private fun JsArray<JsAny?>.validateKeyTypes() {
for (i in 0..<length) {
@Suppress("UNCHECKED_CAST")
when (val value = get(i)) {
null, is Uint8Array, is JsString, is Date, is JsNumber, is IDBKeyRange -> continue
is JsArray<*> -> (value as JsArray<JsAny?>).validateKeyTypes()
else -> error("Illegal key: expected string, date, float, binary blob, or array of those types, but got $value.")
}
}
}
import com.juul.indexeddb.external.JsAny
import com.juul.indexeddb.external.JsArray
import com.juul.indexeddb.external.get
import com.juul.indexeddb.external.toJsString
import com.juul.indexeddb.unsafeCast
import com.juul.indexeddb.validateKeyTypes

public object AutoIncrement

Expand Down Expand Up @@ -46,6 +34,10 @@ public class Key(
internal fun toJs(): IDBKey = (if (values.length == 1) values[0]!! else values).unsafeCast()
}

public expect fun Key(value: String): Key
public expect fun Key(value: Int): Key
public expect fun Key(value: Double): Key

public fun lowerBound(
x: JsAny?,
open: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBCursor
import com.juul.indexeddb.external.IDBCursorWithValue
import com.juul.indexeddb.external.IDBObjectStore
import com.juul.indexeddb.external.JsNumber
import com.juul.indexeddb.external.ReadonlyArray

public class ObjectStore internal constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.Event
import com.juul.indexeddb.external.EventTarget
import kotlinx.coroutines.suspendCancellableCoroutine
import org.w3c.dom.events.Event
import org.w3c.dom.events.EventTarget
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

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

import com.juul.indexeddb.external.IDBFactory
import com.juul.indexeddb.external.JsAny
import com.juul.indexeddb.external.JsArray
import com.juul.indexeddb.external.JsByteArray
import com.juul.indexeddb.external.ReadonlyArray
import com.juul.indexeddb.external.toJsByteArray

internal expect val selfIndexedDB: IDBFactory?

internal expect fun <T : JsAny?> JsArray<T>.toReadonlyArray(): ReadonlyArray<T>

internal expect fun <T : JsAny?> JsAny.unsafeCast(): T

internal fun ByteArray.toJsByteArray(): JsByteArray = toTypedArray().toJsByteArray()

internal expect fun JsArray<JsAny?>.validateKeyTypes()
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.IDBCursor
import com.juul.indexeddb.external.IDBCursorWithValue
import com.juul.indexeddb.external.JsNumber
import com.juul.indexeddb.external.ReadonlyArray

public sealed class Queryable {
Expand Down
6 changes: 6 additions & 0 deletions core/src/commonMain/kotlin/Request.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import com.juul.indexeddb.external.IDBRequest
import com.juul.indexeddb.external.JsAny

internal class Request<T : JsAny?> internal constructor(
internal val request: IDBRequest<T>,
)
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.Event
import com.juul.indexeddb.external.IDBCursor
import com.juul.indexeddb.external.IDBIndexOptions
import com.juul.indexeddb.external.IDBObjectStoreOptions
import com.juul.indexeddb.external.IDBRequest
import com.juul.indexeddb.external.IDBTransaction
import com.juul.indexeddb.external.JsAny
import com.juul.indexeddb.external.ReadonlyArray
import com.juul.indexeddb.external.toInt
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import org.w3c.dom.events.Event

public open class Transaction internal constructor(
internal val transaction: IDBTransaction,
Expand Down Expand Up @@ -160,12 +161,12 @@ public open class Transaction internal constructor(
}
}

public suspend fun Queryable.count(query: Key? = null): JsNumber {
public suspend fun Queryable.count(query: Key? = null): Int {
val request = requestCount(query).request
return request.onNextEvent("success", "error") { event ->
when (event.type) {
"error" -> throw ErrorEventException(event)
else -> request.result
else -> request.result.toInt()
}
}
}
Expand Down Expand Up @@ -310,15 +311,15 @@ public class VersionChangeTransaction internal constructor(
ensureDatabase()
.createObjectStore(
name = name,
options = IDBObjectStoreOptions(
autoIncrement = false,
keyPath = keyPath.toJs(),
),
options = IDBObjectStoreOptions(keyPath = keyPath.toJs()),
),
)

/** Creates an object-store that uses out-of-line keys with a key-generator. */
public fun Database.createObjectStore(name: String, autoIncrement: AutoIncrement): ObjectStore =
public fun Database.createObjectStore(
name: String,
@Suppress("UNUSED_PARAMETER") autoIncrement: AutoIncrement,
): ObjectStore =
ObjectStore(
ensureDatabase()
.createObjectStore(
Expand All @@ -332,7 +333,7 @@ public class VersionChangeTransaction internal constructor(
}

public fun ObjectStore.createIndex(name: String, keyPath: KeyPath, unique: Boolean): Index =
Index(objectStore.createIndex(name, keyPath.toJs(), jso { this.unique = unique }))
Index(objectStore.createIndex(name, keyPath.toJs(), IDBIndexOptions { this.unique = unique }))

public fun ObjectStore.deleteIndex(name: String) {
objectStore.deleteIndex(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.juul.indexeddb

import com.juul.indexeddb.external.JsAny
import com.juul.indexeddb.jso
import com.juul.indexeddb.unsafeCast
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals

private external interface User : JsAny {
var username: JsString
var username: String
}

class AutoIncrementKeyObjectStore {
Expand All @@ -15,20 +17,19 @@ class AutoIncrementKeyObjectStore {
database.createObjectStore("users", AutoIncrement)
}
}
onCleanup {
database.close()
deleteDatabase("auto-increment-keys")
}

val id = database.writeTransaction("users") {
objectStore("users").add(jso<User> { username = "Username".toJsString() })
objectStore("users").add(jso<User> { username = "Username" })
}

val user = database.transaction("users") {
objectStore("users")
.get(Key(id))
?.unsafeCast<User>()
}
assertEquals("Username", user?.username?.toString())
assertEquals("Username", user?.username)

database.close()
deleteDatabase("auto-increment-keys")
}
}
Loading

0 comments on commit 4e2d6d5

Please sign in to comment.