diff --git a/.changeset/friendly-dancers-cry.md b/.changeset/friendly-dancers-cry.md new file mode 100644 index 0000000000..d9612f564f --- /dev/null +++ b/.changeset/friendly-dancers-cry.md @@ -0,0 +1,5 @@ +--- +"electric-sql": patch +--- + +Add clarifying documentation on behaviour `synced` promise returned by the `sync` API. diff --git a/clients/typescript/src/client/model/model.ts b/clients/typescript/src/client/model/model.ts index cfeee0ccd9..49ddb92c13 100644 --- a/clients/typescript/src/client/model/model.ts +++ b/clients/typescript/src/client/model/model.ts @@ -27,6 +27,20 @@ export interface Model< ScalarFieldEnum, GetPayload extends HKT > { + /** + * Subscribes to the given shape, returnig a {@link ShapeSubscription} object which + * can be used to wait for the shape to sync initial data. + * + * NOTE: If you establish a shape subscription that has already synced its initial data, + * awaiting `shape.synced` will always resolve immediately as shape subscriptions are persisted. + * i.e.: imagine that you re-sync the same shape during subsequent application loads. + * Awaiting `shape.synced` a second time will only ensure that the initial + * shape load is complete. It does not ensure that the replication stream + * has caught up to the central DB's more recent state. + * + * @param i - The shape to subscribe to + * @returns A shape subscription + */ sync>(i?: T): Promise /** diff --git a/clients/typescript/src/satellite/process.ts b/clients/typescript/src/satellite/process.ts index 6b4737f2a0..85a3c1fc18 100644 --- a/clients/typescript/src/satellite/process.ts +++ b/clients/typescript/src/satellite/process.ts @@ -87,6 +87,14 @@ type ChangeAccumulator = { export type ShapeSubscription = { key: string + /** + * A promise that will resolve once the subscription has synced + * the initial data for the shape. + * + * NOTE: This does not wait for the most recent data changes to + * be synced into the local database, only an initial data batch + * required to establish the subesequent data replication. + */ synced: Promise } diff --git a/docs/usage/data-access/shapes.md b/docs/usage/data-access/shapes.md index e9bb832c88..b344c6b2d8 100644 --- a/docs/usage/data-access/shapes.md +++ b/docs/usage/data-access/shapes.md @@ -183,7 +183,7 @@ The current filtering implementation does not support non-deterministic function The [`sync`](../../api/clients/typescript.md#sync-method) function resolves to an object containing a promise: 1. the first `sync()` promise resolves when the shape subscription has been confirmed by the server (the sync service) -2. the second `synced` promise resolves when the data in the shape has fully synced onto the local device +2. the second `synced` promise resolves when the initial data load for the shape has synced onto the local device ```tsx // Resolves once the shape subscription @@ -197,6 +197,10 @@ await shape.synced If the shape subscription is invalid, the first promise will be rejected. If the data load fails for some reason, the second promise will be rejected. +:::note +If you establish a shape subscription that has already synced its initial data, awaiting `shape.synced` will always resolve immediately. I.e.: imagine that you re-run the code above on subsequent page loads. Awaiting `shape.synced` a second time will only ensure that the initial shape load is complete. It does not ensure that the replication stream has caught up. +::: + ### Data loading Data synced onto the local device via a shape subscription appears atomically in the local database. I.e.: it all loads within a single transaction. diff --git a/examples/expo/src/Example.tsx b/examples/expo/src/Example.tsx index 24bff93d5d..dbe7fa2db7 100644 --- a/examples/expo/src/Example.tsx +++ b/examples/expo/src/Example.tsx @@ -16,7 +16,8 @@ export const Example = () => { // Resolves when the shape subscription has been established. const shape = await db.items.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced } diff --git a/examples/react-native/src/Example.tsx b/examples/react-native/src/Example.tsx index 20ce023e2a..798b8543af 100644 --- a/examples/react-native/src/Example.tsx +++ b/examples/react-native/src/Example.tsx @@ -15,7 +15,8 @@ export const Example = () => { // Resolves when the shape subscription has been established. const shape = await db.items.sync(); - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced; }; diff --git a/examples/recipes/src/activity_events/ActivityEventsExample.tsx b/examples/recipes/src/activity_events/ActivityEventsExample.tsx index 7419c842e1..6639ddf364 100644 --- a/examples/recipes/src/activity_events/ActivityEventsExample.tsx +++ b/examples/recipes/src/activity_events/ActivityEventsExample.tsx @@ -15,7 +15,8 @@ export const ActivityEventsExample = () => { // Resolves when the shape subscription has been established. const shape = await db.activity_events.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/background_jobs/BackgroundJobsExample.tsx b/examples/recipes/src/background_jobs/BackgroundJobsExample.tsx index 3c59f3b33c..46890c9f83 100644 --- a/examples/recipes/src/background_jobs/BackgroundJobsExample.tsx +++ b/examples/recipes/src/background_jobs/BackgroundJobsExample.tsx @@ -14,7 +14,8 @@ export const BackgroundJobsExample = () => { // Resolves when the shape subscription has been established. const shape = await db.background_jobs.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/chat_room/ChatRoomExample.tsx b/examples/recipes/src/chat_room/ChatRoomExample.tsx index b81ab807fe..9b120ca2d9 100644 --- a/examples/recipes/src/chat_room/ChatRoomExample.tsx +++ b/examples/recipes/src/chat_room/ChatRoomExample.tsx @@ -16,7 +16,8 @@ export const ChatRoomExample = () => { // Resolves when the shape subscription has been established. const shape = await db.chat_room.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/data_viewer/DataViewerExample.tsx b/examples/recipes/src/data_viewer/DataViewerExample.tsx index e4f8f1cea6..d3485dd868 100644 --- a/examples/recipes/src/data_viewer/DataViewerExample.tsx +++ b/examples/recipes/src/data_viewer/DataViewerExample.tsx @@ -13,7 +13,8 @@ export const DataViewerExample = () => { // Resolves when the shape subscription has been established. const shape = await db.commerce_orders.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/log_viewer/LogViewerExample.tsx b/examples/recipes/src/log_viewer/LogViewerExample.tsx index 7fdeea96a0..399b451b22 100644 --- a/examples/recipes/src/log_viewer/LogViewerExample.tsx +++ b/examples/recipes/src/log_viewer/LogViewerExample.tsx @@ -13,7 +13,8 @@ export const LogViewerExample = () => { // Resolves when the shape subscription has been established. const shape = await db.logs.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/monitoring_metrics/MonitoringMetricsExample.tsx b/examples/recipes/src/monitoring_metrics/MonitoringMetricsExample.tsx index 9693312977..1d5b2c0396 100644 --- a/examples/recipes/src/monitoring_metrics/MonitoringMetricsExample.tsx +++ b/examples/recipes/src/monitoring_metrics/MonitoringMetricsExample.tsx @@ -14,7 +14,8 @@ export const MonitoringMetricsExample = () => { // Resolves when the shape subscription has been established. const shape = await db.monitoring.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/recipes/src/request_response/RequestResponseExample.tsx b/examples/recipes/src/request_response/RequestResponseExample.tsx index dda4308a16..92cfdbc9c1 100644 --- a/examples/recipes/src/request_response/RequestResponseExample.tsx +++ b/examples/recipes/src/request_response/RequestResponseExample.tsx @@ -19,7 +19,8 @@ export const RequestResponseExample = () => { }, }) - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced setSynced(true) } diff --git a/examples/tauri-sqlite/src/Example.tsx b/examples/tauri-sqlite/src/Example.tsx index 834162790b..603fde5a5c 100644 --- a/examples/tauri-sqlite/src/Example.tsx +++ b/examples/tauri-sqlite/src/Example.tsx @@ -66,7 +66,8 @@ const ExampleComponent = () => { // Resolves when the shape subscription has been established. const shape = await db.items.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced } diff --git a/examples/web-pglite/src/Example.tsx b/examples/web-pglite/src/Example.tsx index 177ca18c11..36612b1e7d 100644 --- a/examples/web-pglite/src/Example.tsx +++ b/examples/web-pglite/src/Example.tsx @@ -15,7 +15,8 @@ export const Example = () => { // Resolves when the shape subscription has been established. const shape = await db.items.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced } diff --git a/examples/web-wa-sqlite-vuejs/src/ElectricProvider.vue b/examples/web-wa-sqlite-vuejs/src/ElectricProvider.vue index 08d33517aa..5255c39b3f 100644 --- a/examples/web-wa-sqlite-vuejs/src/ElectricProvider.vue +++ b/examples/web-wa-sqlite-vuejs/src/ElectricProvider.vue @@ -26,8 +26,10 @@ onMounted(async () => { // Resolves when the shape subscription has been established. const shape = await client.db.items.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced + electric.value = client }) diff --git a/examples/web-wa-sqlite/src/Example.tsx b/examples/web-wa-sqlite/src/Example.tsx index 177ca18c11..36612b1e7d 100644 --- a/examples/web-wa-sqlite/src/Example.tsx +++ b/examples/web-wa-sqlite/src/Example.tsx @@ -15,7 +15,8 @@ export const Example = () => { // Resolves when the shape subscription has been established. const shape = await db.items.sync() - // Resolves when the data has been synced into the local database. + // Resolves when the initial data for the shape + // has been synced into the local database. await shape.synced }