Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.6.0 (unreleased)

* Remove internal SQLDelight and SQLiter dependencies.
* Add `rawConnection` getter to `ConnectionContext`, which is a `SQLiteConnection` instance from
`androidx.sqlite` that can be used to step through statements in a custom way.

## 1.5.0

* Add `PowerSyncDatabase.getCrudTransactions()`, returning a flow of transactions. This is useful
Expand Down
2 changes: 0 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ plugins {
alias(libs.plugins.skie) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.sqldelight) apply false
alias(libs.plugins.grammarKitComposer) apply false
alias(libs.plugins.mavenPublishPlugin) apply false
alias(libs.plugins.downloadPlugin) apply false
alias(libs.plugins.kotlinter) apply false
Expand Down
1 change: 0 additions & 1 deletion compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ kotlin {
sourceSets {
commonMain.dependencies {
api(project(":core"))
implementation(project(":persistence"))
implementation(compose.runtime)
}
androidMain.dependencies {
Expand Down
94 changes: 29 additions & 65 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,60 +74,6 @@ val downloadPowersyncDesktopBinaries by tasks.registering(Download::class) {
onlyIfModified(true)
}

val sqliteJDBCFolder =
project.layout.buildDirectory
.dir("jdbc")
.get()

val jniLibsFolder = layout.projectDirectory.dir("src/androidMain/jni")

val downloadJDBCJar by tasks.registering(Download::class) {
val version =
libs.versions.sqlite.jdbc
.get()
val jar =
"https://github.com/xerial/sqlite-jdbc/releases/download/$version/sqlite-jdbc-$version.jar"

src(jar)
dest(sqliteJDBCFolder.file("jdbc.jar"))
onlyIfModified(true)
}

val extractJDBCJNI by tasks.registering(Copy::class) {
dependsOn(downloadJDBCJar)

from(
zipTree(downloadJDBCJar.get().dest).matching {
include("org/sqlite/native/Linux-Android/**")
},
)

into(sqliteJDBCFolder.dir("jni"))
}

val moveJDBCJNIFiles by tasks.registering(Copy::class) {
dependsOn(extractJDBCJNI)

val abiMapping =
mapOf(
"aarch64" to "arm64-v8a",
"arm" to "armeabi-v7a",
"x86_64" to "x86_64",
"x86" to "x86",
)

abiMapping.forEach { (sourceABI, androidABI) ->
from(sqliteJDBCFolder.dir("jni/org/sqlite/native/Linux-Android/$sourceABI")) {
include("*.so")
eachFile {
path = "$androidABI/$name"
}
}
}

into(jniLibsFolder) // Move everything into the base jniLibs folder
}

val generateVersionConstant by tasks.registering {
val target = project.layout.buildDirectory.dir("generated/constants")
val packageName = "com.powersync.build"
Expand Down Expand Up @@ -172,6 +118,12 @@ kotlin {
headers(file("src/watchosMain/powersync_static.h"))
}
}

cinterops.create("sqlite3") {
packageName("com.powersync.internal.sqlite3")
includeDirs.allHeaders("src/nativeMain/interop/")
definitionFile.set(project.file("src/nativeMain/interop/sqlite3.def"))
}
}
}

Expand All @@ -183,6 +135,7 @@ kotlin {
languageSettings {
optIn("kotlinx.cinterop.ExperimentalForeignApi")
optIn("kotlin.time.ExperimentalTime")
optIn("kotlin.experimental.ExperimentalObjCRefinement")
}
}

Expand All @@ -192,9 +145,6 @@ kotlin {

val commonJava by creating {
dependsOn(commonMain.get())
dependencies {
implementation(libs.sqlite.jdbc)
}
}

commonMain.configure {
Expand All @@ -203,6 +153,8 @@ kotlin {
}

dependencies {
api(libs.androidx.sqlite.sqlite)

implementation(libs.uuid)
implementation(libs.kotlin.stdlib)
implementation(libs.ktor.client.contentnegotiation)
Expand All @@ -212,29 +164,47 @@ kotlin {
implementation(libs.kotlinx.datetime)
implementation(libs.stately.concurrency)
implementation(libs.configuration.annotations)
api(projects.persistence)
api(libs.ktor.client.core)
api(libs.kermit)
}
}

androidMain {
dependsOn(commonJava)
dependencies.implementation(libs.ktor.client.okhttp)
dependencies {
implementation(libs.ktor.client.okhttp)
implementation(libs.androidx.sqlite.bundled)
}
}

jvmMain {
dependsOn(commonJava)

dependencies {
implementation(libs.ktor.client.okhttp)
implementation(libs.androidx.sqlite.bundled)
}
}

appleMain.dependencies {
implementation(libs.ktor.client.darwin)

// We're not using the bundled SQLite library for Apple platforms. Instead, we depend on
// static-sqlite-driver to link SQLite and have our own bindings implementing the
// driver. The reason for this is that androidx.sqlite-bundled causes linker errors for
// our Swift SDK.
implementation(projects.staticSqliteDriver)
}

// Common apple targets where we link the core extension dynamically
val appleNonWatchOsMain by creating {
dependsOn(appleMain.get())
}

macosMain.orNull?.dependsOn(appleNonWatchOsMain)
iosMain.orNull?.dependsOn(appleNonWatchOsMain)
tvosMain.orNull?.dependsOn(appleNonWatchOsMain)

commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.test.coroutines)
Expand Down Expand Up @@ -294,12 +264,6 @@ android {
ndkVersion = "27.1.12297006"
}

androidComponents.onVariants {
tasks.named("preBuild") {
dependsOn(moveJDBCJNIFiles)
}
}

tasks.named<ProcessResources>(kotlin.jvm().compilations["main"].processResourcesTaskName) {
from(downloadPowersyncDesktopBinaries)
}
Expand Down
13 changes: 0 additions & 13 deletions core/proguard-rules.pro

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,79 +1,23 @@
package com.powersync

import android.content.Context
import com.powersync.db.JdbcSqliteDriver
import com.powersync.db.buildDefaultWalProperties
import com.powersync.db.internal.InternalSchema
import com.powersync.db.migrateDriver
import kotlinx.coroutines.CoroutineScope
import org.sqlite.SQLiteCommitListener
import java.util.concurrent.atomic.AtomicBoolean
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.driver.bundled.BundledSQLiteDriver

@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
public actual class DatabaseDriverFactory(
private val context: Context,
) {
internal actual fun createDriver(
scope: CoroutineScope,
dbFilename: String,
dbDirectory: String?,
readOnly: Boolean,
): PsSqlDriver {
val schema = InternalSchema
private val driver = BundledSQLiteDriver().also { it.addPowerSyncExtension() }

val dbPath =
if (dbDirectory != null) {
"$dbDirectory/$dbFilename"
} else {
context.getDatabasePath(dbFilename)
}
internal actual fun resolveDefaultDatabasePath(dbFilename: String): String = context.getDatabasePath(dbFilename).path

val properties = buildDefaultWalProperties(readOnly = readOnly)
val isFirst = IS_FIRST_CONNECTION.getAndSet(false)
if (isFirst) {
// Make sure the temp_store_directory points towards a temporary directory we actually
// have access to. Due to sandboxing, the default /tmp/ is inaccessible.
// The temp_store_directory pragma is deprecated and not thread-safe, so we only set it
// on the first connection (it sets a global field and will affect every connection
// opened).
val escapedPath = context.cacheDir.absolutePath.replace("\"", "\"\"")
properties.setProperty("temp_store_directory", "\"$escapedPath\"")
}

val driver =
JdbcSqliteDriver(
url = "jdbc:sqlite:$dbPath",
properties = properties,
)

migrateDriver(driver, schema)

driver.loadExtensions(
"libpowersync.so" to "sqlite3_powersync_init",
)

val mappedDriver = PsSqlDriver(driver = driver)

driver.connection.database.addUpdateListener { _, _, table, _ ->
mappedDriver.updateTable(table)
}

driver.connection.database.addCommitListener(
object : SQLiteCommitListener {
override fun onCommit() {
// We track transactions manually
}

override fun onRollback() {
mappedDriver.clearTableUpdates()
}
},
)

return mappedDriver
}
internal actual fun openConnection(
path: String,
openFlags: Int,
): SQLiteConnection = driver.open(path, openFlags)
}

private companion object {
val IS_FIRST_CONNECTION = AtomicBoolean(true)
}
public fun BundledSQLiteDriver.addPowerSyncExtension() {
addExtension("libpowersync.so", "sqlite3_powersync_init")
}
Loading