11import 'dart:async' ;
22
33import 'package:drift/backends.dart' ;
4- import 'package:drift_sqlite_async /src/transaction_executor .dart' ;
4+ import 'package:drift /src/runtime/query_builder/query_builder .dart' ;
55import 'package:sqlite_async/sqlite3_common.dart' ;
66import 'package:sqlite_async/sqlite_async.dart' ;
77
8- class _SqliteAsyncDelegate extends DatabaseDelegate {
8+ // Ends with " RETURNING *", or starts with insert/update/delete.
9+ // Drift-generated queries will always have the RETURNING *.
10+ // The INSERT/UPDATE/DELETE check is for custom queries, and is not exhaustive.
11+ final _returningCheck = RegExp (r'( RETURNING \*;?$)|(^(INSERT|UPDATE|DELETE))' ,
12+ caseSensitive: false );
13+
14+ class _SqliteAsyncDelegate extends _SqliteAsyncQueryDelegate
15+ implements DatabaseDelegate {
916 final SqliteConnection db;
1017 bool _closed = false ;
1118
12- _SqliteAsyncDelegate (this .db);
19+ _SqliteAsyncDelegate (this .db) : super (db, db.writeLock);
20+
21+ bool isInTransaction = false ; // unused
1322
1423 @override
1524 late final DbVersionDelegate versionDelegate =
@@ -18,18 +27,11 @@ class _SqliteAsyncDelegate extends DatabaseDelegate {
1827 // Not used - we override beginTransaction() with SqliteAsyncTransactionExecutor for more control.
1928 @override
2029 late final TransactionDelegate transactionDelegate =
21- const NoTransactionDelegate ( );
30+ _SqliteAsyncTransactionDelegate (db );
2231
2332 @override
2433 bool get isOpen => ! db.closed && ! _closed;
2534
26- // Ends with " RETURNING *", or starts with insert/update/delete.
27- // Drift-generated queries will always have the RETURNING *.
28- // The INSERT/UPDATE/DELETE check is for custom queries, and is not exhaustive.
29- final _returningCheck = RegExp (
30- r'( RETURNING \*;?$)|(^(INSERT|UPDATE|DELETE))' ,
31- caseSensitive: false );
32-
3335 @override
3436 Future <void > open (QueryExecutorUser user) async {
3537 // Workaround - this ensures the db is open
@@ -42,9 +44,30 @@ class _SqliteAsyncDelegate extends DatabaseDelegate {
4244 _closed = true ;
4345 }
4446
47+ @override
48+ void notifyDatabaseOpened (OpeningDetails details) {
49+ // Unused
50+ }
51+ }
52+
53+ class _SqliteAsyncQueryDelegate extends QueryDelegate {
54+ final SqliteWriteContext _context;
55+ final Future <T > Function <T >(
56+ Future <T > Function (SqliteWriteContext tx) callback)? _writeLock;
57+
58+ _SqliteAsyncQueryDelegate (this ._context, this ._writeLock);
59+
60+ Future <T > writeLock <T >(Future <T > Function (SqliteWriteContext tx) callback) {
61+ if (_writeLock case var writeLock? ) {
62+ return writeLock.call (callback);
63+ } else {
64+ return callback (_context);
65+ }
66+ }
67+
4568 @override
4669 Future <void > runBatched (BatchedStatements statements) async {
47- return db. writeLock ((tx) async {
70+ return writeLock ((tx) async {
4871 // sqlite_async's batch functionality doesn't have enough flexibility to support
4972 // this with prepared statements yet.
5073 for (final arg in statements.arguments) {
@@ -56,12 +79,12 @@ class _SqliteAsyncDelegate extends DatabaseDelegate {
5679
5780 @override
5881 Future <void > runCustom (String statement, List <Object ?> args) {
59- return db .execute (statement, args);
82+ return _context .execute (statement, args);
6083 }
6184
6285 @override
6386 Future <int > runInsert (String statement, List <Object ?> args) async {
64- return db. writeLock ((tx) async {
87+ return writeLock ((tx) async {
6588 await tx.execute (statement, args);
6689 final row = await tx.get ('SELECT last_insert_rowid() as row_id' );
6790 return row['row_id' ];
@@ -77,24 +100,38 @@ class _SqliteAsyncDelegate extends DatabaseDelegate {
77100 // This takes write lock, so we want to avoid it for plain select statements.
78101 // This is not an exhaustive check, but should cover all Drift-generated queries using
79102 // `runSelect()`.
80- result = await db .execute (statement, args);
103+ result = await _context .execute (statement, args);
81104 } else {
82105 // Plain SELECT statement - use getAll() to avoid using a write lock.
83- result = await db .getAll (statement, args);
106+ result = await _context .getAll (statement, args);
84107 }
85108 return QueryResult (result.columnNames, result.rows);
86109 }
87110
88111 @override
89112 Future <int > runUpdate (String statement, List <Object ?> args) {
90- return db. writeLock ((tx) async {
113+ return writeLock ((tx) async {
91114 await tx.execute (statement, args);
92115 final row = await tx.get ('SELECT changes() as changes' );
93116 return row['changes' ];
94117 });
95118 }
96119}
97120
121+ class _SqliteAsyncTransactionDelegate extends SupportedTransactionDelegate {
122+ final SqliteConnection _db;
123+
124+ _SqliteAsyncTransactionDelegate (this ._db);
125+
126+ @override
127+ Future <void > startTransaction (Future Function (QueryDelegate p1) run) async {
128+ await _db.writeTransaction ((context) async {
129+ final delegate = _SqliteAsyncQueryDelegate (context, null );
130+ return run (delegate);
131+ });
132+ }
133+ }
134+
98135class _SqliteAsyncVersionDelegate extends DynamicVersionDelegate {
99136 final SqliteConnection _db;
100137
@@ -137,9 +174,4 @@ class SqliteAsyncQueryExecutor extends DelegatedDatabase {
137174
138175 @override
139176 bool get isSequential => false ;
140-
141- @override
142- TransactionExecutor beginTransaction () {
143- return SqliteAsyncTransactionExecutor (db);
144- }
145177}
0 commit comments