Skip to content

Commit 53fa027

Browse files
committed
add sync mode to base colleciton
1 parent b1aeceb commit 53fa027

File tree

5 files changed

+47
-1
lines changed

5 files changed

+47
-1
lines changed

packages/db/src/collection/sync.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
CollectionConfigurationError,
23
CollectionIsInErrorStateError,
34
DuplicateKeySyncError,
45
NoPendingSyncTransactionCommitError,
@@ -33,6 +34,7 @@ export class CollectionSyncManager<
3334
private _events!: CollectionEventsManager
3435
private config!: CollectionConfig<TOutput, TKey, TSchema>
3536
private id: string
37+
private syncMode: `eager` | `on-demand`
3638

3739
public preloadPromise: Promise<void> | null = null
3840
public syncCleanupFn: (() => void) | null = null
@@ -48,6 +50,7 @@ export class CollectionSyncManager<
4850
constructor(config: CollectionConfig<TOutput, TKey, TSchema>, id: string) {
4951
this.config = config
5052
this.id = id
53+
this.syncMode = config.syncMode ?? `eager`
5154
}
5255

5356
setDeps(deps: {
@@ -197,6 +200,14 @@ export class CollectionSyncManager<
197200

198201
// Store loadSubset function if provided
199202
this.syncLoadSubsetFn = syncRes?.loadSubset ?? null
203+
204+
// Validate: on-demand mode requires a loadSubset function
205+
if (this.syncMode === `on-demand` && !this.syncLoadSubsetFn) {
206+
throw new CollectionConfigurationError(
207+
`Collection "${this.id}" is configured with syncMode "on-demand" but the sync function did not return a loadSubset handler. ` +
208+
`Either provide a loadSubset handler or use syncMode "eager".`
209+
)
210+
}
200211
} catch (error) {
201212
this.lifecycle.setStatus(`error`)
202213
throw error
@@ -292,9 +303,14 @@ export class CollectionSyncManager<
292303
* @param options Options to control what data is being loaded
293304
* @returns If data loading is asynchronous, this method returns a promise that resolves when the data is loaded.
294305
* If data loading is synchronous, the data is loaded when the method returns.
295-
* Returns undefined if no sync function is configured.
306+
* Returns undefined if no sync function is configured or if syncMode is 'eager'.
296307
*/
297308
public loadSubset(options: LoadSubsetOptions): Promise<void> | undefined {
309+
// Bypass loadSubset when syncMode is 'eager'
310+
if (this.syncMode === `eager`) {
311+
return undefined
312+
}
313+
298314
if (this.syncLoadSubsetFn) {
299315
const result = this.syncLoadSubsetFn(options)
300316

packages/db/src/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,16 @@ export type CollectionStatus =
380380
/** Collection has been cleaned up and resources freed */
381381
| `cleaned-up`
382382

383+
/**
384+
* @default `eager`
385+
* @description
386+
* Collections have two modes of sync: eager and on-demand.
387+
* - eager: syncs all data immediately on preload
388+
* - on-demand: syncs data in incremental snapshots when the collection is queried
389+
* The exact implementation of the sync mode is up to the sync implementation.
390+
*/
391+
export type SyncMode = `eager` | `on-demand`
392+
383393
export interface BaseCollectionConfig<
384394
T extends object = Record<string, unknown>,
385395
TKey extends string | number = string | number,
@@ -441,6 +451,15 @@ export interface BaseCollectionConfig<
441451
* compare: (x, y) => x.createdAt.getTime() - y.createdAt.getTime()
442452
*/
443453
compare?: (x: T, y: T) => number
454+
/**
455+
* The mode of sync to use for the collection.
456+
* @default `eager`
457+
* @description
458+
* - `eager`: syncs all data immediately on preload
459+
* - `on-demand`: syncs data in incremental snapshots when the collection is queried
460+
* The exact implementation of the sync mode is up to the sync implementation.
461+
*/
462+
syncMode?: SyncMode
444463
/**
445464
* Optional asynchronous handler function called before an insert operation
446465
* @param params Object containing transaction and collection information

packages/db/tests/collection-subscription.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe(`CollectionSubscription status tracking`, () => {
2929
const collection = createCollection<{ id: string; value: string }>({
3030
id: `test`,
3131
getKey: (item) => item.id,
32+
syncMode: `on-demand`,
3233
sync: {
3334
sync: ({ markReady }) => {
3435
markReady()
@@ -70,6 +71,7 @@ describe(`CollectionSubscription status tracking`, () => {
7071
const collection = createCollection<{ id: string; value: string }>({
7172
id: `test`,
7273
getKey: (item) => item.id,
74+
syncMode: `on-demand`,
7375
sync: {
7476
sync: ({ markReady }) => {
7577
markReady()
@@ -102,6 +104,7 @@ describe(`CollectionSubscription status tracking`, () => {
102104
const collection = createCollection<{ id: string; value: string }>({
103105
id: `test`,
104106
getKey: (item) => item.id,
107+
syncMode: `on-demand`,
105108
sync: {
106109
sync: ({ markReady }) => {
107110
markReady()
@@ -160,6 +163,7 @@ describe(`CollectionSubscription status tracking`, () => {
160163
const collection = createCollection<{ id: string; value: string }>({
161164
id: `test`,
162165
getKey: (item) => item.id,
166+
syncMode: `on-demand`,
163167
sync: {
164168
sync: ({ markReady }) => {
165169
markReady()
@@ -215,6 +219,7 @@ describe(`CollectionSubscription status tracking`, () => {
215219
const collection = createCollection<{ id: string; value: string }>({
216220
id: `test`,
217221
getKey: (item) => item.id,
222+
syncMode: `on-demand`,
218223
sync: {
219224
sync: ({ markReady }) => {
220225
markReady()

packages/db/tests/collection.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,7 @@ describe(`Collection isLoadingMore property`, () => {
13811381
const collection = createCollection<{ id: string; value: string }>({
13821382
id: `test`,
13831383
getKey: (item) => item.id,
1384+
syncMode: `on-demand`,
13841385
startSync: true,
13851386
sync: {
13861387
sync: ({ markReady }) => {
@@ -1412,6 +1413,7 @@ describe(`Collection isLoadingMore property`, () => {
14121413
const collection = createCollection<{ id: string; value: string }>({
14131414
id: `test`,
14141415
getKey: (item) => item.id,
1416+
syncMode: `on-demand`,
14151417
startSync: true,
14161418
sync: {
14171419
sync: ({ markReady }) => {
@@ -1440,6 +1442,7 @@ describe(`Collection isLoadingMore property`, () => {
14401442
const collection = createCollection<{ id: string; value: string }>({
14411443
id: `test`,
14421444
getKey: (item) => item.id,
1445+
syncMode: `on-demand`,
14431446
startSync: true,
14441447
sync: {
14451448
sync: ({ markReady }) => {
@@ -1489,6 +1492,7 @@ describe(`Collection isLoadingMore property`, () => {
14891492
const collection = createCollection<{ id: string; value: string }>({
14901493
id: `test`,
14911494
getKey: (item) => item.id,
1495+
syncMode: `on-demand`,
14921496
startSync: true,
14931497
sync: {
14941498
sync: ({ markReady }) => {
@@ -1542,6 +1546,7 @@ describe(`Collection isLoadingMore property`, () => {
15421546
const collection = createCollection<{ id: string; value: string }>({
15431547
id: `test`,
15441548
getKey: (item) => item.id,
1549+
syncMode: `on-demand`,
15451550
startSync: true,
15461551
sync: {
15471552
sync: ({ markReady }) => {

packages/db/tests/query/live-query-collection.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ describe(`createLiveQueryCollection`, () => {
990990
const sourceCollection = createCollection<{ id: string; value: number }>({
991991
id: `source`,
992992
getKey: (item) => item.id,
993+
syncMode: `on-demand`,
993994
sync: {
994995
sync: ({ markReady, begin, write, commit }) => {
995996
begin()

0 commit comments

Comments
 (0)