From d0d969a9aca8f392ce6311fc337fe8efe52ad5e1 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Tue, 19 Mar 2024 20:00:13 +0200 Subject: [PATCH 1/4] fix watched queries --- .gitignore | 3 ++- .../db/internal/PsInternalDatabase.kt | 16 +++++++++--- ...h.sqldelight.dialect.api.SqlDelightDialect | 1 + .../com/powersync/sqlite/PowerSyncDialect.kt | 25 +++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect create mode 100644 dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt diff --git a/.gitignore b/.gitignore index 25cb8fab..052ece8b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ captures !*.xcodeproj/project.xcworkspace/ !*.xcworkspace/contents.xcworkspacedata **/xcshareddata/WorkspaceSettings.xcsettings -Pods/ \ No newline at end of file +Pods/ +plugins/sonatype \ No newline at end of file diff --git a/core/src/commonMain/kotlin/com/powersync/db/internal/PsInternalDatabase.kt b/core/src/commonMain/kotlin/com/powersync/db/internal/PsInternalDatabase.kt index 967d0468..b6f5b73e 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/internal/PsInternalDatabase.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/internal/PsInternalDatabase.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.serialization.encodeToString @@ -38,10 +39,17 @@ class PsInternalDatabase(val driver: PsSqlDriver, private val scope: CoroutineSc init { scope.launch { - tableUpdates().debounce(DEFAULT_WATCH_THROTTLE_MS).collect { tables -> - val dataTables = tables.map { toFriendlyTableName(it) }.filter { it.isNotBlank() } - driver.notifyListeners(queryKeys = dataTables.toTypedArray()) - } + val accumulatedUpdates = mutableSetOf(); + tableUpdates() +// Debounce will discard any events which occur inside the debounce window +// This will accumulate those table updates + .onEach { tables -> accumulatedUpdates.addAll(tables) } + .debounce(DEFAULT_WATCH_THROTTLE_MS) + .collect { + val dataTables = accumulatedUpdates.map { toFriendlyTableName(it) }.filter { it.isNotBlank() } + driver.notifyListeners(queryKeys = dataTables.toTypedArray()); + accumulatedUpdates.clear(); + } } } diff --git a/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect b/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect new file mode 100644 index 00000000..2d4118ed --- /dev/null +++ b/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect @@ -0,0 +1 @@ +com.powersync.sqlite.PowerSyncDialect diff --git a/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt b/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt new file mode 100644 index 00000000..a97e3639 --- /dev/null +++ b/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt @@ -0,0 +1,25 @@ +package com.powersync.sqlite + +import app.cash.sqldelight.dialect.api.IntermediateType +import app.cash.sqldelight.dialect.api.PrimitiveType +import app.cash.sqldelight.dialect.api.SqlDelightDialect +import app.cash.sqldelight.dialect.api.TypeResolver +import app.cash.sqldelight.dialects.sqlite_3_35.SqliteTypeResolver +import app.cash.sqldelight.dialects.sqlite_3_38.SqliteDialect as Sqlite338Dialect +import com.alecstrong.sql.psi.core.psi.SqlFunctionExpr + +class PowerSyncDialect : SqlDelightDialect by Sqlite338Dialect() { + override fun typeResolver(parentResolver: TypeResolver) = PowerSyncTypeResolver(parentResolver) +} + +class PowerSyncTypeResolver(private val parentResolver: TypeResolver) : + TypeResolver by SqliteTypeResolver(parentResolver) { + override fun functionType(functionExpr: SqlFunctionExpr): IntermediateType? { + when (functionExpr.functionName.text) { + "sqlite_version", "powersync_rs_version", "powersync_replace_schema" -> return IntermediateType( + PrimitiveType.TEXT + ) + } + return parentResolver.functionType(functionExpr) + } +} From f6a564137af1e463fde621bdb96168852336cfd5 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Wed, 20 Mar 2024 10:29:45 +0200 Subject: [PATCH 2/4] ignore dialect bin files --- .gitignore | 3 ++- ...h.sqldelight.dialect.api.SqlDelightDialect | 1 - .../com/powersync/sqlite/PowerSyncDialect.kt | 25 ------------------- 3 files changed, 2 insertions(+), 27 deletions(-) delete mode 100644 dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect delete mode 100644 dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt diff --git a/.gitignore b/.gitignore index 052ece8b..5c7eca62 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ captures !*.xcworkspace/contents.xcworkspacedata **/xcshareddata/WorkspaceSettings.xcsettings Pods/ -plugins/sonatype \ No newline at end of file +plugins/sonatype +dialect/bin \ No newline at end of file diff --git a/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect b/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect deleted file mode 100644 index 2d4118ed..00000000 --- a/dialect/bin/main/META-INF/services/app.cash.sqldelight.dialect.api.SqlDelightDialect +++ /dev/null @@ -1 +0,0 @@ -com.powersync.sqlite.PowerSyncDialect diff --git a/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt b/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt deleted file mode 100644 index a97e3639..00000000 --- a/dialect/bin/main/com/powersync/sqlite/PowerSyncDialect.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.powersync.sqlite - -import app.cash.sqldelight.dialect.api.IntermediateType -import app.cash.sqldelight.dialect.api.PrimitiveType -import app.cash.sqldelight.dialect.api.SqlDelightDialect -import app.cash.sqldelight.dialect.api.TypeResolver -import app.cash.sqldelight.dialects.sqlite_3_35.SqliteTypeResolver -import app.cash.sqldelight.dialects.sqlite_3_38.SqliteDialect as Sqlite338Dialect -import com.alecstrong.sql.psi.core.psi.SqlFunctionExpr - -class PowerSyncDialect : SqlDelightDialect by Sqlite338Dialect() { - override fun typeResolver(parentResolver: TypeResolver) = PowerSyncTypeResolver(parentResolver) -} - -class PowerSyncTypeResolver(private val parentResolver: TypeResolver) : - TypeResolver by SqliteTypeResolver(parentResolver) { - override fun functionType(functionExpr: SqlFunctionExpr): IntermediateType? { - when (functionExpr.functionName.text) { - "sqlite_version", "powersync_rs_version", "powersync_replace_schema" -> return IntermediateType( - PrimitiveType.TEXT - ) - } - return parentResolver.functionType(functionExpr) - } -} From da9443cc5bf553827d9e459b60a0f95f700ca66f Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Wed, 20 Mar 2024 11:23:25 +0200 Subject: [PATCH 3/4] chore: bump versions --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 165cf68a..79faefdd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ development=true RELEASE_SIGNING_ENABLED=true # Library config GROUP=com.powersync -LIBRARY_VERSION=0.0.1-ALPHA4 +LIBRARY_VERSION=0.0.1-ALPHA5 GITHUB_REPO=https://github.com/powersync-ja/powersync-kotlin.git # POM POM_URL=https://github.com/powersync-ja/powersync-kotlin/ From 8f9289d2dc2a54c73b5f524aecf4425ca2473480 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Wed, 20 Mar 2024 14:52:07 +0200 Subject: [PATCH 4/4] fix schema index serialization --- .../com/powersync/db/schema/IndexedColumn.kt | 22 +++++++++++++++++-- .../kotlin/com/powersync/db/schema/Table.kt | 18 ++++++++++++++- .../kotlin/com/powersync/demos/AppSchema.kt | 9 ++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/core/src/commonMain/kotlin/com/powersync/db/schema/IndexedColumn.kt b/core/src/commonMain/kotlin/com/powersync/db/schema/IndexedColumn.kt index 2c604f9f..b1f0ec43 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/schema/IndexedColumn.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/schema/IndexedColumn.kt @@ -1,27 +1,45 @@ package com.powersync.db.schema +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable /** * Describes an indexed column. */ @Serializable -data class IndexedColumn ( +data class IndexedColumn( /** * Name of the column to index. */ + @SerialName("name") val column: String, /** * Whether this column is stored in ascending order in the index. */ - private val ascending: Boolean = true + private val ascending: Boolean = true, + + private var columnDefinition: Column? = null, + + /** + * The column definition type + */ + var type: ColumnType? = null ) { companion object { fun ascending(column: String) = IndexedColumn(column, true) fun descending(column: String) = IndexedColumn(column, false) } + /** + * Sets the parent column definition. The column definition's type + * is required for the serialized JSON payload of powersync_replace_schema + */ + fun setColumnDefinition(column: Column) { + this.type = column.type; + this.columnDefinition = column; + } + fun toSql(table: Table): String { val fullColumn = table[column] // errors if not found return fullColumn.let { diff --git a/core/src/commonMain/kotlin/com/powersync/db/schema/Table.kt b/core/src/commonMain/kotlin/com/powersync/db/schema/Table.kt index c9368118..4537c7a7 100644 --- a/core/src/commonMain/kotlin/com/powersync/db/schema/Table.kt +++ b/core/src/commonMain/kotlin/com/powersync/db/schema/Table.kt @@ -2,13 +2,14 @@ package com.powersync.db.schema import com.powersync.invalidSqliteCharacters import kotlinx.serialization.Serializable +import kotlin.math.log /** * A single table in the schema. */ @Serializable -data class Table constructor( +data class Table constructor( /** * The synced table name, matching sync rules. */ @@ -34,6 +35,21 @@ data class Table constructor( */ private val _viewNameOverride: String? = null ) { + + init { + /** + * Need to set the column definition for each index column. + * This is required for serialization + */ + indexes.forEach { index -> + index.columns.forEach { + val matchingColumn = columns.find { c -> c.name == it.column } + ?: throw AssertionError("Could not find column definition for index ${index.name}:${it.column}") + it.setColumnDefinition(column = matchingColumn) + } + } + } + companion object { /** * Create a table that only exists locally. diff --git a/demos/hello-powersync/composeApp/src/commonMain/kotlin/com/powersync/demos/AppSchema.kt b/demos/hello-powersync/composeApp/src/commonMain/kotlin/com/powersync/demos/AppSchema.kt index c5846787..0a78f3f6 100644 --- a/demos/hello-powersync/composeApp/src/commonMain/kotlin/com/powersync/demos/AppSchema.kt +++ b/demos/hello-powersync/composeApp/src/commonMain/kotlin/com/powersync/demos/AppSchema.kt @@ -1,16 +1,21 @@ package com.powersync.demos import com.powersync.db.schema.Column +import com.powersync.db.schema.Index +import com.powersync.db.schema.IndexedColumn import com.powersync.db.schema.Schema import com.powersync.db.schema.Table val AppSchema: Schema = Schema( listOf( Table( - "customers", - listOf( + name = "customers", + columns = listOf( Column.text("name"), Column.text("email") + ), + indexes = listOf( + Index("name", listOf(IndexedColumn.descending("name"))) ) ) )