@@ -35,7 +35,9 @@ export interface WatchOnChangeEvent {
3535 changedTables : string [ ] ;
3636}
3737
38- export interface PowerSyncDBListener extends StreamingSyncImplementationListener { }
38+ export interface PowerSyncDBListener extends StreamingSyncImplementationListener {
39+ initialized : ( ) => void ;
40+ }
3941
4042const POWERSYNC_TABLE_MATCH = / ( ^ p s _ d a t a _ _ | ^ p s _ d a t a _ l o c a l _ _ ) / ;
4143
@@ -61,6 +63,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
6163 protected static transactionMutex : Mutex = new Mutex ( ) ;
6264
6365 closed : boolean ;
66+ ready : boolean ;
6467
6568 currentStatus ?: SyncStatus ;
6669 syncStreamImplementation ?: AbstractStreamingSyncImplementation ;
@@ -69,14 +72,16 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
6972 private abortController : AbortController | null ;
7073 protected bucketStorageAdapter : BucketStorageAdapter ;
7174 private syncStatusListenerDisposer ?: ( ) => void ;
72- protected initialized : Promise < void > ;
75+ protected _isReadyPromise : Promise < void > | null ;
7376
7477 constructor ( protected options : PowerSyncDatabaseOptions ) {
7578 super ( ) ;
76- this . currentStatus = null ;
79+ this . _isReadyPromise = null ;
80+ this . bucketStorageAdapter = this . generateBucketStorageAdapter ( ) ;
7781 this . closed = true ;
82+ this . currentStatus = null ;
7883 this . options = { ...DEFAULT_POWERSYNC_DB_OPTIONS , ...options } ;
79- this . bucketStorageAdapter = this . generateBucketStorageAdapter ( ) ;
84+ this . ready = false ;
8085 this . sdkVersion = '' ;
8186 }
8287
@@ -98,16 +103,40 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
98103
99104 protected abstract generateBucketStorageAdapter ( ) : BucketStorageAdapter ;
100105
106+ /**
107+ * @returns A promise which will resolve once initialization is completed.
108+ */
109+ async waitForReady ( ) : Promise < void > {
110+ if ( this . ready ) {
111+ return ;
112+ }
113+
114+ return (
115+ this . _isReadyPromise ||
116+ ( this . _isReadyPromise = new Promise ( ( resolve ) => {
117+ const l = this . registerListener ( {
118+ initialized : ( ) => {
119+ this . ready = true ;
120+ resolve ( ) ;
121+ l ?.( ) ;
122+ }
123+ } ) ;
124+ } ) )
125+ ) ;
126+ }
127+
101128 abstract _init ( ) : Promise < void > ;
129+
130+ /**
131+ * This performs the total initialization process.
132+ */
102133 async init ( ) {
103- this . initialized = ( async ( ) => {
104- await this . _init ( ) ;
105- await this . bucketStorageAdapter . init ( ) ;
106- await this . database . execute ( 'SELECT powersync_replace_schema(?)' , [ JSON . stringify ( this . schema . toJSON ( ) ) ] ) ;
107- const version = await this . options . database . execute ( 'SELECT powersync_rs_version()' ) ;
108- this . sdkVersion = version . rows ?. item ( 0 ) [ 'powersync_rs_version()' ] ?? '' ;
109- } ) ( ) ;
110- await this . initialized ;
134+ await this . _init ( ) ;
135+ await this . bucketStorageAdapter . init ( ) ;
136+ await this . database . execute ( 'SELECT powersync_replace_schema(?)' , [ JSON . stringify ( this . schema . toJSON ( ) ) ] ) ;
137+ const version = await this . options . database . execute ( 'SELECT powersync_rs_version()' ) ;
138+ this . sdkVersion = version . rows ?. item ( 0 ) [ 'powersync_rs_version()' ] ?? '' ;
139+ this . iterateListeners ( ( cb ) => cb . initialized ?.( ) ) ;
111140 }
112141
113142 /**
@@ -117,7 +146,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
117146 // close connection if one is open
118147 await this . disconnect ( ) ;
119148
120- await this . initialized ;
149+ await this . waitForReady ( ) ;
121150 this . syncStreamImplementation = this . generateSyncStreamImplementation ( connector ) ;
122151 this . syncStatusListenerDisposer = this . syncStreamImplementation . registerListener ( {
123152 statusChanged : ( status ) => {
@@ -175,7 +204,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
175204 * must be constructed.
176205 */
177206 async close ( ) {
178- await this . initialized ;
207+ await this . waitForReady ( ) ;
179208
180209 await this . disconnect ( ) ;
181210 this . database . close ( ) ;
@@ -305,31 +334,31 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
305334 * Execute a statement and optionally return results
306335 */
307336 async execute ( sql : string , parameters ?: any [ ] ) {
308- await this . initialized ;
337+ await this . waitForReady ( ) ;
309338 return this . database . execute ( sql , parameters ) ;
310339 }
311340
312341 /**
313342 * Execute a read-only query and return results
314343 */
315344 async getAll < T > ( sql : string , parameters ?: any [ ] ) : Promise < T [ ] > {
316- await this . initialized ;
345+ await this . waitForReady ( ) ;
317346 return this . database . getAll ( sql , parameters ) ;
318347 }
319348
320349 /**
321350 * Execute a read-only query and return the first result, or null if the ResultSet is empty.
322351 */
323352 async getOptional < T > ( sql : string , parameters ?: any [ ] ) : Promise < T | null > {
324- await this . initialized ;
353+ await this . waitForReady ( ) ;
325354 return this . database . getOptional ( sql , parameters ) ;
326355 }
327356
328357 /**
329358 * Execute a read-only query and return the first result, error if the ResultSet is empty.
330359 */
331360 async get < T > ( sql : string , parameters ?: any [ ] ) : Promise < T > {
332- await this . initialized ;
361+ await this . waitForReady ( ) ;
333362 return this . database . get ( sql , parameters ) ;
334363 }
335364
@@ -339,7 +368,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
339368 * In most cases, [readTransaction] should be used instead.
340369 */
341370 async readLock < T > ( callback : ( db : DBAdapter ) => Promise < T > ) {
342- await this . initialized ;
371+ await this . waitForReady ( ) ;
343372 return mutexRunExclusive ( AbstractPowerSyncDatabase . transactionMutex , ( ) => callback ( this . database ) ) ;
344373 }
345374
@@ -348,7 +377,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
348377 * In most cases, [writeTransaction] should be used instead.
349378 */
350379 async writeLock < T > ( callback : ( db : DBAdapter ) => Promise < T > ) {
351- await this . initialized ;
380+ await this . waitForReady ( ) ;
352381 return mutexRunExclusive ( AbstractPowerSyncDatabase . transactionMutex , async ( ) => {
353382 const res = await callback ( this . database ) ;
354383 _ . defer ( ( ) => this . syncStreamImplementation ?. triggerCrudUpload ( ) ) ;
@@ -360,7 +389,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
360389 callback : ( tx : Transaction ) => Promise < T > ,
361390 lockTimeout : number = DEFAULT_LOCK_TIMEOUT_MS
362391 ) : Promise < T > {
363- await this . initialized ;
392+ await this . waitForReady ( ) ;
364393 return this . database . readTransaction (
365394 async ( tx ) => {
366395 const res = await callback ( { ...tx } ) ;
@@ -375,7 +404,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
375404 callback : ( tx : Transaction ) => Promise < T > ,
376405 lockTimeout : number = DEFAULT_LOCK_TIMEOUT_MS
377406 ) : Promise < T > {
378- await this . initialized ;
407+ await this . waitForReady ( ) ;
379408 return this . database . writeTransaction (
380409 async ( tx ) => {
381410 const res = await callback ( tx ) ;
@@ -389,7 +418,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
389418
390419 async * watch ( sql : string , parameters ?: any [ ] , options ?: SQLWatchOptions ) : AsyncIterable < QueryResult > {
391420 //Fetch initial data
392- yield await this . execute ( sql , parameters ) ;
421+ yield await this . executeReadOnly ( sql , parameters ) ;
393422
394423 const resolvedTables = options ?. tables ?? [ ] ;
395424 if ( ! options ?. tables ) {
@@ -408,7 +437,7 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
408437 ...( options ?? { } ) ,
409438 tables : resolvedTables
410439 } ) ) {
411- yield await this . execute ( sql , parameters ) ;
440+ yield await this . executeReadOnly ( sql , parameters ) ;
412441 }
413442 }
414443
@@ -459,4 +488,9 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
459488 return ( ) => dispose ( ) ;
460489 } ) ;
461490 }
491+
492+ private async executeReadOnly ( sql : string , params : any [ ] ) {
493+ await this . waitForReady ( ) ;
494+ return this . database . readLock ( ( tx ) => tx . execute ( sql , params ) ) ;
495+ }
462496}
0 commit comments