@@ -28,26 +28,24 @@ public class BasePowerSyncDatabaseOptions()
28
28
29
29
}
30
30
31
- public abstract class DatabaseSource { }
31
+ public interface IDatabaseSource { }
32
32
33
- public class DBAdapterSource ( IDBAdapter Adapter ) : DatabaseSource
33
+ public class DBAdapterSource ( IDBAdapter Adapter ) : IDatabaseSource
34
34
{
35
35
public IDBAdapter Adapter { get ; init ; } = Adapter ;
36
36
}
37
37
38
- public class OpenFactorySource ( ISQLOpenFactory Factory ) : DatabaseSource
38
+ public class OpenFactorySource ( ISQLOpenFactory Factory ) : IDatabaseSource
39
39
{
40
40
public ISQLOpenFactory Factory { get ; init ; } = Factory ;
41
41
}
42
42
43
-
44
43
public class PowerSyncDatabaseOptions ( ) : BasePowerSyncDatabaseOptions ( )
45
44
{
46
45
/// <summary>
47
46
/// Source for a SQLite database connection.
48
47
/// </summary>
49
- public DatabaseSource Database { get ; set ; } = null ! ;
50
-
48
+ public IDatabaseSource Database { get ; set ; } = null ! ;
51
49
}
52
50
53
51
public class PowerSyncDBEvent : StreamingSyncImplementationEvent
@@ -64,6 +62,25 @@ public interface IPowerSyncDatabase : IEventStream<PowerSyncDBEvent>
64
62
public Task < CrudBatch ? > GetCrudBatch ( int limit ) ;
65
63
66
64
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
+
67
84
}
68
85
69
86
public class PowerSyncDatabase : EventStream < PowerSyncDBEvent > , IPowerSyncDatabase
@@ -103,9 +120,6 @@ public PowerSyncDatabase(PowerSyncDatabaseOptions options)
103
120
}
104
121
else if ( options . Database is SQLOpenOptions openOptions )
105
122
{
106
- // TODO default to MDSQLite factory for now
107
- // Can be broken out, rename this class to Abstract
108
- // `this.openDBAdapter(options)`
109
123
Database = new MDSQLiteAdapter ( new MDSQLiteAdapterOptions
110
124
{
111
125
Name = openOptions . DbFilename ,
@@ -251,7 +265,7 @@ public async Task UpdateSchema(Schema schema)
251
265
252
266
try
253
267
{
254
- // schema.Validate();
268
+ schema . Validate ( ) ;
255
269
}
256
270
catch ( Exception ex )
257
271
{
@@ -342,13 +356,19 @@ public async Task Disconnect()
342
356
syncStreamStatusCts ? . Cancel ( ) ;
343
357
}
344
358
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 )
346
368
{
347
369
await Disconnect ( ) ;
348
370
await WaitForReady ( ) ;
349
371
350
- // TODO CL bool clearLocal = options?.ClearLocal ?? false;
351
- bool clearLocal = true ;
352
372
353
373
await Database . WriteTransaction ( async tx =>
354
374
{
@@ -360,17 +380,23 @@ await Database.WriteTransaction(async tx =>
360
380
Emit ( new PowerSyncDBEvent { StatusChanged = CurrentStatus } ) ;
361
381
}
362
382
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>
363
391
public new async Task Close ( )
364
392
{
365
- base . Close ( ) ;
366
393
await WaitForReady ( ) ;
367
394
368
- // TODO CL
369
- // if (options.Disconnect)
370
- // {
371
- // await Disconnect();
372
- // }
395
+ if ( Closed ) return ;
396
+
373
397
398
+ await Disconnect ( ) ;
399
+ base . Close ( ) ;
374
400
syncStreamImplementation ? . Close ( ) ;
375
401
BucketStorageAdapter ? . Close ( ) ;
376
402
@@ -436,7 +462,7 @@ await Database.WriteTransaction(async tx =>
436
462
/// </summary>
437
463
public async Task < CrudTransaction ? > GetNextCrudTransaction ( )
438
464
{
439
- return await Database . ReadTransaction ( async tx =>
465
+ return await ReadTransaction ( async tx =>
440
466
{
441
467
var first = await tx . GetOptional < CrudEntryJSON > (
442
468
$ "SELECT id, tx_id, data FROM { PSInternalTable . CRUD } ORDER BY id ASC LIMIT 1") ;
@@ -451,6 +477,7 @@ await Database.WriteTransaction(async tx =>
451
477
452
478
if ( txId == null )
453
479
{
480
+
454
481
all = [ CrudEntry . FromRow ( first ) ] ;
455
482
}
456
483
else
@@ -529,15 +556,51 @@ public async Task<T> Get<T>(string query, object[]? parameters = null)
529
556
return await Database . Get < T > ( query , parameters ) ;
530
557
}
531
558
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
+ }
532
594
533
595
/// <summary>
534
596
/// Executes a read query every time the source tables are modified.
535
597
/// <para />
536
598
/// Use <see cref="SQLWatchOptions.ThrottleMs"/> to specify the minimum interval between queries.
537
599
/// Source tables are automatically detected using <c>EXPLAIN QUERY PLAN</c>.
538
600
/// </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 )
540
602
{
603
+ var tcs = new TaskCompletionSource < bool > ( ) ;
541
604
Task . Run ( async ( ) =>
542
605
{
543
606
try
@@ -567,12 +630,14 @@ public void Watch<T>(string query, object[]? parameters, WatchHandler<T> handler
567
630
Signal = options ? . Signal ,
568
631
ThrottleMs = options ? . ThrottleMs
569
632
} ) ;
633
+ tcs . SetResult ( true ) ;
570
634
}
571
635
catch ( Exception ex )
572
636
{
573
637
handler . OnError ? . Invoke ( ex ) ;
574
638
}
575
639
} ) ;
640
+ return tcs . Task ;
576
641
}
577
642
578
643
private record ExplainedResult ( string opcode , int p2 , int p3 ) ;
@@ -592,7 +657,6 @@ public async Task<string[]> ResolveTables(string sql, object[]? parameters = nul
592
657
. Select ( row => row . p2 )
593
658
. ToList ( ) ;
594
659
595
-
596
660
var tables = await GetAll < TableSelectResult > (
597
661
"SELECT DISTINCT tbl_name FROM sqlite_master WHERE rootpage IN (SELECT json_each.value FROM json_each(?))" ,
598
662
[ JsonConvert . SerializeObject ( rootPages ) ]
0 commit comments