@powersync/common 0.0.0-dev-20250714144421 → 0.0.0-dev-20250715080712
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 +59 -7
- package/lib/client/AbstractPowerSyncDatabase.js +105 -35
- package/lib/client/ConnectionManager.d.ts +4 -4
- package/lib/client/CustomQuery.d.ts +25 -0
- package/lib/client/CustomQuery.js +41 -0
- package/lib/client/Query.d.ts +79 -0
- package/lib/client/Query.js +1 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +2 -2
- package/lib/client/sync/bucket/SqliteBucketStorage.js +14 -14
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +10 -4
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +26 -18
- package/lib/client/watched/GetAllQuery.d.ts +32 -0
- package/lib/client/watched/GetAllQuery.js +24 -0
- package/lib/client/watched/WatchedQuery.d.ts +93 -0
- package/lib/client/watched/WatchedQuery.js +12 -0
- package/lib/client/watched/processors/AbstractQueryProcessor.d.ts +67 -0
- package/lib/client/watched/processors/AbstractQueryProcessor.js +136 -0
- package/lib/client/watched/processors/DifferentialQueryProcessor.d.ts +129 -0
- package/lib/client/watched/processors/DifferentialQueryProcessor.js +175 -0
- package/lib/client/watched/processors/OnChangeQueryProcessor.d.ts +27 -0
- package/lib/client/watched/processors/OnChangeQueryProcessor.js +74 -0
- package/lib/client/watched/processors/comparators.d.ts +24 -0
- package/lib/client/watched/processors/comparators.js +33 -0
- 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 +7 -0
- package/lib/index.js +7 -0
- package/lib/utils/BaseObserver.d.ts +3 -4
- package/lib/utils/BaseObserver.js +3 -0
- package/lib/utils/MetaBaseObserver.d.ts +29 -0
- package/lib/utils/MetaBaseObserver.js +50 -0
- package/package.json +1 -1
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { Mutex } from 'async-mutex';
|
|
2
|
-
import { ILogger } from 'js-logger';
|
|
2
|
+
import Logger, { ILogger } from 'js-logger';
|
|
3
3
|
import { DBAdapter, QueryResult, Transaction } from '../db/DBAdapter.js';
|
|
4
4
|
import { SyncStatus } from '../db/crud/SyncStatus.js';
|
|
5
5
|
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';
|
|
9
10
|
import { SQLOpenFactory, SQLOpenOptions } from './SQLOpenFactory.js';
|
|
10
11
|
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector.js';
|
|
11
12
|
import { BucketStorageAdapter } from './sync/bucket/BucketStorageAdapter.js';
|
|
12
13
|
import { CrudBatch } from './sync/bucket/CrudBatch.js';
|
|
13
14
|
import { CrudTransaction } from './sync/bucket/CrudTransaction.js';
|
|
14
15
|
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';
|
|
15
18
|
export interface DisconnectAndClearOptions {
|
|
16
19
|
/** When set to false, data in local-only tables is preserved. */
|
|
17
20
|
clearLocal?: boolean;
|
|
@@ -44,7 +47,7 @@ export interface PowerSyncDatabaseOptionsWithOpenFactory extends BasePowerSyncDa
|
|
|
44
47
|
export interface PowerSyncDatabaseOptionsWithSettings extends BasePowerSyncDatabaseOptions {
|
|
45
48
|
database: SQLOpenOptions;
|
|
46
49
|
}
|
|
47
|
-
export interface
|
|
50
|
+
export interface SQLOnChangeOptions {
|
|
48
51
|
signal?: AbortSignal;
|
|
49
52
|
tables?: string[];
|
|
50
53
|
/** The minimum interval between queries. */
|
|
@@ -56,6 +59,17 @@ export interface SQLWatchOptions {
|
|
|
56
59
|
* by not removing PowerSync table name prefixes
|
|
57
60
|
*/
|
|
58
61
|
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>;
|
|
59
73
|
}
|
|
60
74
|
export interface WatchOnChangeEvent {
|
|
61
75
|
changedTables: string[];
|
|
@@ -71,6 +85,8 @@ export interface WatchOnChangeHandler {
|
|
|
71
85
|
export interface PowerSyncDBListener extends StreamingSyncImplementationListener {
|
|
72
86
|
initialized: () => void;
|
|
73
87
|
schemaChanged: (schema: Schema) => void;
|
|
88
|
+
closing: () => Promise<void> | void;
|
|
89
|
+
closed: () => Promise<void> | void;
|
|
74
90
|
}
|
|
75
91
|
export interface PowerSyncCloseOptions {
|
|
76
92
|
/**
|
|
@@ -81,9 +97,9 @@ export interface PowerSyncCloseOptions {
|
|
|
81
97
|
disconnect?: boolean;
|
|
82
98
|
}
|
|
83
99
|
export declare const DEFAULT_POWERSYNC_CLOSE_OPTIONS: PowerSyncCloseOptions;
|
|
84
|
-
export declare const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
85
100
|
export declare const DEFAULT_POWERSYNC_DB_OPTIONS: {
|
|
86
101
|
retryDelayMs: number;
|
|
102
|
+
logger: Logger.ILogger;
|
|
87
103
|
crudUploadThrottleMs: number;
|
|
88
104
|
};
|
|
89
105
|
export declare const DEFAULT_CRUD_BATCH_LIMIT = 100;
|
|
@@ -117,7 +133,6 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
117
133
|
protected _schema: Schema;
|
|
118
134
|
private _database;
|
|
119
135
|
protected runExclusiveMutex: Mutex;
|
|
120
|
-
logger: ILogger;
|
|
121
136
|
constructor(options: PowerSyncDatabaseOptionsWithDBAdapter);
|
|
122
137
|
constructor(options: PowerSyncDatabaseOptionsWithOpenFactory);
|
|
123
138
|
constructor(options: PowerSyncDatabaseOptionsWithSettings);
|
|
@@ -180,6 +195,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
180
195
|
* Cannot be used while connected - this should only be called before {@link AbstractPowerSyncDatabase.connect}.
|
|
181
196
|
*/
|
|
182
197
|
updateSchema(schema: Schema): Promise<void>;
|
|
198
|
+
get logger(): Logger.ILogger;
|
|
183
199
|
/**
|
|
184
200
|
* Wait for initialization to complete.
|
|
185
201
|
* While initializing is automatic, this helps to catch and report initialization errors.
|
|
@@ -389,6 +405,42 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
389
405
|
* ```
|
|
390
406
|
*/
|
|
391
407
|
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>;
|
|
392
444
|
/**
|
|
393
445
|
* Execute a read query every time the source tables are modified.
|
|
394
446
|
* Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
|
|
@@ -437,7 +489,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
437
489
|
* }
|
|
438
490
|
* ```
|
|
439
491
|
*/
|
|
440
|
-
onChange(options?:
|
|
492
|
+
onChange(options?: SQLOnChangeOptions): AsyncIterable<WatchOnChangeEvent>;
|
|
441
493
|
/**
|
|
442
494
|
* See {@link onChangeWithCallback}.
|
|
443
495
|
*
|
|
@@ -452,7 +504,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
452
504
|
* }
|
|
453
505
|
* ```
|
|
454
506
|
*/
|
|
455
|
-
onChange(handler?: WatchOnChangeHandler, options?:
|
|
507
|
+
onChange(handler?: WatchOnChangeHandler, options?: SQLOnChangeOptions): () => void;
|
|
456
508
|
/**
|
|
457
509
|
* Invoke the provided callback on any changes to any of the specified tables.
|
|
458
510
|
*
|
|
@@ -465,7 +517,7 @@ export declare abstract class AbstractPowerSyncDatabase extends BaseObserver<Pow
|
|
|
465
517
|
* @param options Options for configuring watch behavior
|
|
466
518
|
* @returns A dispose function to stop watching for changes
|
|
467
519
|
*/
|
|
468
|
-
onChangeWithCallback(handler?: WatchOnChangeHandler, options?:
|
|
520
|
+
onChangeWithCallback(handler?: WatchOnChangeHandler, options?: SQLOnChangeOptions): () => void;
|
|
469
521
|
/**
|
|
470
522
|
* Create a Stream of changes to any of the specified tables.
|
|
471
523
|
*
|
|
@@ -9,13 +9,15 @@ 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';
|
|
12
13
|
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';
|
|
19
21
|
const POWERSYNC_TABLE_MATCH = /(^ps_data__|^ps_data_local__)/;
|
|
20
22
|
const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
|
|
21
23
|
clearLocal: true
|
|
@@ -23,9 +25,9 @@ const DEFAULT_DISCONNECT_CLEAR_OPTIONS = {
|
|
|
23
25
|
export const DEFAULT_POWERSYNC_CLOSE_OPTIONS = {
|
|
24
26
|
disconnect: true
|
|
25
27
|
};
|
|
26
|
-
export const DEFAULT_WATCH_THROTTLE_MS = 30;
|
|
27
28
|
export const DEFAULT_POWERSYNC_DB_OPTIONS = {
|
|
28
29
|
retryDelayMs: 5000,
|
|
30
|
+
logger: Logger.get('PowerSyncDatabase'),
|
|
29
31
|
crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
|
|
30
32
|
};
|
|
31
33
|
export const DEFAULT_CRUD_BATCH_LIMIT = 100;
|
|
@@ -63,7 +65,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
63
65
|
_schema;
|
|
64
66
|
_database;
|
|
65
67
|
runExclusiveMutex;
|
|
66
|
-
logger;
|
|
67
68
|
constructor(options) {
|
|
68
69
|
super();
|
|
69
70
|
this.options = options;
|
|
@@ -83,7 +84,6 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
83
84
|
else {
|
|
84
85
|
throw new Error('The provided `database` option is invalid.');
|
|
85
86
|
}
|
|
86
|
-
this.logger = options.logger ?? Logger.get(`PowerSyncDatabase[${this._database.name}]`);
|
|
87
87
|
this.bucketStorageAdapter = this.generateBucketStorageAdapter();
|
|
88
88
|
this.closed = false;
|
|
89
89
|
this.currentStatus = new SyncStatus({});
|
|
@@ -263,13 +263,16 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
263
263
|
schema.validate();
|
|
264
264
|
}
|
|
265
265
|
catch (ex) {
|
|
266
|
-
this.logger
|
|
266
|
+
this.options.logger?.warn('Schema validation failed. Unexpected behaviour could occur', ex);
|
|
267
267
|
}
|
|
268
268
|
this._schema = schema;
|
|
269
269
|
await this.database.execute('SELECT powersync_replace_schema(?)', [JSON.stringify(this.schema.toJSON())]);
|
|
270
270
|
await this.database.refreshSchema();
|
|
271
271
|
this.iterateListeners(async (cb) => cb.schemaChanged?.(schema));
|
|
272
272
|
}
|
|
273
|
+
get logger() {
|
|
274
|
+
return this.options.logger;
|
|
275
|
+
}
|
|
273
276
|
/**
|
|
274
277
|
* Wait for initialization to complete.
|
|
275
278
|
* While initializing is automatic, this helps to catch and report initialization errors.
|
|
@@ -296,7 +299,9 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
296
299
|
* Connects to stream of events from the PowerSync instance.
|
|
297
300
|
*/
|
|
298
301
|
async connect(connector, options) {
|
|
299
|
-
|
|
302
|
+
const resolvedOptions = options ?? {};
|
|
303
|
+
resolvedOptions.serializedSchema = this.schema.toJSON();
|
|
304
|
+
return this.connectionManager.connect(connector, resolvedOptions);
|
|
300
305
|
}
|
|
301
306
|
/**
|
|
302
307
|
* Close the sync connection.
|
|
@@ -339,6 +344,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
339
344
|
if (this.closed) {
|
|
340
345
|
return;
|
|
341
346
|
}
|
|
347
|
+
await this.iterateAsyncListeners(async (cb) => cb.closing?.());
|
|
342
348
|
const { disconnect } = options;
|
|
343
349
|
if (disconnect) {
|
|
344
350
|
await this.disconnect();
|
|
@@ -346,6 +352,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
346
352
|
await this.connectionManager.close();
|
|
347
353
|
await this.database.close();
|
|
348
354
|
this.closed = true;
|
|
355
|
+
await this.iterateAsyncListeners(async (cb) => cb.closed?.());
|
|
349
356
|
}
|
|
350
357
|
/**
|
|
351
358
|
* Get upload queue size estimate and count.
|
|
@@ -592,6 +599,60 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
592
599
|
const options = handlerOrOptions;
|
|
593
600
|
return this.watchWithAsyncGenerator(sql, parameters, options);
|
|
594
601
|
}
|
|
602
|
+
/**
|
|
603
|
+
* Allows defining a query which can be used to build a {@link WatchedQuery}.
|
|
604
|
+
* The defined query will be executed with {@link AbstractPowerSyncDatabase#getAll}.
|
|
605
|
+
* An optional mapper function can be provided to transform the results.
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```javascript
|
|
609
|
+
* const watchedTodos = powersync.query({
|
|
610
|
+
* sql: `SELECT photo_id as id FROM todos WHERE photo_id IS NOT NULL`,
|
|
611
|
+
* parameters: [],
|
|
612
|
+
* mapper: (row) => ({
|
|
613
|
+
* ...row,
|
|
614
|
+
* created_at: new Date(row.created_at as string)
|
|
615
|
+
* })
|
|
616
|
+
* })
|
|
617
|
+
* .watch()
|
|
618
|
+
* // OR use .differentialWatch() for fine-grained watches.
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
query(query) {
|
|
622
|
+
const { sql, parameters = [], mapper } = query;
|
|
623
|
+
const compatibleQuery = {
|
|
624
|
+
compile: () => ({
|
|
625
|
+
sql,
|
|
626
|
+
parameters
|
|
627
|
+
}),
|
|
628
|
+
execute: async ({ sql, parameters }) => {
|
|
629
|
+
const result = await this.getAll(sql, parameters);
|
|
630
|
+
return mapper ? result.map(mapper) : result;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
return this.customQuery(compatibleQuery);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Allows building a {@link WatchedQuery} using an existing {@link WatchCompatibleQuery}.
|
|
637
|
+
* The watched query will use the provided {@link WatchCompatibleQuery.execute} method to query results.
|
|
638
|
+
*
|
|
639
|
+
* @example
|
|
640
|
+
* ```javascript
|
|
641
|
+
*
|
|
642
|
+
* // Potentially a query from an ORM like Drizzle
|
|
643
|
+
* const query = db.select().from(lists);
|
|
644
|
+
*
|
|
645
|
+
* const watchedTodos = powersync.customQuery(query)
|
|
646
|
+
* .watch()
|
|
647
|
+
* // OR use .differentialWatch() for fine-grained watches.
|
|
648
|
+
* ```
|
|
649
|
+
*/
|
|
650
|
+
customQuery(query) {
|
|
651
|
+
return new CustomQuery({
|
|
652
|
+
db: this,
|
|
653
|
+
query
|
|
654
|
+
});
|
|
655
|
+
}
|
|
595
656
|
/**
|
|
596
657
|
* Execute a read query every time the source tables are modified.
|
|
597
658
|
* Use {@link SQLWatchOptions.throttleMs} to specify the minimum interval between queries.
|
|
@@ -605,39 +666,45 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
605
666
|
* @param options Options for configuring watch behavior
|
|
606
667
|
*/
|
|
607
668
|
watchWithCallback(sql, parameters, handler, options) {
|
|
608
|
-
const { onResult, onError = (e) => this.logger
|
|
669
|
+
const { onResult, onError = (e) => this.options.logger?.error(e) } = handler ?? {};
|
|
609
670
|
if (!onResult) {
|
|
610
671
|
throw new Error('onResult is required');
|
|
611
672
|
}
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}, {
|
|
630
|
-
...(options ?? {}),
|
|
631
|
-
tables: resolvedTables,
|
|
632
|
-
// Override the abort signal since we intercept it
|
|
633
|
-
signal: abortSignal
|
|
634
|
-
});
|
|
673
|
+
const { comparator } = options ?? {};
|
|
674
|
+
// This API yields a QueryResult type.
|
|
675
|
+
// This is not a standard Array result, which makes it incompatible with the .query API.
|
|
676
|
+
const watchedQuery = new OnChangeQueryProcessor({
|
|
677
|
+
db: this,
|
|
678
|
+
comparator,
|
|
679
|
+
placeholderData: null,
|
|
680
|
+
watchOptions: {
|
|
681
|
+
query: {
|
|
682
|
+
compile: () => ({
|
|
683
|
+
sql: sql,
|
|
684
|
+
parameters: parameters ?? []
|
|
685
|
+
}),
|
|
686
|
+
execute: () => this.executeReadOnly(sql, parameters)
|
|
687
|
+
},
|
|
688
|
+
reportFetching: false,
|
|
689
|
+
throttleMs: options?.throttleMs ?? DEFAULT_WATCH_THROTTLE_MS
|
|
635
690
|
}
|
|
636
|
-
|
|
637
|
-
|
|
691
|
+
});
|
|
692
|
+
const dispose = watchedQuery.registerListener({
|
|
693
|
+
onData: (data) => {
|
|
694
|
+
if (!data) {
|
|
695
|
+
// This should not happen. We only use null for the initial data.
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
onResult(data);
|
|
699
|
+
},
|
|
700
|
+
onError: (error) => {
|
|
701
|
+
onError(error);
|
|
638
702
|
}
|
|
639
|
-
};
|
|
640
|
-
|
|
703
|
+
});
|
|
704
|
+
options?.signal?.addEventListener('abort', () => {
|
|
705
|
+
dispose();
|
|
706
|
+
watchedQuery.close();
|
|
707
|
+
});
|
|
641
708
|
}
|
|
642
709
|
/**
|
|
643
710
|
* Execute a read query every time the source tables are modified.
|
|
@@ -711,7 +778,7 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
711
778
|
* @returns A dispose function to stop watching for changes
|
|
712
779
|
*/
|
|
713
780
|
onChangeWithCallback(handler, options) {
|
|
714
|
-
const { onChange, onError = (e) => this.logger
|
|
781
|
+
const { onChange, onError = (e) => this.options.logger?.error(e) } = handler ?? {};
|
|
715
782
|
if (!onChange) {
|
|
716
783
|
throw new Error('onChange is required');
|
|
717
784
|
}
|
|
@@ -727,6 +794,9 @@ export class AbstractPowerSyncDatabase extends BaseObserver {
|
|
|
727
794
|
return;
|
|
728
795
|
executor.schedule({ changedTables: intersection });
|
|
729
796
|
}), throttleMs);
|
|
797
|
+
if (options?.triggerImmediate) {
|
|
798
|
+
executor.schedule({ changedTables: [] });
|
|
799
|
+
}
|
|
730
800
|
const dispose = this.database.registerListener({
|
|
731
801
|
tablesUpdated: async (update) => {
|
|
732
802
|
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.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AbstractPowerSyncDatabase } from './AbstractPowerSyncDatabase.js';
|
|
2
|
+
import { Query, StandardWatchedQueryOptions } from './Query.js';
|
|
3
|
+
import { DifferentialQueryProcessor, DifferentialWatchedQueryOptions } from './watched/processors/DifferentialQueryProcessor.js';
|
|
4
|
+
import { OnChangeQueryProcessor } from './watched/processors/OnChangeQueryProcessor.js';
|
|
5
|
+
import { WatchCompatibleQuery, WatchedQueryOptions } from './watched/WatchedQuery.js';
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export interface CustomQueryOptions<RowType> {
|
|
10
|
+
db: AbstractPowerSyncDatabase;
|
|
11
|
+
query: WatchCompatibleQuery<RowType[]>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare class CustomQuery<RowType> implements Query<RowType> {
|
|
17
|
+
protected options: CustomQueryOptions<RowType>;
|
|
18
|
+
constructor(options: CustomQueryOptions<RowType>);
|
|
19
|
+
protected resolveOptions(options: WatchedQueryOptions): {
|
|
20
|
+
reportFetching: boolean | undefined;
|
|
21
|
+
throttleMs: number | undefined;
|
|
22
|
+
};
|
|
23
|
+
watch(watchOptions: StandardWatchedQueryOptions<RowType>): OnChangeQueryProcessor<RowType[]>;
|
|
24
|
+
differentialWatch(differentialWatchOptions: DifferentialWatchedQueryOptions<RowType>): DifferentialQueryProcessor<RowType>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FalsyComparator } from './watched/processors/comparators.js';
|
|
2
|
+
import { DifferentialQueryProcessor } from './watched/processors/DifferentialQueryProcessor.js';
|
|
3
|
+
import { OnChangeQueryProcessor } from './watched/processors/OnChangeQueryProcessor.js';
|
|
4
|
+
import { DEFAULT_WATCH_QUERY_OPTIONS } from './watched/WatchedQuery.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export class CustomQuery {
|
|
9
|
+
options;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
}
|
|
13
|
+
resolveOptions(options) {
|
|
14
|
+
return {
|
|
15
|
+
reportFetching: options?.reportFetching ?? DEFAULT_WATCH_QUERY_OPTIONS.reportFetching,
|
|
16
|
+
throttleMs: options?.throttleMs ?? DEFAULT_WATCH_QUERY_OPTIONS.throttleMs
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
watch(watchOptions) {
|
|
20
|
+
return new OnChangeQueryProcessor({
|
|
21
|
+
db: this.options.db,
|
|
22
|
+
comparator: watchOptions?.comparator ?? FalsyComparator,
|
|
23
|
+
placeholderData: watchOptions?.placeholderData ?? [],
|
|
24
|
+
watchOptions: {
|
|
25
|
+
...this.resolveOptions(watchOptions),
|
|
26
|
+
query: this.options.query
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
differentialWatch(differentialWatchOptions) {
|
|
31
|
+
return new DifferentialQueryProcessor({
|
|
32
|
+
db: this.options.db,
|
|
33
|
+
differentiator: differentialWatchOptions?.differentiator,
|
|
34
|
+
placeholderData: differentialWatchOptions?.placeholderData ?? [],
|
|
35
|
+
watchOptions: {
|
|
36
|
+
...this.resolveOptions(differentialWatchOptions),
|
|
37
|
+
query: this.options.query
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ArrayComparator } from './watched/processors/comparators.js';
|
|
2
|
+
import { DifferentialWatchedQuery, DifferentialWatchedQueryOptions } from './watched/processors/DifferentialQueryProcessor.js';
|
|
3
|
+
import { ComparisonWatchedQuery } from './watched/processors/OnChangeQueryProcessor.js';
|
|
4
|
+
import { WatchedQueryOptions } from './watched/WatchedQuery.js';
|
|
5
|
+
/**
|
|
6
|
+
* Query parameters for {@link ArrayQueryDefinition#parameters}
|
|
7
|
+
*/
|
|
8
|
+
export type QueryParam = string | number | boolean | null | undefined | bigint | Uint8Array;
|
|
9
|
+
/**
|
|
10
|
+
* Options for building a query with {@link AbstractPowerSyncDatabase#query}.
|
|
11
|
+
* This query will be executed with {@link AbstractPowerSyncDatabase#getAll}.
|
|
12
|
+
*/
|
|
13
|
+
export interface ArrayQueryDefinition<RowType = unknown> {
|
|
14
|
+
sql: string;
|
|
15
|
+
parameters?: ReadonlyArray<Readonly<QueryParam>>;
|
|
16
|
+
/**
|
|
17
|
+
* Maps the raw SQLite row to a custom typed object.
|
|
18
|
+
* @example
|
|
19
|
+
* ```javascript
|
|
20
|
+
* mapper: (row) => ({
|
|
21
|
+
* ...row,
|
|
22
|
+
* created_at: new Date(row.created_at as string),
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
mapper?: (row: Record<string, unknown>) => RowType;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for {@link Query.watch}.
|
|
30
|
+
*/
|
|
31
|
+
export interface StandardWatchedQueryOptions<RowType> extends WatchedQueryOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Optional comparator which processes the items of an array of rows.
|
|
34
|
+
* The comparator compares the result set rows by index using the {@link ArrayComparatorOptions#compareBy} function.
|
|
35
|
+
* The comparator reports a changed result set as soon as a row does not match the previous result set.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```javascript
|
|
39
|
+
* comparator: new ArrayComparator({
|
|
40
|
+
* compareBy: (item) => JSON.stringify(item)
|
|
41
|
+
* })
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
comparator?: ArrayComparator<RowType>;
|
|
45
|
+
/**
|
|
46
|
+
* The initial data state reported while the query is loading for the first time.
|
|
47
|
+
* @default []
|
|
48
|
+
*/
|
|
49
|
+
placeholderData?: RowType[];
|
|
50
|
+
}
|
|
51
|
+
export interface Query<RowType> {
|
|
52
|
+
/**
|
|
53
|
+
* Creates a {@link WatchedQuery} which watches and emits results of the linked query.
|
|
54
|
+
*
|
|
55
|
+
* By default the returned watched query will emit changes whenever a change to the underlying SQLite tables is made.
|
|
56
|
+
* These changes might not be relevant to the query, but the query will emit a new result set.
|
|
57
|
+
*
|
|
58
|
+
* A {@link StandardWatchedQueryOptions#comparator} can be provided to limit the data emissions. The watched query will still
|
|
59
|
+
* query the underlying DB on underlying table changes, but the result will only be emitted if the comparator detects a change in the results.
|
|
60
|
+
*
|
|
61
|
+
* The comparator in this method is optimized and returns early as soon as it detects a change. Each data emission will correlate to a change in the result set,
|
|
62
|
+
* but note that the result set will not maintain internal object references to the previous result set. If internal object references are needed,
|
|
63
|
+
* consider using {@link Query#differentialWatch} instead.
|
|
64
|
+
*/
|
|
65
|
+
watch(options?: StandardWatchedQueryOptions<RowType>): ComparisonWatchedQuery<ReadonlyArray<Readonly<RowType>>>;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a {@link WatchedQuery} which watches and emits results of the linked query.
|
|
68
|
+
*
|
|
69
|
+
* This query method watches for changes in the underlying SQLite tables and runs the query on each table change.
|
|
70
|
+
* The difference between the current and previous result set is computed.
|
|
71
|
+
* The watched query will not emit changes if the result set is identical to the previous result set.
|
|
72
|
+
* If the result set is different, the watched query will emit the new result set and provide a detailed diff of the changes.
|
|
73
|
+
*
|
|
74
|
+
* The deep differentiation allows maintaining result set object references between result emissions.
|
|
75
|
+
* The {@link DifferentialWatchedQuery#state} `data` array will contain the previous row references for unchanged rows.
|
|
76
|
+
* A detailed diff of the changes can be accessed via {@link DifferentialWatchedQuery#state} `diff`.
|
|
77
|
+
*/
|
|
78
|
+
differentialWatch(options?: DifferentialWatchedQueryOptions<RowType>): DifferentialWatchedQuery<RowType>;
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseListener,
|
|
1
|
+
import { BaseListener, BaseObserverInterface, 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 BaseObserverInterface<BucketStorageListener>, Disposable {
|
|
66
66
|
init(): Promise<void>;
|
|
67
67
|
saveSyncData(batch: SyncDataBatch, fixedKeyFormat?: boolean): Promise<void>;
|
|
68
68
|
removeBuckets(buckets: string[]): Promise<void>;
|