diff --git a/CHANGELOG.md b/CHANGELOG.md index a1904367..8d7822e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog +## 1.0.0-BETA23 + +* Make `execute` and `PowerSyncTransaction` functions throwable for Swift + ## 1.0.0-BETA22 + * Fix `updateHasSynced` internal null pointer exception ## 1.0.0-BETA21 diff --git a/core/src/commonMain/kotlin/com/powersync/db/PowerSyncDatabaseImpl.kt b/core/src/commonMain/kotlin/com/powersync/db/PowerSyncDatabaseImpl.kt index f99340e1..b7a7d5dc 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/PowerSyncDatabaseImpl.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/PowerSyncDatabaseImpl.kt @@ -13,7 +13,7 @@ import com.powersync.db.crud.CrudRow import com.powersync.db.crud.CrudTransaction import com.powersync.db.internal.InternalDatabaseImpl import com.powersync.db.internal.InternalTable -import com.powersync.db.internal.PowerSyncTransaction +import com.powersync.db.internal.ThrowableTransactionCallback import com.powersync.db.schema.Schema import com.powersync.sync.SyncStatus import com.powersync.sync.SyncStream @@ -164,9 +164,9 @@ internal class PowerSyncDatabaseImpl( } override suspend fun getNextCrudTransaction(): CrudTransaction? { - return internalDb.readTransaction { + return internalDb.readTransaction { transaction -> val entry = - bucketStorage.nextCrudItem(this) + bucketStorage.nextCrudItem(transaction) ?: return@readTransaction null val txId = entry.transactionId @@ -222,9 +222,9 @@ internal class PowerSyncDatabaseImpl( mapper: (SqlCursor) -> RowType, ): Flow> = internalDb.watch(sql, parameters, mapper) - override suspend fun readTransaction(callback: (tx: PowerSyncTransaction) -> R): R = internalDb.writeTransaction(callback) + override suspend fun readTransaction(callback: ThrowableTransactionCallback): R = internalDb.writeTransaction(callback) - override suspend fun writeTransaction(callback: (tx: PowerSyncTransaction) -> R): R = internalDb.writeTransaction(callback) + override suspend fun writeTransaction(callback: ThrowableTransactionCallback): R = internalDb.writeTransaction(callback) override suspend fun execute( sql: String, @@ -235,16 +235,16 @@ internal class PowerSyncDatabaseImpl( lastTransactionId: Int, writeCheckpoint: String?, ) { - internalDb.writeTransaction { + internalDb.writeTransaction { transaction -> internalDb.queries.deleteEntriesWithIdLessThan(lastTransactionId.toLong()) - if (writeCheckpoint != null && !bucketStorage.hasCrud(this)) { - execute( + if (writeCheckpoint != null && !bucketStorage.hasCrud(transaction)) { + transaction.execute( "UPDATE ps_buckets SET target_op = CAST(? AS INTEGER) WHERE name='\$local'", listOf(writeCheckpoint), ) } else { - execute( + transaction.execute( "UPDATE ps_buckets SET target_op = CAST(? AS INTEGER) WHERE name='\$local'", listOf(bucketStorage.getMaxOpId()), ) diff --git a/core/src/commonMain/kotlin/com/powersync/db/Queries.kt b/core/src/commonMain/kotlin/com/powersync/db/Queries.kt index b4e8a806..f400297c 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/Queries.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/Queries.kt @@ -1,7 +1,7 @@ package com.powersync.db import com.powersync.PowerSyncException -import com.powersync.db.internal.PowerSyncTransaction +import com.powersync.db.internal.ThrowableTransactionCallback import kotlinx.coroutines.flow.Flow import kotlin.coroutines.cancellation.CancellationException @@ -58,8 +58,8 @@ public interface Queries { ): Flow> @Throws(PowerSyncException::class, CancellationException::class) - public suspend fun writeTransaction(callback: (PowerSyncTransaction) -> R): R + public suspend fun writeTransaction(callback: ThrowableTransactionCallback): R @Throws(PowerSyncException::class, CancellationException::class) - public suspend fun readTransaction(callback: (PowerSyncTransaction) -> R): R + public suspend fun readTransaction(callback: ThrowableTransactionCallback): R } diff --git a/core/src/commonMain/kotlin/com/powersync/db/internal/InternalDatabaseImpl.kt b/core/src/commonMain/kotlin/com/powersync/db/internal/InternalDatabaseImpl.kt index c609010f..d8252877 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/internal/InternalDatabaseImpl.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/internal/InternalDatabaseImpl.kt @@ -7,11 +7,13 @@ import app.cash.sqldelight.coroutines.mapToList import app.cash.sqldelight.db.QueryResult import app.cash.sqldelight.db.SqlPreparedStatement import com.persistence.PowersyncQueries +import com.powersync.PowerSyncException import com.powersync.PsSqlDriver import com.powersync.db.SqlCursor import com.powersync.db.runWrapped import com.powersync.persistence.PsDatabase import com.powersync.utils.JsonUtil +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview @@ -91,13 +93,15 @@ internal class InternalDatabaseImpl( ): Long { val numParams = parameters?.size ?: 0 - return driver - .execute( - identifier = null, - sql = sql, - parameters = numParams, - binders = getBindersFromParams(parameters), - ).value + return runWrapped { + driver + .execute( + identifier = null, + sql = sql, + parameters = numParams, + binders = getBindersFromParams(parameters), + ).value + } } override suspend fun get( @@ -214,17 +218,29 @@ internal class InternalDatabaseImpl( } } - override suspend fun readTransaction(callback: PowerSyncTransaction.() -> R): R = + override suspend fun readTransaction(callback: ThrowableTransactionCallback): R = withContext(dbContext) { transactor.transactionWithResult(noEnclosing = true) { - callback(transaction) + runWrapped { + val result = callback.execute(transaction) + if (result is PowerSyncException) { + throw result + } + result + } } } - override suspend fun writeTransaction(callback: PowerSyncTransaction.() -> R): R = + override suspend fun writeTransaction(callback: ThrowableTransactionCallback): R = withContext(dbContext) { transactor.transactionWithResult(noEnclosing = true) { - callback(transaction) + runWrapped { + val result = callback.execute(transaction) + if (result is PowerSyncException) { + throw result + } + result + } } } @@ -331,3 +347,11 @@ internal fun getBindersFromParams(parameters: List?): (SqlPreparedStatemen } } } + +/** + * Kotlin allows SAM (Single Abstract Method) interfaces to be treated like lambda expressions. + */ +public fun interface ThrowableTransactionCallback { + @Throws(PowerSyncException::class, CancellationException::class) + public fun execute(transaction: PowerSyncTransaction): R +} diff --git a/core/src/commonMain/kotlin/com/powersync/db/internal/PowerSyncTransaction.kt b/core/src/commonMain/kotlin/com/powersync/db/internal/PowerSyncTransaction.kt index 56d80138..3902b5f8 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/internal/PowerSyncTransaction.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/internal/PowerSyncTransaction.kt @@ -1,25 +1,31 @@ package com.powersync.db.internal +import com.powersync.PowerSyncException import com.powersync.db.SqlCursor +import kotlin.coroutines.cancellation.CancellationException public interface PowerSyncTransaction { + @Throws(PowerSyncException::class, CancellationException::class) public fun execute( sql: String, parameters: List? = listOf(), ): Long + @Throws(PowerSyncException::class, CancellationException::class) public fun getOptional( sql: String, parameters: List? = listOf(), mapper: (SqlCursor) -> RowType, ): RowType? + @Throws(PowerSyncException::class, CancellationException::class) public fun getAll( sql: String, parameters: List? = listOf(), mapper: (SqlCursor) -> RowType, ): List + @Throws(PowerSyncException::class, CancellationException::class) public fun get( sql: String, parameters: List? = listOf(), diff --git a/gradle.properties b/gradle.properties index 7bb8e53a..a557879d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ development=true RELEASE_SIGNING_ENABLED=true # Library config GROUP=com.powersync -LIBRARY_VERSION=1.0.0-BETA22 +LIBRARY_VERSION=1.0.0-BETA23 GITHUB_REPO=https://github.com/powersync-ja/powersync-kotlin.git # POM POM_URL=https://github.com/powersync-ja/powersync-kotlin/