@@ -8,11 +8,12 @@ import { UploadQueueStats } from '../db/crud/UploadQueueStatus';
8
8
import { PowerSyncBackendConnector } from './connection/PowerSyncBackendConnector' ;
9
9
import {
10
10
AbstractStreamingSyncImplementation ,
11
+ DEFAULT_CRUD_UPLOAD_THROTTLE_MS ,
11
12
StreamingSyncImplementationListener
12
13
} from './sync/stream/AbstractStreamingSyncImplementation' ;
13
14
import { CrudBatch } from './sync/bucket/CrudBatch' ;
14
15
import { CrudTransaction } from './sync/bucket/CrudTransaction' ;
15
- import { BucketStorageAdapter } from './sync/bucket/BucketStorageAdapter' ;
16
+ import { BucketStorageAdapter , PSInternalTable } from './sync/bucket/BucketStorageAdapter' ;
16
17
import { CrudEntry } from './sync/bucket/CrudEntry' ;
17
18
import { mutexRunExclusive } from '../utils/mutex' ;
18
19
import { BaseObserver } from '../utils/BaseObserver' ;
@@ -22,13 +23,19 @@ export interface PowerSyncDatabaseOptions {
22
23
schema : Schema ;
23
24
database : DBAdapter ;
24
25
retryDelay ?: number ;
26
+ crudUploadThrottleMs ?: number ;
25
27
logger ?: ILogger ;
26
28
}
27
29
28
30
export interface SQLWatchOptions {
29
31
signal ?: AbortSignal ;
30
32
tables ?: string [ ] ;
31
33
throttleMs ?: number ;
34
+ /**
35
+ * Allows for watching any SQL table
36
+ * by not removing PowerSync table name prefixes
37
+ */
38
+ rawTableNames ?: boolean ;
32
39
}
33
40
34
41
export interface WatchOnChangeEvent {
@@ -45,7 +52,8 @@ export const DEFAULT_WATCH_THROTTLE_MS = 30;
45
52
46
53
export const DEFAULT_POWERSYNC_DB_OPTIONS = {
47
54
retryDelay : 5000 ,
48
- logger : Logger . get ( 'PowerSyncDatabase' )
55
+ logger : Logger . get ( 'PowerSyncDatabase' ) ,
56
+ crudUploadThrottleMs : DEFAULT_CRUD_UPLOAD_THROTTLE_MS
49
57
} ;
50
58
51
59
/**
@@ -133,6 +141,21 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
133
141
this . sdkVersion = version . rows ?. item ( 0 ) [ 'powersync_rs_version()' ] ?? '' ;
134
142
this . ready = true ;
135
143
this . iterateListeners ( ( cb ) => cb . initialized ?.( ) ) ;
144
+ this . watchCrudUploads ( ) ;
145
+ }
146
+
147
+ /**
148
+ * Queues a CRUD upload when internal CRUD tables have been updated
149
+ */
150
+ protected async watchCrudUploads ( ) {
151
+ for await ( const event of this . onChange ( {
152
+ tables : [ PSInternalTable . CRUD ] ,
153
+ rawTableNames : true
154
+ } ) ) {
155
+ if ( this . connected ) {
156
+ this . syncStreamImplementation ?. triggerCrudUpload ( ) ;
157
+ }
158
+ }
136
159
}
137
160
138
161
/**
@@ -182,9 +205,9 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
182
205
183
206
// TODO DB name, verify this is necessary with extension
184
207
await this . database . writeTransaction ( async ( tx ) => {
185
- await tx . execute ( ' DELETE FROM ps_oplog WHERE 1' ) ;
186
- await tx . execute ( ' DELETE FROM ps_crud WHERE 1' ) ;
187
- await tx . execute ( ' DELETE FROM ps_buckets WHERE 1' ) ;
208
+ await tx . execute ( ` DELETE FROM ${ PSInternalTable . OPLOG } WHERE 1` ) ;
209
+ await tx . execute ( ` DELETE FROM ${ PSInternalTable . CRUD } WHERE 1` ) ;
210
+ await tx . execute ( ` DELETE FROM ${ PSInternalTable . BUCKETS } WHERE 1` ) ;
188
211
189
212
const existingTableRows = await tx . execute (
190
213
"SELECT name FROM sqlite_master WHERE type='table' AND name GLOB 'ps_data_*'"
@@ -220,12 +243,14 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
220
243
async getUploadQueueStats ( includeSize ?: boolean ) : Promise < UploadQueueStats > {
221
244
return this . readTransaction ( async ( tx ) => {
222
245
if ( includeSize ) {
223
- const result = await tx . execute ( 'SELECT SUM(cast(data as blob) + 20) as size, count(*) as count FROM ps_crud' ) ;
246
+ const result = await tx . execute (
247
+ `SELECT SUM(cast(data as blob) + 20) as size, count(*) as count FROM ${ PSInternalTable . CRUD } `
248
+ ) ;
224
249
225
250
const row = result . rows . item ( 0 ) ;
226
251
return new UploadQueueStats ( row ?. count ?? 0 , row ?. size ?? 0 ) ;
227
252
} else {
228
- const result = await tx . execute ( ' SELECT count(*) as count FROM ps_crud' ) ;
253
+ const result = await tx . execute ( ` SELECT count(*) as count FROM ${ PSInternalTable . CRUD } ` ) ;
229
254
const row = result . rows . item ( 0 ) ;
230
255
return new UploadQueueStats ( row ?. count ?? 0 ) ;
231
256
}
@@ -250,9 +275,10 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
250
275
* and a single transaction may be split over multiple batches.
251
276
*/
252
277
async getCrudBatch ( limit : number ) : Promise < CrudBatch | null > {
253
- const result = await this . database . execute ( 'SELECT id, tx_id, data FROM ps_crud ORDER BY id ASC LIMIT ?' , [
254
- limit + 1
255
- ] ) ;
278
+ const result = await this . database . execute (
279
+ `SELECT id, tx_id, data FROM ${ PSInternalTable . CRUD } ORDER BY id ASC LIMIT ?` ,
280
+ [ limit + 1 ]
281
+ ) ;
256
282
257
283
const all : CrudEntry [ ] = result . rows ?. _array ?. map ( ( row ) => CrudEntry . fromRow ( row ) ) ?? [ ] ;
258
284
@@ -268,11 +294,13 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
268
294
const last = all [ all . length - 1 ] ;
269
295
return new CrudBatch ( all , haveMore , async ( writeCheckpoint ?: string ) => {
270
296
await this . writeTransaction ( async ( tx ) => {
271
- await tx . execute ( 'DELETE FROM ps_crud WHERE id <= ?' , [ last . clientId ] ) ;
272
- if ( writeCheckpoint != null && ( await tx . execute ( 'SELECT 1 FROM ps_crud LIMIT 1' ) ) == null ) {
273
- await tx . execute ( "UPDATE ps_buckets SET target_op = ? WHERE name='$local'" , [ writeCheckpoint ] ) ;
297
+ await tx . execute ( `DELETE FROM ${ PSInternalTable . CRUD } WHERE id <= ?` , [ last . clientId ] ) ;
298
+ if ( writeCheckpoint != null && ( await tx . execute ( `SELECT 1 FROM ${ PSInternalTable . CRUD } LIMIT 1` ) ) == null ) {
299
+ await tx . execute ( `UPDATE ${ PSInternalTable . BUCKETS } SET target_op = ? WHERE name='$local'` , [
300
+ writeCheckpoint
301
+ ] ) ;
274
302
} else {
275
- await tx . execute ( " UPDATE ps_buckets SET target_op = ? WHERE name='$local'" , [
303
+ await tx . execute ( ` UPDATE ${ PSInternalTable . BUCKETS } SET target_op = ? WHERE name='$local'` , [
276
304
this . bucketStorageAdapter . getMaxOpId ( )
277
305
] ) ;
278
306
}
@@ -295,7 +323,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
295
323
*/
296
324
async getNextCrudTransaction ( ) : Promise < CrudTransaction > {
297
325
return await this . readTransaction ( async ( tx ) => {
298
- const first = await tx . execute ( ' SELECT id, tx_id, data FROM ps_crud ORDER BY id ASC LIMIT 1' ) ;
326
+ const first = await tx . execute ( ` SELECT id, tx_id, data FROM ${ PSInternalTable . CRUD } ORDER BY id ASC LIMIT 1` ) ;
299
327
300
328
if ( ! first . rows . length ) {
301
329
return null ;
@@ -306,7 +334,10 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
306
334
if ( ! txId ) {
307
335
all = [ CrudEntry . fromRow ( first . rows . item ( 0 ) ) ] ;
308
336
} else {
309
- const result = await tx . execute ( 'SELECT id, tx_id, data FROM ps_crud WHERE tx_id = ? ORDER BY id ASC' , [ txId ] ) ;
337
+ const result = await tx . execute (
338
+ `SELECT id, tx_id, data FROM ${ PSInternalTable . CRUD } WHERE tx_id = ? ORDER BY id ASC` ,
339
+ [ txId ]
340
+ ) ;
310
341
all = result . rows . _array . map ( ( row ) => CrudEntry . fromRow ( row ) ) ;
311
342
}
312
343
@@ -316,14 +347,16 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
316
347
all ,
317
348
async ( writeCheckpoint ?: string ) => {
318
349
await this . writeTransaction ( async ( tx ) => {
319
- await tx . execute ( ' DELETE FROM ps_crud WHERE id <= ?' , [ last . clientId ] ) ;
350
+ await tx . execute ( ` DELETE FROM ${ PSInternalTable . CRUD } WHERE id <= ?` , [ last . clientId ] ) ;
320
351
if ( writeCheckpoint ) {
321
- const check = await tx . execute ( ' SELECT 1 FROM ps_crud LIMIT 1' ) ;
352
+ const check = await tx . execute ( ` SELECT 1 FROM ${ PSInternalTable . CRUD } LIMIT 1` ) ;
322
353
if ( ! check . rows ?. length ) {
323
- await tx . execute ( "UPDATE ps_buckets SET target_op = ? WHERE name='$local'" , [ writeCheckpoint ] ) ;
354
+ await tx . execute ( `UPDATE ${ PSInternalTable . BUCKETS } SET target_op = ? WHERE name='$local'` , [
355
+ writeCheckpoint
356
+ ] ) ;
324
357
}
325
358
} else {
326
- await tx . execute ( " UPDATE ps_buckets SET target_op = ? WHERE name='$local'" , [
359
+ await tx . execute ( ` UPDATE ${ PSInternalTable . BUCKETS } SET target_op = ? WHERE name='$local'` , [
327
360
this . bucketStorageAdapter . getMaxOpId ( )
328
361
] ) ;
329
362
}
@@ -340,7 +373,6 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
340
373
async execute ( sql : string , parameters ?: any [ ] ) {
341
374
await this . waitForReady ( ) ;
342
375
const result = await this . database . execute ( sql , parameters ) ;
343
- _ . defer ( ( ) => this . syncStreamImplementation ?. triggerCrudUpload ( ) ) ;
344
376
return result ;
345
377
}
346
378
@@ -386,7 +418,6 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
386
418
await this . waitForReady ( ) ;
387
419
return mutexRunExclusive ( AbstractPowerSyncDatabase . transactionMutex , async ( ) => {
388
420
const res = await callback ( this . database ) ;
389
- _ . defer ( ( ) => this . syncStreamImplementation ?. triggerCrudUpload ( ) ) ;
390
421
return res ;
391
422
} ) ;
392
423
}
@@ -415,7 +446,6 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
415
446
async ( tx ) => {
416
447
const res = await callback ( tx ) ;
417
448
await tx . commit ( ) ;
418
- _ . defer ( ( ) => this . syncStreamImplementation ?. triggerCrudUpload ( ) ) ;
419
449
return res ;
420
450
} ,
421
451
{ timeoutMs : lockTimeout }
@@ -475,10 +505,13 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
475
505
const dispose = this . database . registerListener ( {
476
506
tablesUpdated : async ( update ) => {
477
507
const { table } = update ;
478
- if ( ! table . match ( POWERSYNC_TABLE_MATCH ) ) {
508
+ const { rawTableNames } = options ;
509
+
510
+ if ( ! rawTableNames && ! table . match ( POWERSYNC_TABLE_MATCH ) ) {
479
511
return ;
480
512
}
481
- const tableName = table . replace ( POWERSYNC_TABLE_MATCH , '' ) ;
513
+
514
+ const tableName = rawTableNames ? table : table . replace ( POWERSYNC_TABLE_MATCH , '' ) ;
482
515
throttledTableUpdates . push ( tableName ) ;
483
516
484
517
flushTableUpdates ( ) ;
0 commit comments