@tanstack/powersync-db-collection 0.1.37 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/definitions.cjs.map +1 -1
- package/dist/cjs/definitions.d.cts +34 -3
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/powersync.cjs +233 -78
- package/dist/cjs/powersync.cjs.map +1 -1
- package/dist/cjs/sqlite-compiler.cjs +219 -0
- package/dist/cjs/sqlite-compiler.cjs.map +1 -0
- package/dist/cjs/sqlite-compiler.d.cts +42 -0
- package/dist/esm/definitions.d.ts +34 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/powersync.js +233 -78
- package/dist/esm/powersync.js.map +1 -1
- package/dist/esm/sqlite-compiler.d.ts +42 -0
- package/dist/esm/sqlite-compiler.js +219 -0
- package/dist/esm/sqlite-compiler.js.map +1 -0
- package/package.json +7 -6
- package/src/definitions.ts +40 -2
- package/src/index.ts +1 -0
- package/src/powersync.ts +325 -89
- package/src/sqlite-compiler.ts +354 -0
package/src/powersync.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { DiffTriggerOperation, sanitizeSQL } from '@powersync/common'
|
|
2
|
+
import { or } from '@tanstack/db'
|
|
3
|
+
import { compileSQLite } from './sqlite-compiler'
|
|
2
4
|
import { PendingOperationStore } from './PendingOperationStore'
|
|
3
5
|
import { PowerSyncTransactor } from './PowerSyncTransactor'
|
|
4
6
|
import { DEFAULT_BATCH_SIZE } from './definitions'
|
|
5
7
|
import { asPowerSyncRecord, mapOperation } from './helpers'
|
|
6
8
|
import { convertTableToSchema } from './schema'
|
|
7
9
|
import { serializeForSQLite } from './serialization'
|
|
10
|
+
import type {
|
|
11
|
+
CleanupFn,
|
|
12
|
+
LoadSubsetOptions,
|
|
13
|
+
OperationType,
|
|
14
|
+
SyncConfig,
|
|
15
|
+
} from '@tanstack/db'
|
|
8
16
|
import type {
|
|
9
17
|
AnyTableColumnType,
|
|
10
18
|
ExtractedTable,
|
|
@@ -24,9 +32,8 @@ import type {
|
|
|
24
32
|
PowerSyncCollectionUtils,
|
|
25
33
|
} from './definitions'
|
|
26
34
|
import type { PendingOperation } from './PendingOperationStore'
|
|
27
|
-
import type { SyncConfig } from '@tanstack/db'
|
|
28
35
|
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
29
|
-
import type { Table, TriggerDiffRecord } from '@powersync/common'
|
|
36
|
+
import type { LockContext, Table, TriggerDiffRecord } from '@powersync/common'
|
|
30
37
|
|
|
31
38
|
/**
|
|
32
39
|
* Creates PowerSync collection options for use with a standard Collection.
|
|
@@ -225,6 +232,7 @@ export function powerSyncCollectionOptions<
|
|
|
225
232
|
table,
|
|
226
233
|
schema: inputSchema,
|
|
227
234
|
syncBatchSize = DEFAULT_BATCH_SIZE,
|
|
235
|
+
syncMode = 'eager',
|
|
228
236
|
...restConfig
|
|
229
237
|
} = config
|
|
230
238
|
|
|
@@ -296,134 +304,361 @@ export function powerSyncCollectionOptions<
|
|
|
296
304
|
*/
|
|
297
305
|
const sync: SyncConfig<OutputType, string> = {
|
|
298
306
|
sync: (params) => {
|
|
299
|
-
const { begin, write, commit, markReady } = params
|
|
307
|
+
const { begin, write, collection, commit, markReady } = params
|
|
300
308
|
const abortController = new AbortController()
|
|
301
309
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
`Sync is starting for ${viewName} into ${trackedTableName}`,
|
|
306
|
-
)
|
|
307
|
-
database.onChangeWithCallback(
|
|
308
|
-
{
|
|
309
|
-
onChange: async () => {
|
|
310
|
-
await database
|
|
311
|
-
.writeTransaction(async (context) => {
|
|
312
|
-
begin()
|
|
313
|
-
const operations = await context.getAll<TriggerDiffRecord>(
|
|
314
|
-
`SELECT * FROM ${trackedTableName} ORDER BY timestamp ASC`,
|
|
315
|
-
)
|
|
316
|
-
const pendingOperations: Array<PendingOperation> = []
|
|
317
|
-
|
|
318
|
-
for (const op of operations) {
|
|
319
|
-
const { id, operation, timestamp, value } = op
|
|
320
|
-
const parsedValue = deserializeSyncRow({
|
|
321
|
-
id,
|
|
322
|
-
...JSON.parse(value),
|
|
323
|
-
})
|
|
324
|
-
const parsedPreviousValue =
|
|
325
|
-
op.operation == DiffTriggerOperation.UPDATE
|
|
326
|
-
? deserializeSyncRow({
|
|
327
|
-
id,
|
|
328
|
-
...JSON.parse(op.previous_value),
|
|
329
|
-
})
|
|
330
|
-
: undefined
|
|
331
|
-
write({
|
|
332
|
-
type: mapOperation(operation),
|
|
333
|
-
value: parsedValue,
|
|
334
|
-
previousValue: parsedPreviousValue,
|
|
335
|
-
})
|
|
336
|
-
pendingOperations.push({
|
|
337
|
-
id,
|
|
338
|
-
operation,
|
|
339
|
-
timestamp,
|
|
340
|
-
tableName: viewName,
|
|
341
|
-
})
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// clear the current operations
|
|
345
|
-
await context.execute(`DELETE FROM ${trackedTableName}`)
|
|
346
|
-
|
|
347
|
-
commit()
|
|
348
|
-
pendingOperationStore.resolvePendingFor(pendingOperations)
|
|
349
|
-
})
|
|
350
|
-
.catch((error) => {
|
|
351
|
-
database.logger.error(
|
|
352
|
-
`An error has been detected in the sync handler`,
|
|
353
|
-
error,
|
|
354
|
-
)
|
|
355
|
-
})
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
signal: abortController.signal,
|
|
360
|
-
triggerImmediate: false,
|
|
361
|
-
tables: [trackedTableName],
|
|
362
|
-
},
|
|
363
|
-
)
|
|
310
|
+
let disposeTracking:
|
|
311
|
+
| ((options?: { context?: LockContext }) => Promise<void>)
|
|
312
|
+
| null = null
|
|
364
313
|
|
|
365
|
-
|
|
314
|
+
if (syncMode === `eager`) {
|
|
315
|
+
return runEagerSync()
|
|
316
|
+
} else {
|
|
317
|
+
return runOnDemandSync()
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function createDiffTrigger(options: {
|
|
321
|
+
setupContext?: LockContext
|
|
322
|
+
when: Record<DiffTriggerOperation, string>
|
|
323
|
+
writeType: (rowId: string) => OperationType
|
|
324
|
+
batchQuery: (
|
|
325
|
+
lockContext: LockContext,
|
|
326
|
+
batchSize: number,
|
|
327
|
+
cursor: number,
|
|
328
|
+
) => Promise<Array<TableType>>
|
|
329
|
+
onReady: () => void
|
|
330
|
+
}) {
|
|
331
|
+
const { setupContext, when, writeType, batchQuery, onReady } = options
|
|
332
|
+
|
|
333
|
+
return await database.triggers.createDiffTrigger({
|
|
366
334
|
source: viewName,
|
|
367
335
|
destination: trackedTableName,
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
[DiffTriggerOperation.UPDATE]: `TRUE`,
|
|
371
|
-
[DiffTriggerOperation.DELETE]: `TRUE`,
|
|
372
|
-
},
|
|
336
|
+
setupContext,
|
|
337
|
+
when,
|
|
373
338
|
hooks: {
|
|
374
339
|
beforeCreate: async (context) => {
|
|
375
340
|
let currentBatchCount = syncBatchSize
|
|
376
341
|
let cursor = 0
|
|
377
342
|
while (currentBatchCount == syncBatchSize) {
|
|
378
343
|
begin()
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
344
|
+
|
|
345
|
+
const batchItems = await batchQuery(
|
|
346
|
+
context,
|
|
347
|
+
syncBatchSize,
|
|
348
|
+
cursor,
|
|
382
349
|
)
|
|
383
350
|
currentBatchCount = batchItems.length
|
|
384
351
|
cursor += currentBatchCount
|
|
385
352
|
for (const row of batchItems) {
|
|
386
353
|
write({
|
|
387
|
-
type:
|
|
354
|
+
type: writeType(row.id),
|
|
388
355
|
value: deserializeSyncRow(row),
|
|
389
356
|
})
|
|
390
357
|
}
|
|
391
358
|
commit()
|
|
392
359
|
}
|
|
393
|
-
|
|
360
|
+
onReady()
|
|
394
361
|
database.logger.info(
|
|
395
362
|
`Sync is ready for ${viewName} into ${trackedTableName}`,
|
|
396
363
|
)
|
|
397
364
|
},
|
|
398
365
|
},
|
|
399
366
|
})
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function flushDiffRecords(): Promise<void> {
|
|
370
|
+
await database
|
|
371
|
+
.writeTransaction(async (context) => {
|
|
372
|
+
await flushDiffRecordsWithContext(context)
|
|
373
|
+
})
|
|
374
|
+
.catch((error) => {
|
|
375
|
+
database.logger.error(
|
|
376
|
+
`An error has been detected in the sync handler`,
|
|
377
|
+
error,
|
|
378
|
+
)
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// We can use this directly if we want to pair a flush with dispose+recreate diff trigger.
|
|
383
|
+
async function flushDiffRecordsWithContext(
|
|
384
|
+
context: LockContext,
|
|
385
|
+
): Promise<void> {
|
|
386
|
+
try {
|
|
387
|
+
begin()
|
|
388
|
+
const operations = await context.getAll<TriggerDiffRecord>(
|
|
389
|
+
`SELECT * FROM ${trackedTableName} ORDER BY operation_id ASC`,
|
|
390
|
+
)
|
|
391
|
+
const pendingOperations: Array<PendingOperation> = []
|
|
392
|
+
|
|
393
|
+
for (const op of operations) {
|
|
394
|
+
const { id, operation, timestamp, value } = op
|
|
395
|
+
const parsedValue = deserializeSyncRow({
|
|
396
|
+
id,
|
|
397
|
+
...JSON.parse(value),
|
|
398
|
+
})
|
|
399
|
+
const parsedPreviousValue =
|
|
400
|
+
op.operation == DiffTriggerOperation.UPDATE
|
|
401
|
+
? deserializeSyncRow({
|
|
402
|
+
id,
|
|
403
|
+
...JSON.parse(op.previous_value),
|
|
404
|
+
})
|
|
405
|
+
: undefined
|
|
406
|
+
write({
|
|
407
|
+
type: mapOperation(operation),
|
|
408
|
+
value: parsedValue,
|
|
409
|
+
previousValue: parsedPreviousValue,
|
|
410
|
+
})
|
|
411
|
+
pendingOperations.push({
|
|
412
|
+
id,
|
|
413
|
+
operation,
|
|
414
|
+
timestamp,
|
|
415
|
+
tableName: viewName,
|
|
416
|
+
})
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// clear the current operations
|
|
420
|
+
await context.execute(`DELETE FROM ${trackedTableName}`)
|
|
421
|
+
|
|
422
|
+
commit()
|
|
423
|
+
pendingOperationStore.resolvePendingFor(pendingOperations)
|
|
424
|
+
} catch (error) {
|
|
425
|
+
database.logger.error(
|
|
426
|
+
`An error has been detected in the sync handler`,
|
|
427
|
+
error,
|
|
428
|
+
)
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// The sync function needs to be synchronous.
|
|
433
|
+
async function start(afterOnChangeRegistered?: () => Promise<void>) {
|
|
434
|
+
database.logger.info(
|
|
435
|
+
`Sync is starting for ${viewName} into ${trackedTableName}`,
|
|
436
|
+
)
|
|
437
|
+
database.onChangeWithCallback(
|
|
438
|
+
{
|
|
439
|
+
onChange: async () => {
|
|
440
|
+
await flushDiffRecords()
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
signal: abortController.signal,
|
|
445
|
+
triggerImmediate: false,
|
|
446
|
+
tables: [trackedTableName],
|
|
447
|
+
},
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
await afterOnChangeRegistered?.()
|
|
400
451
|
|
|
401
452
|
// If the abort controller was aborted while processing the request above
|
|
402
453
|
if (abortController.signal.aborted) {
|
|
403
|
-
await disposeTracking()
|
|
454
|
+
await disposeTracking?.()
|
|
404
455
|
} else {
|
|
405
456
|
abortController.signal.addEventListener(
|
|
406
457
|
`abort`,
|
|
407
|
-
() => {
|
|
408
|
-
disposeTracking()
|
|
458
|
+
async () => {
|
|
459
|
+
await disposeTracking?.()
|
|
409
460
|
},
|
|
410
461
|
{ once: true },
|
|
411
462
|
)
|
|
412
463
|
}
|
|
413
464
|
}
|
|
414
465
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
),
|
|
420
|
-
)
|
|
466
|
+
// Eager mode.
|
|
467
|
+
// Registers a diff trigger for the entire table.
|
|
468
|
+
function runEagerSync() {
|
|
469
|
+
let onUnload: CleanupFn | void | null = null
|
|
421
470
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
471
|
+
start(async () => {
|
|
472
|
+
onUnload = await restConfig.onLoad?.()
|
|
473
|
+
|
|
474
|
+
disposeTracking = await createDiffTrigger({
|
|
475
|
+
when: {
|
|
476
|
+
[DiffTriggerOperation.INSERT]: `TRUE`,
|
|
477
|
+
[DiffTriggerOperation.UPDATE]: `TRUE`,
|
|
478
|
+
[DiffTriggerOperation.DELETE]: `TRUE`,
|
|
479
|
+
},
|
|
480
|
+
writeType: (_rowId: string) => `insert`,
|
|
481
|
+
batchQuery: (
|
|
482
|
+
lockContext: LockContext,
|
|
483
|
+
batchSize: number,
|
|
484
|
+
cursor: number,
|
|
485
|
+
) =>
|
|
486
|
+
lockContext.getAll<TableType>(
|
|
487
|
+
sanitizeSQL`SELECT * FROM ${viewName} LIMIT ? OFFSET ?`,
|
|
488
|
+
[batchSize, cursor],
|
|
489
|
+
),
|
|
490
|
+
onReady: () => markReady(),
|
|
491
|
+
})
|
|
492
|
+
}).catch((error) =>
|
|
493
|
+
database.logger.error(
|
|
494
|
+
`Could not start syncing process for ${viewName} into ${trackedTableName}`,
|
|
495
|
+
error,
|
|
496
|
+
),
|
|
425
497
|
)
|
|
426
|
-
|
|
498
|
+
|
|
499
|
+
return () => {
|
|
500
|
+
database.logger.info(
|
|
501
|
+
`Sync has been stopped for ${viewName} into ${trackedTableName}`,
|
|
502
|
+
)
|
|
503
|
+
abortController.abort()
|
|
504
|
+
onUnload?.()
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// On-demand mode.
|
|
509
|
+
// Registers a diff trigger for the active WHERE expressions.
|
|
510
|
+
function runOnDemandSync() {
|
|
511
|
+
let onUnloadSubset: CleanupFn | void | null = null
|
|
512
|
+
|
|
513
|
+
start().catch((error) =>
|
|
514
|
+
database.logger.error(
|
|
515
|
+
`Could not start syncing process for ${viewName} into ${trackedTableName}`,
|
|
516
|
+
error,
|
|
517
|
+
),
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
// Tracks all active WHERE expressions for on-demand sync filtering.
|
|
521
|
+
// Each loadSubset call pushes its predicate; unloadSubset removes it.
|
|
522
|
+
const activeWhereExpressions: Array<LoadSubsetOptions['where']> = []
|
|
523
|
+
|
|
524
|
+
const loadSubset = async (
|
|
525
|
+
options?: LoadSubsetOptions,
|
|
526
|
+
): Promise<void> => {
|
|
527
|
+
if (options) {
|
|
528
|
+
activeWhereExpressions.push(options.where)
|
|
529
|
+
onUnloadSubset = await restConfig.onLoadSubset?.(options)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (activeWhereExpressions.length === 0) {
|
|
533
|
+
await database.writeLock(async (ctx) => {
|
|
534
|
+
await flushDiffRecordsWithContext(ctx)
|
|
535
|
+
await disposeTracking?.({ context: ctx })
|
|
536
|
+
})
|
|
537
|
+
return
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const combinedWhere =
|
|
541
|
+
activeWhereExpressions.length === 1
|
|
542
|
+
? activeWhereExpressions[0]
|
|
543
|
+
: or(
|
|
544
|
+
activeWhereExpressions[0],
|
|
545
|
+
activeWhereExpressions[1],
|
|
546
|
+
...activeWhereExpressions.slice(2),
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
const compiledNewData = compileSQLite(
|
|
550
|
+
{ where: combinedWhere },
|
|
551
|
+
{ jsonColumn: 'NEW.data' },
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
const compiledOldData = compileSQLite(
|
|
555
|
+
{ where: combinedWhere },
|
|
556
|
+
{ jsonColumn: 'OLD.data' },
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
const compiledView = compileSQLite({ where: combinedWhere })
|
|
560
|
+
|
|
561
|
+
const newDataWhenClause = toInlinedWhereClause(compiledNewData)
|
|
562
|
+
const oldDataWhenClause = toInlinedWhereClause(compiledOldData)
|
|
563
|
+
const viewWhereClause = toInlinedWhereClause(compiledView)
|
|
564
|
+
|
|
565
|
+
await database.writeLock(async (ctx) => {
|
|
566
|
+
await flushDiffRecordsWithContext(ctx)
|
|
567
|
+
await disposeTracking?.({ context: ctx })
|
|
568
|
+
|
|
569
|
+
disposeTracking = await createDiffTrigger({
|
|
570
|
+
setupContext: ctx,
|
|
571
|
+
when: {
|
|
572
|
+
[DiffTriggerOperation.INSERT]: newDataWhenClause,
|
|
573
|
+
[DiffTriggerOperation.UPDATE]: `(${newDataWhenClause}) OR (${oldDataWhenClause})`,
|
|
574
|
+
[DiffTriggerOperation.DELETE]: oldDataWhenClause,
|
|
575
|
+
},
|
|
576
|
+
writeType: (rowId: string) =>
|
|
577
|
+
collection.has(rowId) ? `update` : `insert`,
|
|
578
|
+
batchQuery: (
|
|
579
|
+
lockContext: LockContext,
|
|
580
|
+
batchSize: number,
|
|
581
|
+
cursor: number,
|
|
582
|
+
) =>
|
|
583
|
+
lockContext.getAll<TableType>(
|
|
584
|
+
`SELECT * FROM ${viewName} WHERE ${viewWhereClause} LIMIT ? OFFSET ?`,
|
|
585
|
+
[batchSize, cursor],
|
|
586
|
+
),
|
|
587
|
+
onReady: () => {},
|
|
588
|
+
})
|
|
589
|
+
})
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const toInlinedWhereClause = (compiled: {
|
|
593
|
+
where?: string
|
|
594
|
+
params: Array<unknown>
|
|
595
|
+
}): string => {
|
|
596
|
+
if (!compiled.where) return 'TRUE'
|
|
597
|
+
const sqlParts = compiled.where.split('?')
|
|
598
|
+
return sanitizeSQL(
|
|
599
|
+
sqlParts as unknown as TemplateStringsArray,
|
|
600
|
+
...compiled.params,
|
|
601
|
+
)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const unloadSubset = async (options: LoadSubsetOptions) => {
|
|
605
|
+
onUnloadSubset?.()
|
|
606
|
+
|
|
607
|
+
const idx = activeWhereExpressions.indexOf(options.where)
|
|
608
|
+
if (idx !== -1) {
|
|
609
|
+
activeWhereExpressions.splice(idx, 1)
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Evict rows that were exclusively loaded by the departing predicate.
|
|
613
|
+
// These are rows matching the departing WHERE that are no longer covered
|
|
614
|
+
// by any remaining active predicate.
|
|
615
|
+
const compiledDeparting = compileSQLite({ where: options.where })
|
|
616
|
+
const departingWhereSQL = toInlinedWhereClause(compiledDeparting)
|
|
617
|
+
|
|
618
|
+
let evictionSQL: string
|
|
619
|
+
if (activeWhereExpressions.length === 0) {
|
|
620
|
+
evictionSQL = `SELECT id FROM ${viewName} WHERE ${departingWhereSQL}`
|
|
621
|
+
} else {
|
|
622
|
+
const combinedRemaining =
|
|
623
|
+
activeWhereExpressions.length === 1
|
|
624
|
+
? activeWhereExpressions[0]!
|
|
625
|
+
: or(
|
|
626
|
+
activeWhereExpressions[0],
|
|
627
|
+
activeWhereExpressions[1],
|
|
628
|
+
...activeWhereExpressions.slice(2),
|
|
629
|
+
)
|
|
630
|
+
const compiledRemaining = compileSQLite({
|
|
631
|
+
where: combinedRemaining,
|
|
632
|
+
})
|
|
633
|
+
const remainingWhereSQL = toInlinedWhereClause(compiledRemaining)
|
|
634
|
+
evictionSQL = `SELECT id FROM ${viewName} WHERE (${departingWhereSQL}) AND NOT (${remainingWhereSQL})`
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const rowsToEvict = await database.getAll<{ id: string }>(evictionSQL)
|
|
638
|
+
if (rowsToEvict.length > 0) {
|
|
639
|
+
begin()
|
|
640
|
+
for (const { id } of rowsToEvict) {
|
|
641
|
+
write({ type: `delete`, key: id })
|
|
642
|
+
}
|
|
643
|
+
commit()
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Recreate the diff trigger for the remaining active WHERE expressions.
|
|
647
|
+
await loadSubset()
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
markReady()
|
|
651
|
+
|
|
652
|
+
return {
|
|
653
|
+
cleanup: () => {
|
|
654
|
+
database.logger.info(
|
|
655
|
+
`Sync has been stopped for ${viewName} into ${trackedTableName}`,
|
|
656
|
+
)
|
|
657
|
+
abortController.abort()
|
|
658
|
+
},
|
|
659
|
+
loadSubset: (options: LoadSubsetOptions) => loadSubset(options),
|
|
660
|
+
unloadSubset: (options: LoadSubsetOptions) => unloadSubset(options),
|
|
661
|
+
}
|
|
427
662
|
}
|
|
428
663
|
},
|
|
429
664
|
// Expose the getSyncMetadata function
|
|
@@ -442,6 +677,7 @@ export function powerSyncCollectionOptions<
|
|
|
442
677
|
getKey,
|
|
443
678
|
// Syncing should start immediately since we need to monitor the changes for mutations
|
|
444
679
|
startSync: true,
|
|
680
|
+
syncMode,
|
|
445
681
|
sync,
|
|
446
682
|
onInsert: async (params) => {
|
|
447
683
|
// The transaction here should only ever contain a single insert mutation
|