From 9f2405217a2f443c5064911afc9eb65be32f83e5 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Tue, 23 Jan 2024 13:46:11 +0200 Subject: [PATCH 1/4] fix watched queries: watches now execute read queries after table changes have been commited --- .changeset/angry-foxes-hammer.md | 5 +++ .changeset/fast-chicken-vanish.md | 6 ++++ .../src/client/AbstractPowerSyncDatabase.ts | 22 ++++++++++--- .../powersync-sdk-common/src/db/DBAdapter.ts | 31 +++++++++++++++++-- .../powersync-sdk-react-native/package.json | 2 +- .../RNQSDBAdapter.ts | 2 +- powersync-supabase-react-native-todolist-demo | 1 + yarn.lock | 8 ++--- 8 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 .changeset/angry-foxes-hammer.md create mode 100644 .changeset/fast-chicken-vanish.md create mode 160000 powersync-supabase-react-native-todolist-demo diff --git a/.changeset/angry-foxes-hammer.md b/.changeset/angry-foxes-hammer.md new file mode 100644 index 000000000..f8e85589c --- /dev/null +++ b/.changeset/angry-foxes-hammer.md @@ -0,0 +1,5 @@ +--- +'@journeyapps/powersync-sdk-react-native': patch +--- + +Fixed watched queries from updating before writes have been commited on the write connection. diff --git a/.changeset/fast-chicken-vanish.md b/.changeset/fast-chicken-vanish.md new file mode 100644 index 000000000..7db781341 --- /dev/null +++ b/.changeset/fast-chicken-vanish.md @@ -0,0 +1,6 @@ +--- +'@journeyapps/powersync-sdk-react-native': minor +'@journeyapps/powersync-sdk-common': minor +--- + +Added the ability to receive batched table updates from DB adapters. diff --git a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts index e46e0232d..b9f607acf 100644 --- a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts @@ -1,7 +1,13 @@ import _ from 'lodash'; import { Mutex } from 'async-mutex'; import Logger, { ILogger } from 'js-logger'; -import { DBAdapter, QueryResult, Transaction } from '../db/DBAdapter'; +import { + BatchedUpdateNotification, + DBAdapter, + QueryResult, + Transaction, + isBatchedUpdateNotification +} from '../db/DBAdapter'; import { Schema } from '../db/schema/Schema'; import { SyncStatus } from '../db/crud/SyncStatus'; import { UploadQueueStats } from '../db/crud/UploadQueueStatus'; @@ -511,15 +517,21 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver { - const { table } = update; const { rawTableNames } = options; - if (!rawTableNames && !table.match(POWERSYNC_TABLE_MATCH)) { + const tables = isBatchedUpdateNotification(update) ? update.tables : [update.table]; + + const filteredTables = rawTableNames ? tables : tables.filter((t) => !!t.match(POWERSYNC_TABLE_MATCH)); + if (!filteredTables.length) { return; } - const tableName = rawTableNames ? table : table.replace(POWERSYNC_TABLE_MATCH, ''); - throttledTableUpdates.push(tableName); + // Remove any PowerSync table prefixes if necessary + const mappedTableNames = rawTableNames + ? filteredTables + : filteredTables.map((t) => t.replace(POWERSYNC_TABLE_MATCH, '')); + + throttledTableUpdates.push(...mappedTableNames); flushTableUpdates(); } diff --git a/packages/powersync-sdk-common/src/db/DBAdapter.ts b/packages/powersync-sdk-common/src/db/DBAdapter.ts index 0be4e5d3f..26aba1980 100644 --- a/packages/powersync-sdk-common/src/db/DBAdapter.ts +++ b/packages/powersync-sdk-common/src/db/DBAdapter.ts @@ -5,6 +5,11 @@ import { BaseListener, BaseObserverInterface } from '../utils/BaseObserver'; +/** + * TODO most of these types could be exported to a common `types` package + * which is used by the DB adapter libraries as well. + */ + /** * Object returned by SQL Query executions { * insertId: Represent the auto-generated row id if applicable @@ -54,14 +59,28 @@ export enum RowUpdateType { SQLITE_DELETE = 9, SQLITE_UPDATE = 23 } -export interface UpdateNotification { +export interface TableUpdateOperation { opType: RowUpdateType; - table: string; rowId: number; } +export interface UpdateNotification extends TableUpdateOperation { + table: string; +} + +export interface BatchedUpdateNotification { + rawUpdates: UpdateNotification[]; + tables: string[]; + groupedUpdates: Record; +} export interface DBAdapterListener extends BaseListener { - tablesUpdated: (updateNotification: UpdateNotification) => void; + /** + * Listener for table updates. + * Allows for single table updates in order to maintain API compatibility + * without the need for a major version bump + * The DB adapter can also batch update notifications if supported. + */ + tablesUpdated: (updateNotification: BatchedUpdateNotification | UpdateNotification) => void; } export interface DBLockOptions { @@ -77,3 +96,9 @@ export interface DBAdapter extends BaseObserverInterface, DBG writeLock: (fn: (tx: LockContext) => Promise, options?: DBLockOptions) => Promise; writeTransaction: (fn: (tx: Transaction) => Promise, options?: DBLockOptions) => Promise; } + +export function isBatchedUpdateNotification( + update: BatchedUpdateNotification | UpdateNotification +): update is BatchedUpdateNotification { + return 'tables' in update; +} diff --git a/packages/powersync-sdk-react-native/package.json b/packages/powersync-sdk-react-native/package.json index 257d15bcb..049d0819e 100644 --- a/packages/powersync-sdk-react-native/package.json +++ b/packages/powersync-sdk-react-native/package.json @@ -44,7 +44,7 @@ "async-lock": "^1.4.0" }, "devDependencies": { - "@journeyapps/react-native-quick-sqlite": "^1.0.0", + "@journeyapps/react-native-quick-sqlite": "0.0.0-dev-20240123100027", "@types/async-lock": "^1.4.0", "react-native": "0.72.4", "react": "18.2.0", diff --git a/packages/powersync-sdk-react-native/src/db/adapters/react-native-quick-sqlite/RNQSDBAdapter.ts b/packages/powersync-sdk-react-native/src/db/adapters/react-native-quick-sqlite/RNQSDBAdapter.ts index 5cae2294a..f2fbbe924 100644 --- a/packages/powersync-sdk-react-native/src/db/adapters/react-native-quick-sqlite/RNQSDBAdapter.ts +++ b/packages/powersync-sdk-react-native/src/db/adapters/react-native-quick-sqlite/RNQSDBAdapter.ts @@ -21,7 +21,7 @@ export class RNQSDBAdapter extends BaseObserver implements DB constructor(protected baseDB: QuickSQLiteConnection, public name: string) { super(); // link table update commands - baseDB.registerUpdateHook((update) => { + baseDB.registerTablesChangedHook((update) => { this.iterateListeners((cb) => cb.tablesUpdated?.(update)); }); diff --git a/powersync-supabase-react-native-todolist-demo b/powersync-supabase-react-native-todolist-demo new file mode 160000 index 000000000..ef67b6397 --- /dev/null +++ b/powersync-supabase-react-native-todolist-demo @@ -0,0 +1 @@ +Subproject commit ef67b6397cf1cbf70c7512dfeb3eddb0719bc8c8 diff --git a/yarn.lock b/yarn.lock index 22008a359..7b2df78a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2220,10 +2220,10 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@journeyapps/react-native-quick-sqlite@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@journeyapps/react-native-quick-sqlite/-/react-native-quick-sqlite-1.0.0.tgz#bb836a82a64705a2be6de27560b1e8816bba19d0" - integrity sha512-rQPE5OoMfXCyBBnCNMhkd4pES8zt0CbxiWb6GfZ04ik/cKji14GWBkvw9YZdyutc3zb3CNiexHYP1xZzlQYTQg== +"@journeyapps/react-native-quick-sqlite@0.0.0-dev-20240123100027": + version "0.0.0-dev-20240123100027" + resolved "https://registry.npmjs.org/@journeyapps/react-native-quick-sqlite/-/react-native-quick-sqlite-0.0.0-dev-20240123100027.tgz#f91c305326012cefaf53508875017dd6ba6f530d" + integrity sha512-hT0axuG/2Y8YeiXVlPeXCNm+tfSBDhJS1ffT9x0dCHuzh4YWZnCOmwA6SVnj3dARFaWvKz3er2hklGgS1H1n3g== dependencies: lodash "^4.17.21" uuid "3.4.0" From 373bceca8528e9a1d53011d815c088f3b17b81f7 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Tue, 23 Jan 2024 13:59:50 +0200 Subject: [PATCH 2/4] update powersync url --- .gitmodules | 2 +- .../src/client/AbstractPowerSyncDatabase.ts | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.gitmodules b/.gitmodules index ad7f8869a..1b6f520e0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "apps/supabase-todolist"] path = apps/supabase-todolist - url = git@github.com:journeyapps/powersync-supabase-react-native-todolist-demo.git + url = git@github.com:powersync-ja/powersync-supabase-react-native-todolist-demo.git diff --git a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts index b9f607acf..3257e9b98 100644 --- a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts @@ -1,13 +1,7 @@ import _ from 'lodash'; import { Mutex } from 'async-mutex'; import Logger, { ILogger } from 'js-logger'; -import { - BatchedUpdateNotification, - DBAdapter, - QueryResult, - Transaction, - isBatchedUpdateNotification -} from '../db/DBAdapter'; +import { DBAdapter, QueryResult, Transaction, isBatchedUpdateNotification } from '../db/DBAdapter'; import { Schema } from '../db/schema/Schema'; import { SyncStatus } from '../db/crud/SyncStatus'; import { UploadQueueStats } from '../db/crud/UploadQueueStatus'; From 5b97ecc94d50e08ce4ac48a8202f714fd530deed Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Tue, 23 Jan 2024 14:46:34 +0200 Subject: [PATCH 3/4] weird submodule test --- powersync-supabase-react-native-todolist-demo | 1 - 1 file changed, 1 deletion(-) delete mode 160000 powersync-supabase-react-native-todolist-demo diff --git a/powersync-supabase-react-native-todolist-demo b/powersync-supabase-react-native-todolist-demo deleted file mode 160000 index ef67b6397..000000000 --- a/powersync-supabase-react-native-todolist-demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ef67b6397cf1cbf70c7512dfeb3eddb0719bc8c8 From fe981d3411c148929eb8469869ca15af2d4b33a8 Mon Sep 17 00:00:00 2001 From: Steven Ontong Date: Wed, 24 Jan 2024 11:08:24 +0200 Subject: [PATCH 4/4] bump dev packages --- packages/powersync-sdk-react-native/package.json | 4 ++-- yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/powersync-sdk-react-native/package.json b/packages/powersync-sdk-react-native/package.json index 049d0819e..24d9b0327 100644 --- a/packages/powersync-sdk-react-native/package.json +++ b/packages/powersync-sdk-react-native/package.json @@ -27,7 +27,7 @@ }, "homepage": "https://docs.powersync.co/", "peerDependencies": { - "@journeyapps/react-native-quick-sqlite": "^1.0.0", + "@journeyapps/react-native-quick-sqlite": "^1.1.0", "base-64": "^1.0.0", "react": "*", "react-native": "*", @@ -44,7 +44,7 @@ "async-lock": "^1.4.0" }, "devDependencies": { - "@journeyapps/react-native-quick-sqlite": "0.0.0-dev-20240123100027", + "@journeyapps/react-native-quick-sqlite": "^1.1.0", "@types/async-lock": "^1.4.0", "react-native": "0.72.4", "react": "18.2.0", diff --git a/yarn.lock b/yarn.lock index 7b2df78a8..a63f460fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2220,10 +2220,10 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@journeyapps/react-native-quick-sqlite@0.0.0-dev-20240123100027": - version "0.0.0-dev-20240123100027" - resolved "https://registry.npmjs.org/@journeyapps/react-native-quick-sqlite/-/react-native-quick-sqlite-0.0.0-dev-20240123100027.tgz#f91c305326012cefaf53508875017dd6ba6f530d" - integrity sha512-hT0axuG/2Y8YeiXVlPeXCNm+tfSBDhJS1ffT9x0dCHuzh4YWZnCOmwA6SVnj3dARFaWvKz3er2hklGgS1H1n3g== +"@journeyapps/react-native-quick-sqlite@^1.0.0", "@journeyapps/react-native-quick-sqlite@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@journeyapps/react-native-quick-sqlite/-/react-native-quick-sqlite-1.1.0.tgz#cf4aa6694b7232d0f86e565fdba4e41ef15d80cc" + integrity sha512-Pg6VA6ABC7N5FrNB5eqTgNsKdzzmDSp5aBtnQh1BlcZu7ISPZdCcKo+ZJtKyzTAWpc17LIttvJwxez6zBxUdOw== dependencies: lodash "^4.17.21" uuid "3.4.0"