diff --git a/.changeset/fresh-fishes-own.md b/.changeset/fresh-fishes-own.md new file mode 100644 index 000000000..d08cbe92f --- /dev/null +++ b/.changeset/fresh-fishes-own.md @@ -0,0 +1,5 @@ +--- +'@journeyapps/powersync-sdk-common': patch +--- + +Resolving tables for watch() before handling any results, eliminating a potential race condition between initial result and changes. Also handling a potential uncaught exception. diff --git a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts index f9074f094..0ae817c7a 100644 --- a/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/powersync-sdk-common/src/client/AbstractPowerSyncDatabase.ts @@ -476,8 +476,8 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver { try { - // Fetch initial data - onResult(await this.executeReadOnly(sql, parameters)); - const resolvedTables = await this.resolveTables(sql, parameters, options); + // Fetch initial data + const result = await this.executeReadOnly(sql, parameters); + onResult(result); + this.onChangeWithCallback( - { onChange: async () => onResult(await this.executeReadOnly(sql, parameters)), onError }, + { + onChange: async () => { + try { + const result = await this.executeReadOnly(sql, parameters); + onResult(result); + } catch (error) { + onError?.(error); + } + }, + onError + }, { ...(options ?? {}), tables: resolvedTables @@ -663,11 +674,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver { return new EventIterator((eventOptions) => { (async () => { + const resolvedTables = await this.resolveTables(sql, parameters, options); + // Fetch initial data eventOptions.push(await this.executeReadOnly(sql, parameters)); - const resolvedTables = await this.resolveTables(sql, parameters, options); - for await (const event of this.onChangeWithAsyncGenerator({ ...(options ?? {}), tables: resolvedTables diff --git a/packages/powersync-sdk-web/tests/watch.test.ts b/packages/powersync-sdk-web/tests/watch.test.ts index f3f843a29..daafe4cac 100644 --- a/packages/powersync-sdk-web/tests/watch.test.ts +++ b/packages/powersync-sdk-web/tests/watch.test.ts @@ -195,6 +195,9 @@ describe('Watch Tests', () => { } })(); + // Ensures insert doesn't form part of initial result + await new Promise((resolve) => setTimeout(resolve, throttleDuration)); + // Create the inserts as fast as possible await powersync.execute('INSERT INTO assets(id, make, customer_id) VALUES (uuid(), ?, ?)', ['test', uuid()]); @@ -238,7 +241,9 @@ describe('Watch Tests', () => { } ); - // Create the inserts as fast as possible + // Ensures insert doesn't form part of initial result + await new Promise((resolve) => setTimeout(resolve, throttleDuration)); + await powersync.execute('INSERT INTO assets(id, make, customer_id) VALUES (uuid(), ?, ?)', ['test', uuid()]); await new Promise((resolve) => setTimeout(resolve, throttleDuration * 2));