Skip to content

Commit

Permalink
Add a native implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
eygraber committed Jun 16, 2024
1 parent 97aa3ea commit 7c89bfc
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 269 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.squareup.okhttp3:okhttp") {
version {
strictly '4.4.1'
}
}

classpath(libs.atomicfu.plugin)
}
}

Expand Down
42 changes: 15 additions & 27 deletions drivers/androidx-sqlite-driver/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,22 @@ plugins {
alias(libs.plugins.dokka)
id("app.cash.sqldelight.toolchain.runtime")
alias(libs.plugins.binaryCompatibilityValidator)
alias(libs.plugins.atomicfu)
}

archivesBaseName = 'sqldelight-kmp-driver'

kotlin {
// tier 1
// there is only tier 1 support for androidx.sqlite:sqlite-bundled
// https://maven.google.com/web/index.html?q=bundled#androidx.sqlite
androidTarget()
jvm()
// linuxX64()
// macosX64()
// macosArm64()
// iosSimulatorArm64()
// iosX64()

// tier 2
// linuxArm64()
// watchosSimulatorArm64()
// watchosX64()
// watchosArm32()
// watchosArm64()
// tvosSimulatorArm64()
// tvosX64()
// tvosArm64()
// iosArm64()

// tier 3
// https://github.com/touchlab/SQLiter/issues/117
// androidNativeArm32()
// androidNativeArm64()
// androidNativeX86()
// androidNativeX64()
// https://developer.android.com/kotlin/multiplatform/sqlite#driver_implementations
// mingwX64()
// watchosDeviceArm64()
linuxX64()
macosX64()
macosArm64()
iosSimulatorArm64()
iosArm64()
iosX64()

sourceSets {
commonMain {
Expand Down Expand Up @@ -71,6 +53,12 @@ kotlin {
implementation libs.androidx.sqliteBundled
}
}

nativeTest {
dependencies {
implementation libs.androidx.sqliteBundled
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.cash.sqldelight.driver.androidx.sqlite

import app.cash.sqldelight.Transacter

internal actual class TransactionsThreadLocal actual constructor() {
private val transactions = ThreadLocal<Transacter.Transaction>()

internal actual fun get(): Transacter.Transaction? = transactions.get()

internal actual fun set(transaction: Transacter.Transaction?) {
transactions.set(transaction)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package app.cash.sqldelight.driver.androidx.sqlite

import androidx.sqlite.SQLiteDriver
import androidx.sqlite.driver.AndroidSQLiteDriver
import app.cash.sqldelight.Transacter
import com.squareup.sqldelight.driver.test.DriverTest
import com.squareup.sqldelight.driver.test.QueryTest
import com.squareup.sqldelight.driver.test.TransacterTest
import java.util.concurrent.Semaphore
import org.junit.Assert
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
actual abstract class CommonDriverTest : DriverTest()

@RunWith(RobolectricTestRunner::class)
actual abstract class CommonQueryTest : QueryTest()

@RunWith(RobolectricTestRunner::class)
actual abstract class CommonTransacterTest : TransacterTest()

actual fun androidxSqliteTestDriver(): SQLiteDriver = AndroidSQLiteDriver()

actual inline fun <T> assertChecksThreadConfinement(
transacter: Transacter,
crossinline scope: Transacter.(T.() -> Unit) -> Unit,
crossinline block: T.() -> Unit,
) {
lateinit var thread: Thread
var result: Result<Unit>? = null
val semaphore = Semaphore(0)

transacter.scope {
thread = kotlin.concurrent.thread {
result = runCatching {
this@scope.block()
}

semaphore.release()
}
}

semaphore.acquire()
thread.interrupt()
Assert.assertThrows(IllegalStateException::class.java) {
result!!.getOrThrow()
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import app.cash.sqldelight.db.SqlPreparedStatement
import app.cash.sqldelight.db.SqlSchema
import io.github.reactivecircus.cache4k.Cache
import io.github.reactivecircus.cache4k.CacheEvent
import kotlinx.atomicfu.locks.SynchronizedObject
import kotlinx.atomicfu.locks.synchronized

internal expect class TransactionsThreadLocal() {
internal fun get(): Transacter.Transaction?
internal fun set(transaction: Transacter.Transaction?)
}

internal const val DEFAULT_CACHE_SIZE = 20

Expand All @@ -28,7 +35,7 @@ class AndroidxSqliteDriver(
name: String?,
cacheSize: Int = DEFAULT_CACHE_SIZE,
) : SqlDriver {
private val transactions = ThreadLocal<Transacter.Transaction>()
private val transactions = TransactionsThreadLocal()
private val connection by lazy {
driver.open(name ?: ":memory:")
}
Expand All @@ -46,18 +53,19 @@ class AndroidxSqliteDriver(
}
.build()

private val listenersLock = SynchronizedObject()
private val listeners = linkedMapOf<String, MutableSet<Query.Listener>>()

override fun addListener(vararg queryKeys: String, listener: Query.Listener) {
synchronized(listeners) {
synchronized(listenersLock) {
queryKeys.forEach {
listeners.getOrPut(it) { linkedSetOf() }.add(listener)
}
}
}

override fun removeListener(vararg queryKeys: String, listener: Query.Listener) {
synchronized(listeners) {
synchronized(listenersLock) {
queryKeys.forEach {
listeners[it]?.remove(listener)
}
Expand All @@ -66,7 +74,7 @@ class AndroidxSqliteDriver(

override fun notifyListeners(vararg queryKeys: String) {
val listenersToNotify = linkedSetOf<Query.Listener>()
synchronized(listeners) {
synchronized(listenersLock) {
queryKeys.forEach { listeners[it]?.let(listenersToNotify::addAll) }
}
listenersToNotify.forEach(Query.Listener::queryResultsChanged)
Expand Down
Loading

0 comments on commit 7c89bfc

Please sign in to comment.