@@ -28,26 +28,24 @@ public class BasePowerSyncDatabaseOptions()
2828
2929}
3030
31- public abstract class DatabaseSource { }
31+ public interface IDatabaseSource { }
3232
33- public class DBAdapterSource ( IDBAdapter Adapter ) : DatabaseSource
33+ public class DBAdapterSource ( IDBAdapter Adapter ) : IDatabaseSource
3434{
3535 public IDBAdapter Adapter { get ; init ; } = Adapter ;
3636}
3737
38- public class OpenFactorySource ( ISQLOpenFactory Factory ) : DatabaseSource
38+ public class OpenFactorySource ( ISQLOpenFactory Factory ) : IDatabaseSource
3939{
4040 public ISQLOpenFactory Factory { get ; init ; } = Factory ;
4141}
4242
43-
4443public class PowerSyncDatabaseOptions ( ) : BasePowerSyncDatabaseOptions ( )
4544{
4645 /// <summary>
4746 /// Source for a SQLite database connection.
4847 /// </summary>
49- public DatabaseSource Database { get ; set ; } = null ! ;
50-
48+ public IDatabaseSource Database { get ; set ; } = null ! ;
5149}
5250
5351public class PowerSyncDBEvent : StreamingSyncImplementationEvent
@@ -64,6 +62,25 @@ public interface IPowerSyncDatabase : IEventStream<PowerSyncDBEvent>
6462 public Task < CrudBatch ? > GetCrudBatch ( int limit ) ;
6563
6664 public Task < CrudTransaction ? > GetNextCrudTransaction ( ) ;
65+
66+ Task < NonQueryResult > Execute ( string query , object [ ] ? parameters = null ) ;
67+
68+ Task < T [ ] > GetAll < T > ( string sql , params object [ ] ? parameters ) ;
69+
70+ Task < T ? > GetOptional < T > ( string sql , params object [ ] ? parameters ) ;
71+
72+ Task < T > Get < T > ( string sql , params object [ ] ? parameters ) ;
73+
74+ Task < T > ReadLock < T > ( Func < ILockContext , Task < T > > fn , DBLockOptions ? options = null ) ;
75+
76+ Task < T > ReadTransaction < T > ( Func < ITransaction , Task < T > > fn , DBLockOptions ? options = null ) ;
77+
78+ Task WriteLock ( Func < ILockContext , Task > fn , DBLockOptions ? options = null ) ;
79+ Task < T > WriteLock < T > ( Func < ILockContext , Task < T > > fn , DBLockOptions ? options = null ) ;
80+
81+ Task WriteTransaction ( Func < ITransaction , Task > fn , DBLockOptions ? options = null ) ;
82+ Task < T > WriteTransaction < T > ( Func < ITransaction , Task < T > > fn , DBLockOptions ? options = null ) ;
83+
6784}
6885
6986public class PowerSyncDatabase : EventStream < PowerSyncDBEvent > , IPowerSyncDatabase
@@ -103,9 +120,6 @@ public PowerSyncDatabase(PowerSyncDatabaseOptions options)
103120 }
104121 else if ( options . Database is SQLOpenOptions openOptions )
105122 {
106- // TODO default to MDSQLite factory for now
107- // Can be broken out, rename this class to Abstract
108- // `this.openDBAdapter(options)`
109123 Database = new MDSQLiteAdapter ( new MDSQLiteAdapterOptions
110124 {
111125 Name = openOptions . DbFilename ,
@@ -251,7 +265,7 @@ public async Task UpdateSchema(Schema schema)
251265
252266 try
253267 {
254- // schema.Validate();
268+ schema . Validate ( ) ;
255269 }
256270 catch ( Exception ex )
257271 {
@@ -342,13 +356,19 @@ public async Task Disconnect()
342356 syncStreamStatusCts ? . Cancel ( ) ;
343357 }
344358
345- public async Task DisconnectAndClear ( )
359+ /// <summary>
360+ /// Disconnect and clear the database.
361+ /// Use this when logging out.
362+ /// The database can still be queried after this is called, but the tables
363+ /// would be empty.
364+ ///
365+ /// To preserve data in local-only tables, set clearLocal to false.
366+ /// </summary>
367+ public async Task DisconnectAndClear ( bool clearLocal = true )
346368 {
347369 await Disconnect ( ) ;
348370 await WaitForReady ( ) ;
349371
350- // TODO CL bool clearLocal = options?.ClearLocal ?? false;
351- bool clearLocal = true ;
352372
353373 await Database . WriteTransaction ( async tx =>
354374 {
@@ -360,17 +380,23 @@ await Database.WriteTransaction(async tx =>
360380 Emit ( new PowerSyncDBEvent { StatusChanged = CurrentStatus } ) ;
361381 }
362382
383+ /// <summary>
384+ /// Close the database, releasing resources.
385+ ///
386+ /// Also disconnects any active connection.
387+ ///
388+ /// Once close is called, this connection cannot be used again - a new one
389+ /// must be constructed.
390+ /// </summary>
363391 public new async Task Close ( )
364392 {
365- base . Close ( ) ;
366393 await WaitForReady ( ) ;
367394
368- // TODO CL
369- // if (options.Disconnect)
370- // {
371- // await Disconnect();
372- // }
395+ if ( Closed ) return ;
396+
373397
398+ await Disconnect ( ) ;
399+ base . Close ( ) ;
374400 syncStreamImplementation ? . Close ( ) ;
375401 BucketStorageAdapter ? . Close ( ) ;
376402
@@ -436,7 +462,7 @@ await Database.WriteTransaction(async tx =>
436462 /// </summary>
437463 public async Task < CrudTransaction ? > GetNextCrudTransaction ( )
438464 {
439- return await Database . ReadTransaction ( async tx =>
465+ return await ReadTransaction ( async tx =>
440466 {
441467 var first = await tx . GetOptional < CrudEntryJSON > (
442468 $ "SELECT id, tx_id, data FROM { PSInternalTable . CRUD } ORDER BY id ASC LIMIT 1") ;
@@ -451,6 +477,7 @@ await Database.WriteTransaction(async tx =>
451477
452478 if ( txId == null )
453479 {
480+
454481 all = [ CrudEntry . FromRow ( first ) ] ;
455482 }
456483 else
@@ -529,15 +556,51 @@ public async Task<T> Get<T>(string query, object[]? parameters = null)
529556 return await Database . Get < T > ( query , parameters ) ;
530557 }
531558
559+ public async Task < T > ReadLock < T > ( Func < ILockContext , Task < T > > fn , DBLockOptions ? options = null )
560+ {
561+ await WaitForReady ( ) ;
562+ return await Database . ReadLock ( fn , options ) ;
563+ }
564+
565+ public async Task WriteLock ( Func < ILockContext , Task > fn , DBLockOptions ? options = null )
566+ {
567+ await WaitForReady ( ) ;
568+ await Database . WriteLock ( fn , options ) ;
569+ }
570+
571+ public async Task < T > WriteLock < T > ( Func < ILockContext , Task < T > > fn , DBLockOptions ? options = null )
572+ {
573+ await WaitForReady ( ) ;
574+ return await Database . WriteLock ( fn , options ) ;
575+ }
576+
577+ public async Task < T > ReadTransaction < T > ( Func < ITransaction , Task < T > > fn , DBLockOptions ? options = null )
578+ {
579+ await WaitForReady ( ) ;
580+ return await Database . ReadTransaction ( fn , options ) ;
581+ }
582+
583+ public async Task WriteTransaction ( Func < ITransaction , Task > fn , DBLockOptions ? options = null )
584+ {
585+ await WaitForReady ( ) ;
586+ await Database . WriteTransaction ( fn , options ) ;
587+ }
588+
589+ public async Task < T > WriteTransaction < T > ( Func < ITransaction , Task < T > > fn , DBLockOptions ? options = null )
590+ {
591+ await WaitForReady ( ) ;
592+ return await Database . WriteTransaction ( fn , options ) ;
593+ }
532594
533595 /// <summary>
534596 /// Executes a read query every time the source tables are modified.
535597 /// <para />
536598 /// Use <see cref="SQLWatchOptions.ThrottleMs"/> to specify the minimum interval between queries.
537599 /// Source tables are automatically detected using <c>EXPLAIN QUERY PLAN</c>.
538600 /// </summary>
539- public void Watch < T > ( string query , object [ ] ? parameters , WatchHandler < T > handler , SQLWatchOptions ? options = null )
601+ public Task Watch < T > ( string query , object [ ] ? parameters , WatchHandler < T > handler , SQLWatchOptions ? options = null )
540602 {
603+ var tcs = new TaskCompletionSource < bool > ( ) ;
541604 Task . Run ( async ( ) =>
542605 {
543606 try
@@ -567,12 +630,14 @@ public void Watch<T>(string query, object[]? parameters, WatchHandler<T> handler
567630 Signal = options ? . Signal ,
568631 ThrottleMs = options ? . ThrottleMs
569632 } ) ;
633+ tcs . SetResult ( true ) ;
570634 }
571635 catch ( Exception ex )
572636 {
573637 handler . OnError ? . Invoke ( ex ) ;
574638 }
575639 } ) ;
640+ return tcs . Task ;
576641 }
577642
578643 private record ExplainedResult ( string opcode , int p2 , int p3 ) ;
@@ -592,7 +657,6 @@ public async Task<string[]> ResolveTables(string sql, object[]? parameters = nul
592657 . Select ( row => row . p2 )
593658 . ToList ( ) ;
594659
595-
596660 var tables = await GetAll < TableSelectResult > (
597661 "SELECT DISTINCT tbl_name FROM sqlite_master WHERE rootpage IN (SELECT json_each.value FROM json_each(?))" ,
598662 [ JsonConvert . SerializeObject ( rootPages ) ]
0 commit comments