@powersync/common 0.0.0-dev-20250714151300 → 0.0.0-dev-20250715104704
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/bundle.cjs +5 -5
- package/dist/bundle.mjs +3 -3
- package/lib/client/AbstractPowerSyncDatabase.d.ts +5 -56
- package/lib/client/AbstractPowerSyncDatabase.js +32 -96
- package/lib/client/ConnectionManager.d.ts +4 -4
- package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +2 -2
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +9 -5
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +21 -18
- package/lib/db/schema/RawTable.d.ts +57 -0
- package/lib/db/schema/RawTable.js +28 -0
- package/lib/db/schema/Schema.d.ts +14 -0
- package/lib/db/schema/Schema.js +20 -1
- package/lib/index.d.ts +1 -7
- package/lib/index.js +1 -7
- package/lib/utils/BaseObserver.d.ts +4 -3
- package/lib/utils/BaseObserver.js +0 -3
- package/package.json +1 -1
- package/lib/client/CustomQuery.d.ts +0 -25
- package/lib/client/CustomQuery.js +0 -41
- package/lib/client/Query.d.ts +0 -79
- package/lib/client/Query.js +0 -1
- package/lib/client/watched/GetAllQuery.d.ts +0 -32
- package/lib/client/watched/GetAllQuery.js +0 -24
- package/lib/client/watched/WatchedQuery.d.ts +0 -93
- package/lib/client/watched/WatchedQuery.js +0 -12
- package/lib/client/watched/processors/AbstractQueryProcessor.d.ts +0 -67
- package/lib/client/watched/processors/AbstractQueryProcessor.js +0 -136
- package/lib/client/watched/processors/DifferentialQueryProcessor.d.ts +0 -129
- package/lib/client/watched/processors/DifferentialQueryProcessor.js +0 -175
- package/lib/client/watched/processors/OnChangeQueryProcessor.d.ts +0 -27
- package/lib/client/watched/processors/OnChangeQueryProcessor.js +0 -74
- package/lib/client/watched/processors/comparators.d.ts +0 -24
- package/lib/client/watched/processors/comparators.js +0 -33
- package/lib/utils/MetaBaseObserver.d.ts +0 -29
- package/lib/utils/MetaBaseObserver.js +0 -50
|
@@ -6,15 +6,12 @@ import { UploadQueueStats } from '../db/crud/UploadQueueStatus.js';
|
|
|
6
6
|
import { Schema } from '../db/schema/Schema.js';
|
|
7
7
|
import { BaseObserver } from '../utils/BaseObserver.js';
|
|
8
8
|
import { ConnectionManager } from './ConnectionManager.js';
|
|
9
|
-
import { ArrayQueryDefinition, Query } from './Query.js';
|
|
10
9
|
import { SQLOpenFactory, SQLOpenOptions } from './SQLOpenFactory.js';
|
|
11
10
|
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
12
11
|
import { BucketStorageAdapter } from './sync/bucket/BucketStorageAdapter.js';
|
|
13
12
|
import { CrudBatch } from './sync/bucket/CrudBatch.js';
|
|
14
13
|
import { CrudTransaction } from './sync/bucket/CrudTransaction.js';
|
|
15
14
|
import { StreamingSyncImplementation, StreamingSyncImplementationListener, type AdditionalConnectionOptions, type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions } from './sync/stream/AbstractStreamingSyncImplementation.js';
|
|
16
|
-
import { WatchCompatibleQuery } from './watched/WatchedQuery.js';
|
|
17
|
-
import { WatchedQueryComparator } from './watched/processors/comparators.js';
|
|
18
15
|
export interface DisconnectAndClearOptions {
|
|
19
16
|
/** When set to false, data in local-only tables is preserved. */
|
|
20
17
|
clearLocal?: boolean;
|
|
@@ -47,7 +44,7 @@ export interface PowerSyncDatabaseOptionsWithOpenFactory extends BasePowerSyncDa
|
|
|
47
44
|
export interface PowerSyncDatabaseOptionsWithSettings extends BasePowerSyncDatabaseOptions {
|
|
48
45
|
database: SQLOpenOptions;
|
|
49
46
|
}
|
|
50
|
-
export interface
|
|
47
|
+
export interface SQLWatchOptions {
|
|
51
48
|
signal?: AbortSignal;
|
|
52
49
|
tables?: string[];
|
|
53
50
|
/** The minimum interval between queries. */
|
|
@@ -59,17 +56,6 @@ export interface SQLOnChangeOptions {
|
|
|
59
56
|
* by not removing PowerSync table name prefixes
|
|
60
57
|
*/
|
|
61
58
|
rawTableNames?: boolean;
|
|
62
|
-
/**
|
|
63
|
-
* Emits an empty result set immediately
|
|
64
|
-
*/
|
|
65
|
-
triggerImmediate?: boolean;
|
|
66
|
-
}
|
|
67
|
-
export interface SQLWatchOptions extends SQLOnChangeOptions {
|
|
68
|
-
/**
|
|
69
|
-
* Optional comparator which will be used to compare the results of the query.
|
|
70
|
-
* The watched query will only yield results if the comparator returns false.
|
|
71
|
-
*/
|
|
72
|
-
comparator?: WatchedQueryComparator<QueryResult>;
|
|
73
59
|
}
|
|
74
60
|
export interface WatchOnChangeEvent {
|
|
75
61
|
changedTables: string[];
|
|
@@ -85,8 +71,6 @@ export interface WatchOnChangeHandler {
|
|
|
85
71
|
export interface PowerSyncDBListener extends StreamingSyncImplementationListener {
|
|
86
72
|
initialized: () => void;
|
|
87
73
|
schemaChanged: (schema: Schema) => void;
|
|
88
|
-
closing: () => Promise<void> | void;
|
|
89
|
-
closed: () => Promise<void> | void;
|
|
90
74
|
}
|
|
91
75
|
export interface PowerSyncCloseOptions {
|
|
92
76
|
/**
|
|
@@ -97,6 +81,7 @@ export interface PowerSyncCloseOptions {
|
|
|
97
81
|
disconnect?: boolean;
|
|
98
82
|
}
|
|
99
83
|
export declare const DEFAULT_POWERSYNC_CLOSE_OPTIONS: PowerSyncCloseOptions;
|
|
84
|
+
export declare const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
100
85
|
export declare const DEFAULT_POWERSYNC_DB_OPTIONS: {
|
|
101
86
|
retryDelayMs: number;
|
|
102
87
|
logger: Logger.ILogger;
|
|
@@ -405,42 +390,6 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
405
390
|
* ```
|
|
406
391
|
*/
|
|
407
392
|
watch(sql: string, parameters?: any[], handler?: WatchHandler, options?: SQLWatchOptions): void;
|
|
408
|
-
/**
|
|
409
|
-
* Allows defining a query which can be used to build a {@link WatchedQuery}.
|
|
410
|
-
* The defined query will be executed with {@link AbstractPowerSyncDatabase#getAll}.
|
|
411
|
-
* An optional mapper function can be provided to transform the results.
|
|
412
|
-
*
|
|
413
|
-
* @example
|
|
414
|
-
* ```javascript
|
|
415
|
-
* const watchedTodos = powersync.query({
|
|
416
|
-
* sql: `SELECT photo_id as id FROM todos WHERE photo_id IS NOT NULL`,
|
|
417
|
-
* parameters: [],
|
|
418
|
-
* mapper: (row) => ({
|
|
419
|
-
* ...row,
|
|
420
|
-
* created_at: new Date(row.created_at as string)
|
|
421
|
-
* })
|
|
422
|
-
* })
|
|
423
|
-
* .watch()
|
|
424
|
-
* // OR use .differentialWatch() for fine-grained watches.
|
|
425
|
-
* ```
|
|
426
|
-
*/
|
|
427
|
-
query<RowType>(query: ArrayQueryDefinition<RowType>): Query<RowType>;
|
|
428
|
-
/**
|
|
429
|
-
* Allows building a {@link WatchedQuery} using an existing {@link WatchCompatibleQuery}.
|
|
430
|
-
* The watched query will use the provided {@link WatchCompatibleQuery.execute} method to query results.
|
|
431
|
-
*
|
|
432
|
-
* @example
|
|
433
|
-
* ```javascript
|
|
434
|
-
*
|
|
435
|
-
* // Potentially a query from an ORM like Drizzle
|
|
436
|
-
* const query = db.select().from(lists);
|
|
437
|
-
*
|
|
438
|
-
* const watchedTodos = powersync.customQuery(query)
|
|
439
|
-
* .watch()
|
|
440
|
-
* // OR use .differentialWatch() for fine-grained watches.
|
|
441
|
-
* ```
|
|
442
|
-
*/
|
|
443
|
-
customQuery<RowType>(query: WatchCompatibleQuery<RowType[]>): Query<RowType>;
|
|
444
393
|
/**
|
|
445
394
|
* Execute a read query every time the source tables are modified.
|
|
446
395
|
* Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
|
|
@@ -489,7 +438,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
489
438
|
* }
|
|
490
439
|
* ```
|
|
491
440
|
*/
|
|
492
|
-
onChange(options?:
|
|
441
|
+
onChange(options?: SQLWatchOptions): AsyncIterable<WatchOnChangeEvent>;
|
|
493
442
|
/**
|
|
494
443
|
* See {@link onChangeWithCallback}.
|
|
495
444
|
*
|
|
@@ -504,7 +453,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
504
453
|
* }
|
|
505
454
|
* ```
|
|
506
455
|
*/
|
|
507
|
-
onChange(handler?: WatchOnChangeHandler, options?:
|
|
456
|
+
onChange(handler?: WatchOnChangeHandler, options?: SQLWatchOptions): () => void;
|
|
508
457
|
/**
|
|
509
458
|
* Invoke the provided callback on any changes to any of the specified tables.
|
|
510
459
|
*
|
|
@@ -517,7 +466,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
517
466
|
* @param options Options for configuring watch behavior
|
|
518
467
|
* @returns A dispose function to stop watching for changes
|
|
519
468
|
*/
|
|
520
|
-
onChangeWithCallback(handler?: WatchOnChangeHandler, options?:
|
|
469
|
+
onChangeWithCallback(handler?: WatchOnChangeHandler, options?: SQLWatchOptions): () => void;
|
|
521
470
|
/**
|
|
522
471
|
* Create a Stream of changes to any of the specified tables.
|
|
523
472
|
*
|
|
@@ -9,15 +9,13 @@ import { BaseObserver } from '../utils/BaseObserver.js';
|
|
|
9
9
|
import { ControlledExecutor } from '../utils/ControlledExecutor.js';
|
|
10
10
|
import { throttleTrailing } from '../utils/async.js';
|
|
11
11
|
import { ConnectionManager } from './ConnectionManager.js';
|
|
12
|
-
import { CustomQuery } from './CustomQuery.js';
|
|
13
12
|
import { isDBAdapter, isSQLOpenFactory, isSQLOpenOptions } from './SQLOpenFactory.js';
|
|
13
|
+
import { runOnSchemaChange } from './runOnSchemaChange.js';
|
|
14
14
|
import { PSInternalTable } from './sync/bucket/BucketStorageAdapter.js';
|
|
15
15
|
import { CrudBatch } from './sync/bucket/CrudBatch.js';
|
|
16
16
|
import { CrudEntry } from './sync/bucket/CrudEntry.js';
|
|
17
17
|
import { CrudTransaction } from './sync/bucket/CrudTransaction.js';
|
|
18
18
|
import { DEFAULT_CRUD_UPLOAD_THROTTLE_MS, DEFAULT_RETRY_DELAY_MS } from './sync/stream/AbstractStreamingSyncImplementation.js';
|
|
19
|
-
import { DEFAULT_WATCH_THROTTLE_MS } from './watched/WatchedQuery.js';
|
|
20
|
-
import { OnChangeQueryProcessor } from './watched/processors/OnChangeQueryProcessor.js';
|
|
21
19
|
const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
|
|
22
20
|
const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
|
|
23
21
|
clearLocal: true
|
|
@@ -25,6 +23,7 @@ const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
|
|
|
25
23
|
export const DEFAULT_POWERSYNC_CLOSE_OPTIONS = {
|
|
26
24
|
disconnect: true
|
|
27
25
|
};
|
|
26
|
+
export const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
28
27
|
export const DEFAULT_POWERSYNC_DB_OPTIONS = {
|
|
29
28
|
retryDelayMs: 5000,
|
|
30
29
|
logger: Logger.get('PowerSyncDatabase'),
|
|
@@ -299,7 +298,9 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
299
298
|
* Connects to stream of events from the PowerSync instance.
|
|
300
299
|
*/
|
|
301
300
|
async connect(connector, options) {
|
|
302
|
-
|
|
301
|
+
const resolvedOptions = options ?? {};
|
|
302
|
+
resolvedOptions.serializedSchema = this.schema.toJSON();
|
|
303
|
+
return this.connectionManager.connect(connector, resolvedOptions);
|
|
303
304
|
}
|
|
304
305
|
/**
|
|
305
306
|
* Close the sync connection.
|
|
@@ -342,7 +343,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
342
343
|
if (this.closed) {
|
|
343
344
|
return;
|
|
344
345
|
}
|
|
345
|
-
await this.iterateAsyncListeners(async (cb) => cb.closing?.());
|
|
346
346
|
const { disconnect } = options;
|
|
347
347
|
if (disconnect) {
|
|
348
348
|
await this.disconnect();
|
|
@@ -350,7 +350,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
350
350
|
await this.connectionManager.close();
|
|
351
351
|
await this.database.close();
|
|
352
352
|
this.closed = true;
|
|
353
|
-
await this.iterateAsyncListeners(async (cb) => cb.closed?.());
|
|
354
353
|
}
|
|
355
354
|
/**
|
|
356
355
|
* Get upload queue size estimate and count.
|
|
@@ -597,60 +596,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
597
596
|
const options = handlerOrOptions;
|
|
598
597
|
return this.watchWithAsyncGenerator(sql, parameters, options);
|
|
599
598
|
}
|
|
600
|
-
/**
|
|
601
|
-
* Allows defining a query which can be used to build a {@link WatchedQuery}.
|
|
602
|
-
* The defined query will be executed with {@link AbstractPowerSyncDatabase#getAll}.
|
|
603
|
-
* An optional mapper function can be provided to transform the results.
|
|
604
|
-
*
|
|
605
|
-
* @example
|
|
606
|
-
* ```javascript
|
|
607
|
-
* const watchedTodos = powersync.query({
|
|
608
|
-
* sql: `SELECT photo_id as id FROM todos WHERE photo_id IS NOT NULL`,
|
|
609
|
-
* parameters: [],
|
|
610
|
-
* mapper: (row) => ({
|
|
611
|
-
* ...row,
|
|
612
|
-
* created_at: new Date(row.created_at as string)
|
|
613
|
-
* })
|
|
614
|
-
* })
|
|
615
|
-
* .watch()
|
|
616
|
-
* // OR use .differentialWatch() for fine-grained watches.
|
|
617
|
-
* ```
|
|
618
|
-
*/
|
|
619
|
-
query(query) {
|
|
620
|
-
const { sql, parameters = [], mapper } = query;
|
|
621
|
-
const compatibleQuery = {
|
|
622
|
-
compile: () => ({
|
|
623
|
-
sql,
|
|
624
|
-
parameters
|
|
625
|
-
}),
|
|
626
|
-
execute: async ({ sql, parameters }) => {
|
|
627
|
-
const result = await this.getAll(sql, parameters);
|
|
628
|
-
return mapper ? result.map(mapper) : result;
|
|
629
|
-
}
|
|
630
|
-
};
|
|
631
|
-
return this.customQuery(compatibleQuery);
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Allows building a {@link WatchedQuery} using an existing {@link WatchCompatibleQuery}.
|
|
635
|
-
* The watched query will use the provided {@link WatchCompatibleQuery.execute} method to query results.
|
|
636
|
-
*
|
|
637
|
-
* @example
|
|
638
|
-
* ```javascript
|
|
639
|
-
*
|
|
640
|
-
* // Potentially a query from an ORM like Drizzle
|
|
641
|
-
* const query = db.select().from(lists);
|
|
642
|
-
*
|
|
643
|
-
* const watchedTodos = powersync.customQuery(query)
|
|
644
|
-
* .watch()
|
|
645
|
-
* // OR use .differentialWatch() for fine-grained watches.
|
|
646
|
-
* ```
|
|
647
|
-
*/
|
|
648
|
-
customQuery(query) {
|
|
649
|
-
return new CustomQuery({
|
|
650
|
-
db: this,
|
|
651
|
-
query
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
599
|
/**
|
|
655
600
|
* Execute a read query every time the source tables are modified.
|
|
656
601
|
* Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
|
|
@@ -668,41 +613,35 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
668
613
|
if (!onResult) {
|
|
669
614
|
throw new Error('onResult is required');
|
|
670
615
|
}
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
616
|
+
const watchQuery = async (abortSignal) => {
|
|
617
|
+
try {
|
|
618
|
+
const resolvedTables = await this.resolveTables(sql, parameters, options);
|
|
619
|
+
// Fetch initial data
|
|
620
|
+
const result = await this.executeReadOnly(sql, parameters);
|
|
621
|
+
onResult(result);
|
|
622
|
+
this.onChangeWithCallback({
|
|
623
|
+
onChange: async () => {
|
|
624
|
+
try {
|
|
625
|
+
const result = await this.executeReadOnly(sql, parameters);
|
|
626
|
+
onResult(result);
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
onError?.(error);
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
onError
|
|
633
|
+
}, {
|
|
634
|
+
...(options ?? {}),
|
|
635
|
+
tables: resolvedTables,
|
|
636
|
+
// Override the abort signal since we intercept it
|
|
637
|
+
signal: abortSignal
|
|
638
|
+
});
|
|
688
639
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
onData: (data) => {
|
|
692
|
-
if (!data) {
|
|
693
|
-
// This should not happen. We only use null for the initial data.
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
onResult(data);
|
|
697
|
-
},
|
|
698
|
-
onError: (error) => {
|
|
699
|
-
onError(error);
|
|
640
|
+
catch (error) {
|
|
641
|
+
onError?.(error);
|
|
700
642
|
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
dispose();
|
|
704
|
-
watchedQuery.close();
|
|
705
|
-
});
|
|
643
|
+
};
|
|
644
|
+
runOnSchemaChange(watchQuery, this, options);
|
|
706
645
|
}
|
|
707
646
|
/**
|
|
708
647
|
* Execute a read query every time the source tables are modified.
|
|
@@ -792,9 +731,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
792
731
|
return;
|
|
793
732
|
executor.schedule({ changedTables: intersection });
|
|
794
733
|
}), throttleMs);
|
|
795
|
-
if (options?.triggerImmediate) {
|
|
796
|
-
executor.schedule({ changedTables: [] });
|
|
797
|
-
}
|
|
798
734
|
const dispose = this.database.registerListener({
|
|
799
735
|
tablesUpdated: async (update) => {
|
|
800
736
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ILogger } from 'js-logger';
|
|
2
2
|
import { BaseListener, BaseObserver } from '../utils/BaseObserver.js';
|
|
3
3
|
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
4
|
-
import {
|
|
4
|
+
import { InternalConnectionOptions, StreamingSyncImplementation } from './sync/stream/AbstractStreamingSyncImplementation.js';
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
@@ -17,12 +17,12 @@ export interface ConnectionManagerSyncImplementationResult {
|
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
19
|
export interface ConnectionManagerOptions {
|
|
20
|
-
createSyncImplementation(connector: PowerSyncBackendConnector, options:
|
|
20
|
+
createSyncImplementation(connector: PowerSyncBackendConnector, options: InternalConnectionOptions): Promise<ConnectionManagerSyncImplementationResult>;
|
|
21
21
|
logger: ILogger;
|
|
22
22
|
}
|
|
23
23
|
type StoredConnectionOptions = {
|
|
24
24
|
connector: PowerSyncBackendConnector;
|
|
25
|
-
options:
|
|
25
|
+
options: InternalConnectionOptions;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
28
|
* @internal
|
|
@@ -66,7 +66,7 @@ export declare class ConnectionManager extends BaseObserver<ConnectionManagerLis
|
|
|
66
66
|
constructor(options: ConnectionManagerOptions);
|
|
67
67
|
get logger(): ILogger;
|
|
68
68
|
close(): Promise<void>;
|
|
69
|
-
connect(connector: PowerSyncBackendConnector, options
|
|
69
|
+
connect(connector: PowerSyncBackendConnector, options: InternalConnectionOptions): Promise<void>;
|
|
70
70
|
protected connectInternal(): Promise<void>;
|
|
71
71
|
/**
|
|
72
72
|
* Close the sync connection.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseListener,
|
|
1
|
+
import { BaseListener, BaseObserver, Disposable } from '../../../utils/BaseObserver.js';
|
|
2
2
|
import { CrudBatch } from './CrudBatch.js';
|
|
3
3
|
import { CrudEntry, OpId } from './CrudEntry.js';
|
|
4
4
|
import { SyncDataBatch } from './SyncDataBatch.js';
|
|
@@ -62,7 +62,7 @@ export declare enum PowerSyncControlCommand {
|
|
|
62
62
|
export interface BucketStorageListener extends BaseListener {
|
|
63
63
|
crudUpdate: () => void;
|
|
64
64
|
}
|
|
65
|
-
export interface BucketStorageAdapter extends
|
|
65
|
+
export interface BucketStorageAdapter extends BaseObserver<BucketStorageListener>, Disposable {
|
|
66
66
|
init(): Promise<void>;
|
|
67
67
|
saveSyncData(batch: SyncDataBatch, fixedKeyFormat?: boolean): Promise<void>;
|
|
68
68
|
removeBuckets(buckets: string[]): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Logger, { ILogger } from 'js-logger';
|
|
2
2
|
import { SyncStatus, SyncStatusOptions } from '../../../db/crud/SyncStatus.js';
|
|
3
|
-
import { BaseListener, BaseObserver,
|
|
3
|
+
import { BaseListener, BaseObserver, Disposable } from '../../../utils/BaseObserver.js';
|
|
4
4
|
import { BucketStorageAdapter } from '../bucket/BucketStorageAdapter.js';
|
|
5
5
|
import { AbstractRemote, FetchStrategy } from './AbstractRemote.js';
|
|
6
6
|
import { StreamingSyncRequestParameterType } from './streaming-sync-types.js';
|
|
@@ -88,7 +88,8 @@ export interface StreamingSyncImplementationListener extends BaseListener {
|
|
|
88
88
|
* Configurable options to be used when connecting to the PowerSync
|
|
89
89
|
* backend instance.
|
|
90
90
|
*/
|
|
91
|
-
export
|
|
91
|
+
export type PowerSyncConnectionOptions = Omit<InternalConnectionOptions, 'serializedSchema'>;
|
|
92
|
+
export interface InternalConnectionOptions extends BaseConnectionOptions, AdditionalConnectionOptions {
|
|
92
93
|
}
|
|
93
94
|
/** @internal */
|
|
94
95
|
export interface BaseConnectionOptions {
|
|
@@ -114,6 +115,10 @@ export interface BaseConnectionOptions {
|
|
|
114
115
|
* These parameters are passed to the sync rules, and will be available under the`user_parameters` object.
|
|
115
116
|
*/
|
|
116
117
|
params?: Record<string, StreamingSyncRequestParameterType>;
|
|
118
|
+
/**
|
|
119
|
+
* The serialized schema - mainly used to forward information about raw tables to the sync client.
|
|
120
|
+
*/
|
|
121
|
+
serializedSchema?: any;
|
|
117
122
|
}
|
|
118
123
|
/** @internal */
|
|
119
124
|
export interface AdditionalConnectionOptions {
|
|
@@ -131,11 +136,11 @@ export interface AdditionalConnectionOptions {
|
|
|
131
136
|
}
|
|
132
137
|
/** @internal */
|
|
133
138
|
export type RequiredAdditionalConnectionOptions = Required<AdditionalConnectionOptions>;
|
|
134
|
-
export interface StreamingSyncImplementation extends
|
|
139
|
+
export interface StreamingSyncImplementation extends BaseObserver<StreamingSyncImplementationListener>, Disposable {
|
|
135
140
|
/**
|
|
136
141
|
* Connects to the sync service
|
|
137
142
|
*/
|
|
138
|
-
connect(options?:
|
|
143
|
+
connect(options?: InternalConnectionOptions): Promise<void>;
|
|
139
144
|
/**
|
|
140
145
|
* Disconnects from the sync services.
|
|
141
146
|
* @throws if not connected or if abort is not controlled internally
|
|
@@ -164,7 +169,6 @@ export declare abstract class AbstractStreamingSyncImplementation extends BaseOb
|
|
|
164
169
|
protected _lastSyncedAt: Date | null;
|
|
165
170
|
protected options: AbstractStreamingSyncImplementationOptions;
|
|
166
171
|
protected abortController: AbortController | null;
|
|
167
|
-
protected uploadAbortController: AbortController | null;
|
|
168
172
|
protected crudUpdateListener?: () => void;
|
|
169
173
|
protected streamingSyncPromise?: Promise<void>;
|
|
170
174
|
private isUploadingCrud;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Logger from 'js-logger';
|
|
2
|
-
import { FULL_SYNC_PRIORITY } from '../../../db/crud/SyncProgress.js';
|
|
3
2
|
import { SyncStatus } from '../../../db/crud/SyncStatus.js';
|
|
3
|
+
import { FULL_SYNC_PRIORITY } from '../../../db/crud/SyncProgress.js';
|
|
4
4
|
import { AbortOperation } from '../../../utils/AbortOperation.js';
|
|
5
5
|
import { BaseObserver } from '../../../utils/BaseObserver.js';
|
|
6
6
|
import { throttleLeadingTrailing } from '../../../utils/async.js';
|
|
@@ -72,7 +72,8 @@ export const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
|
72
72
|
connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET,
|
|
73
73
|
clientImplementation: DEFAULT_SYNC_CLIENT_IMPLEMENTATION,
|
|
74
74
|
fetchStrategy: FetchStrategy.Buffered,
|
|
75
|
-
params: {}
|
|
75
|
+
params: {},
|
|
76
|
+
serializedSchema: undefined
|
|
76
77
|
};
|
|
77
78
|
// The priority we assume when we receive checkpoint lines where no priority is set.
|
|
78
79
|
// This is the default priority used by the sync service, but can be set to an arbitrary
|
|
@@ -83,9 +84,6 @@ export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
83
84
|
_lastSyncedAt;
|
|
84
85
|
options;
|
|
85
86
|
abortController;
|
|
86
|
-
// In rare cases, mostly for tests, uploads can be triggered without being properly connected.
|
|
87
|
-
// This allows ensuring that all upload processes can be aborted.
|
|
88
|
-
uploadAbortController;
|
|
89
87
|
crudUpdateListener;
|
|
90
88
|
streamingSyncPromise;
|
|
91
89
|
isUploadingCrud = false;
|
|
@@ -162,10 +160,8 @@ export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
162
160
|
return this.options.logger;
|
|
163
161
|
}
|
|
164
162
|
async dispose() {
|
|
165
|
-
super.dispose();
|
|
166
163
|
this.crudUpdateListener?.();
|
|
167
164
|
this.crudUpdateListener = undefined;
|
|
168
|
-
this.uploadAbortController?.abort();
|
|
169
165
|
}
|
|
170
166
|
async hasCompletedSync() {
|
|
171
167
|
return this.options.adapter.hasCompletedSync();
|
|
@@ -184,12 +180,7 @@ export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
184
180
|
* Keep track of the first item in the CRUD queue for the last `uploadCrud` iteration.
|
|
185
181
|
*/
|
|
186
182
|
let checkedCrudItem;
|
|
187
|
-
|
|
188
|
-
this.uploadAbortController = controller;
|
|
189
|
-
this.abortController?.signal.addEventListener('abort', () => {
|
|
190
|
-
controller.abort();
|
|
191
|
-
}, { once: true });
|
|
192
|
-
while (!controller.signal.aborted) {
|
|
183
|
+
while (true) {
|
|
193
184
|
try {
|
|
194
185
|
/**
|
|
195
186
|
* This is the first item in the FIFO CRUD queue.
|
|
@@ -230,7 +221,7 @@ The next upload iteration will be delayed.`);
|
|
|
230
221
|
uploadError: ex
|
|
231
222
|
}
|
|
232
223
|
});
|
|
233
|
-
await this.delayRetry(
|
|
224
|
+
await this.delayRetry();
|
|
234
225
|
if (!this.isConnected) {
|
|
235
226
|
// Exit the upload loop if the sync stream is no longer connected
|
|
236
227
|
break;
|
|
@@ -245,7 +236,6 @@ The next upload iteration will be delayed.`);
|
|
|
245
236
|
});
|
|
246
237
|
}
|
|
247
238
|
}
|
|
248
|
-
this.uploadAbortController = null;
|
|
249
239
|
}
|
|
250
240
|
});
|
|
251
241
|
}
|
|
@@ -526,6 +516,8 @@ The next upload iteration will be delayed.`);
|
|
|
526
516
|
}
|
|
527
517
|
if (isStreamingSyncCheckpoint(line)) {
|
|
528
518
|
targetCheckpoint = line.checkpoint;
|
|
519
|
+
// New checkpoint - existing validated checkpoint is no longer valid
|
|
520
|
+
pendingValidatedCheckpoint = null;
|
|
529
521
|
const bucketsToDelete = new Set(bucketMap.keys());
|
|
530
522
|
const newBuckets = new Map();
|
|
531
523
|
for (const checksum of line.checkpoint.buckets) {
|
|
@@ -549,8 +541,15 @@ The next upload iteration will be delayed.`);
|
|
|
549
541
|
return;
|
|
550
542
|
}
|
|
551
543
|
else if (!result.applied) {
|
|
544
|
+
// "Could not apply checkpoint due to local data". We need to retry after
|
|
545
|
+
// finishing uploads.
|
|
552
546
|
pendingValidatedCheckpoint = targetCheckpoint;
|
|
553
547
|
}
|
|
548
|
+
else {
|
|
549
|
+
// Nothing to retry later. This would likely already be null from the last
|
|
550
|
+
// checksum or checksum_diff operation, but we make sure.
|
|
551
|
+
pendingValidatedCheckpoint = null;
|
|
552
|
+
}
|
|
554
553
|
}
|
|
555
554
|
else if (isStreamingSyncCheckpointPartiallyComplete(line)) {
|
|
556
555
|
const priority = line.partial_checkpoint_complete.priority;
|
|
@@ -587,6 +586,8 @@ The next upload iteration will be delayed.`);
|
|
|
587
586
|
if (targetCheckpoint == null) {
|
|
588
587
|
throw new Error('Checkpoint diff without previous checkpoint');
|
|
589
588
|
}
|
|
589
|
+
// New checkpoint - existing validated checkpoint is no longer valid
|
|
590
|
+
pendingValidatedCheckpoint = null;
|
|
590
591
|
const diff = line.checkpoint_diff;
|
|
591
592
|
const newBuckets = new Map();
|
|
592
593
|
for (const checksum of targetCheckpoint.buckets) {
|
|
@@ -826,9 +827,11 @@ The next upload iteration will be delayed.`);
|
|
|
826
827
|
}
|
|
827
828
|
}
|
|
828
829
|
try {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
830
|
+
const options = { parameters: resolvedOptions.params };
|
|
831
|
+
if (resolvedOptions.serializedSchema) {
|
|
832
|
+
options.schema = resolvedOptions.serializedSchema;
|
|
833
|
+
}
|
|
834
|
+
await control(PowerSyncControlCommand.START, JSON.stringify(options));
|
|
832
835
|
this.notifyCompletedUploads = () => {
|
|
833
836
|
controlInvocations?.enqueueData({ command: PowerSyncControlCommand.NOTIFY_CRUD_UPLOAD_COMPLETED });
|
|
834
837
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A pending variant of a {@link RawTable} that doesn't have a name (because it would be inferred when creating the
|
|
3
|
+
* schema).
|
|
4
|
+
*/
|
|
5
|
+
export type RawTableType = {
|
|
6
|
+
/**
|
|
7
|
+
* The statement to run when PowerSync detects that a row needs to be inserted or updated.
|
|
8
|
+
*/
|
|
9
|
+
put: PendingStatement;
|
|
10
|
+
/**
|
|
11
|
+
* The statement to run when PowerSync detects that a row needs to be deleted.
|
|
12
|
+
*/
|
|
13
|
+
delete: PendingStatement;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A parameter to use as part of {@link PendingStatement}.
|
|
17
|
+
*
|
|
18
|
+
* For delete statements, only the `"Id"` value is supported - the sync client will replace it with the id of the row to
|
|
19
|
+
* be synced.
|
|
20
|
+
*
|
|
21
|
+
* For insert and replace operations, the values of columns in the table are available as parameters through
|
|
22
|
+
* `{Column: 'name'}`.
|
|
23
|
+
*/
|
|
24
|
+
export type PendingStatementParameter = 'Id' | {
|
|
25
|
+
Column: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A statement that the PowerSync client should use to insert or delete data into a table managed by the user.
|
|
29
|
+
*/
|
|
30
|
+
export type PendingStatement = {
|
|
31
|
+
sql: string;
|
|
32
|
+
params: PendingStatementParameter[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Instructs PowerSync to sync data into a "raw" table.
|
|
36
|
+
*
|
|
37
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
38
|
+
* using client-side table and column constraints.
|
|
39
|
+
*
|
|
40
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
41
|
+
*
|
|
42
|
+
* @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
|
|
43
|
+
* stability guarantees.
|
|
44
|
+
*/
|
|
45
|
+
export declare class RawTable implements RawTableType {
|
|
46
|
+
/**
|
|
47
|
+
* The name of the table.
|
|
48
|
+
*
|
|
49
|
+
* This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
|
|
50
|
+
* another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
|
|
51
|
+
* appears in the source / backend database) are to be handled specially.
|
|
52
|
+
*/
|
|
53
|
+
name: string;
|
|
54
|
+
put: PendingStatement;
|
|
55
|
+
delete: PendingStatement;
|
|
56
|
+
constructor(name: string, type: RawTableType);
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructs PowerSync to sync data into a "raw" table.
|
|
3
|
+
*
|
|
4
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
5
|
+
* using client-side table and column constraints.
|
|
6
|
+
*
|
|
7
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
8
|
+
*
|
|
9
|
+
* @experimental Please note that this feature is experimental at the moment, and not covered by PowerSync semver or
|
|
10
|
+
* stability guarantees.
|
|
11
|
+
*/
|
|
12
|
+
export class RawTable {
|
|
13
|
+
/**
|
|
14
|
+
* The name of the table.
|
|
15
|
+
*
|
|
16
|
+
* This does not have to match the actual table name in the schema - {@link put} and {@link delete} are free to use
|
|
17
|
+
* another table. Instead, this name is used by the sync client to recognize that operations on this table (as it
|
|
18
|
+
* appears in the source / backend database) are to be handled specially.
|
|
19
|
+
*/
|
|
20
|
+
name;
|
|
21
|
+
put;
|
|
22
|
+
delete;
|
|
23
|
+
constructor(name, type) {
|
|
24
|
+
this.name = name;
|
|
25
|
+
this.put = type.put;
|
|
26
|
+
this.delete = type.delete;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RawTable, RawTableType } from './RawTable.js';
|
|
1
2
|
import { RowType, Table } from './Table.js';
|
|
2
3
|
type SchemaType = Record<string, Table<any>>;
|
|
3
4
|
export type SchemaTableType<S extends SchemaType> = {
|
|
@@ -10,7 +11,19 @@ export declare class Schema<S extends SchemaType = SchemaType> {
|
|
|
10
11
|
readonly types: SchemaTableType<S>;
|
|
11
12
|
readonly props: S;
|
|
12
13
|
readonly tables: Table[];
|
|
14
|
+
readonly rawTables: RawTable[];
|
|
13
15
|
constructor(tables: Table[] | S);
|
|
16
|
+
/**
|
|
17
|
+
* Adds raw tables to this schema. Raw tables are identified by their name, but entirely managed by the application
|
|
18
|
+
* developer instead of automatically by PowerSync.
|
|
19
|
+
* Since raw tables are not backed by JSON, running complex queries on them may be more efficient. Further, they allow
|
|
20
|
+
* using client-side table and column constraints.
|
|
21
|
+
* Note that raw tables are only supported when using the new `SyncClientImplementation.rust` sync client.
|
|
22
|
+
*
|
|
23
|
+
* @param tables An object of (table name, raw table definition) entries.
|
|
24
|
+
* @experimental Note that the raw tables API is still experimental and may change in the future.
|
|
25
|
+
*/
|
|
26
|
+
withRawTables(tables: Record<string, RawTableType>): void;
|
|
14
27
|
validate(): void;
|
|
15
28
|
toJSON(): {
|
|
16
29
|
tables: {
|
|
@@ -35,6 +48,7 @@ export declare class Schema<S extends SchemaType = SchemaType> {
|
|
|
35
48
|
}[];
|
|
36
49
|
}[];
|
|
37
50
|
}[];
|
|
51
|
+
raw_tables: RawTable[];
|
|
38
52
|
};
|
|
39
53
|
private convertToClassicTables;
|
|
40
54
|
}
|