Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let package = Package(
targets: [
.binaryTarget(
name: packageName,
path: "./PowerSyncKotlin/build/XCFrameworks/debug/PowerSyncKotlin.xcframework"
path: "./PowerSyncKotlin/build/XCFrameworks/debug/\(packageName).xcframework"
)
,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public actual class DatabaseDriverFactory(
@Suppress("unused")
private fun onTransactionCommit(success: Boolean) {
driver?.also { driver ->
if (success) {
driver.fireTableUpdates()
} else {
// Only clear updates if a rollback happened
// We manually fire updates when transactions are completed
if (!success) {
driver.clearTableUpdates()
}
}
Expand All @@ -42,38 +42,38 @@ public actual class DatabaseDriverFactory(
PsSqlDriver(
scope = scope,
driver =
AndroidSqliteDriver(
context = context,
schema = schema,
name = dbFilename,
factory =
RequerySQLiteOpenHelperFactory(
listOf(
RequerySQLiteOpenHelperFactory.ConfigurationOptions { config ->
config.customExtensions.add(
SQLiteCustomExtension(
"libpowersync",
"sqlite3_powersync_init",
),
)
config.customExtensions.add(
SQLiteCustomExtension(
"libpowersync-sqlite",
"powersync_init",
),
)
config
},
),
),
callback =
object : AndroidSqliteDriver.Callback(schema) {
override fun onConfigure(db: SupportSQLiteDatabase) {
db.enableWriteAheadLogging()
super.onConfigure(db)
}
AndroidSqliteDriver(
context = context,
schema = schema,
name = dbFilename,
factory =
RequerySQLiteOpenHelperFactory(
listOf(
RequerySQLiteOpenHelperFactory.ConfigurationOptions { config ->
config.customExtensions.add(
SQLiteCustomExtension(
"libpowersync",
"sqlite3_powersync_init",
),
)
config.customExtensions.add(
SQLiteCustomExtension(
"libpowersync-sqlite",
"powersync_init",
),
)
config
},
),
),
callback =
object : AndroidSqliteDriver.Callback(schema) {
override fun onConfigure(db: SupportSQLiteDatabase) {
db.enableWriteAheadLogging()
super.onConfigure(db)
}
},
),
)
setupSqliteBinding()
return this.driver as PsSqlDriver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString

Expand All @@ -33,6 +36,12 @@ internal class InternalDatabaseImpl(
override val transactor: PsDatabase = PsDatabase(driver)
override val queries: PowersyncQueries = transactor.powersyncQueries

// Register callback for table updates
private fun tableUpdates(): Flow<List<String>> = driver.tableUpdates()

// Debounced by transaction completion
private val tableUpdatesMutex = Mutex()

// Could be scope.coroutineContext, but the default is GlobalScope, which seems like a bad idea. To discuss.
private val dbContext = Dispatchers.IO
private val transaction =
Expand Down Expand Up @@ -62,30 +71,44 @@ internal class InternalDatabaseImpl(
}

companion object {
const val POWERSYNC_TABLE_MATCH: String = "(^ps_data__|^ps_data_local__)"
const val DEFAULT_WATCH_THROTTLE_MS: Long = 30L
const val POWERSYNC_TABLE_MATCH = "(^ps_data__|^ps_data_local__)"
const val DEFAULT_WATCH_THROTTLE_MS = 30L
}

init {
scope.launch {
val accumulatedUpdates = mutableSetOf<String>()
// Store table changes in an accumulated array which will be (debounced) emitted on transaction end
tableUpdates()
// Debounce will discard any events which occur inside the debounce window
// This will accumulate those table updates
.onEach { tables -> accumulatedUpdates.addAll(tables) }
.onEach { tables ->
val dataTables =
tables
.map { toFriendlyTableName(it) }
.filter { it.isNotBlank() }
tableUpdatesMutex.withLock {
accumulatedUpdates.addAll(dataTables)
}
}
// debounce ignores events inside the throttle. Debouncing needs to be done after accumulation
.debounce(DEFAULT_WATCH_THROTTLE_MS)
.collect {
val dataTables = accumulatedUpdates.map { toFriendlyTableName(it) }.filter { it.isNotBlank() }
driver.notifyListeners(queryKeys = dataTables.toTypedArray())
accumulatedUpdates.clear()
.collect { _ ->
tableUpdatesMutex.withLock {
driver.notifyListeners(queryKeys = accumulatedUpdates.toTypedArray())
accumulatedUpdates.clear()
}
}
}
}

override suspend fun execute(
sql: String,
parameters: List<Any?>?,
): Long = withContext(dbContext) { executeSync(sql, parameters) }
): Long =
withContext(dbContext) {
val r = executeSync(sql, parameters)
driver.fireTableUpdates()
r
}

private fun executeSync(
sql: String,
Expand Down Expand Up @@ -233,20 +256,21 @@ internal class InternalDatabaseImpl(

override suspend fun <R> writeTransaction(callback: ThrowableTransactionCallback<R>): R =
withContext(dbContext) {
transactor.transactionWithResult(noEnclosing = true) {
runWrapped {
val result = callback.execute(transaction)
if (result is PowerSyncException) {
throw result
val r =
transactor.transactionWithResult(noEnclosing = true) {
runWrapped {
val result = callback.execute(transaction)
if (result is PowerSyncException) {
throw result
}
result
}
result
}
}
// Trigger watched queries
driver.fireTableUpdates()
r
}

// Register callback for table updates
private fun tableUpdates(): Flow<List<String>> = driver.tableUpdates()

// Register callback for table updates on a specific table
override fun updatesOnTable(tableName: String): Flow<Unit> = driver.updatesOnTable(tableName)

Expand Down
49 changes: 25 additions & 24 deletions core/src/iosMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public actual class DatabaseDriverFactory {

private fun onTransactionCommit(success: Boolean) {
driver?.also { driver ->
if (success) {
driver.fireTableUpdates()
} else {
// Only clear updates on rollback
// We manually fire updates when a transaction ended
if (!success) {
driver.clearTableUpdates()
}
}
Expand All @@ -63,7 +63,8 @@ public actual class DatabaseDriverFactory {
override fun eWrite(
message: String,
exception: Throwable?,
) {}
) {
}

override fun trace(message: String) {}

Expand All @@ -74,27 +75,27 @@ public actual class DatabaseDriverFactory {
PsSqlDriver(
scope = scope,
driver =
NativeSqliteDriver(
configuration =
DatabaseConfiguration(
name = dbFilename,
version = schema.version.toInt(),
create = { connection -> wrapConnection(connection) { schema.create(it) } },
loggingConfig = Logging(logger = sqlLogger),
lifecycleConfig =
DatabaseConfiguration.Lifecycle(
onCreateConnection = { connection ->
setupSqliteBinding(connection)
wrapConnection(connection) { driver ->
schema.create(driver)
}
},
onCloseConnection = { connection ->
deregisterSqliteBinding(connection)
},
),
),
NativeSqliteDriver(
configuration =
DatabaseConfiguration(
name = dbFilename,
version = schema.version.toInt(),
create = { connection -> wrapConnection(connection) { schema.create(it) } },
loggingConfig = Logging(logger = sqlLogger),
lifecycleConfig =
DatabaseConfiguration.Lifecycle(
onCreateConnection = { connection ->
setupSqliteBinding(connection)
wrapConnection(connection) { driver ->
schema.create(driver)
}
},
onCloseConnection = { connection ->
deregisterSqliteBinding(connection)
},
),
),
),
)
return this.driver as PsSqlDriver
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public actual class DatabaseDriverFactory {
@Suppress("unused")
private fun onTransactionCommit(success: Boolean) {
driver?.also { driver ->
if (success) {
driver.fireTableUpdates()
} else {
// Only clear updates on rollback
// We manually fire updates when a transaction ended
if (!success) {
driver.clearTableUpdates()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@android:style/Theme.Material.Light.NoActionBar">

<activity
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>