mirror of https://github.com/AMT-Cheif/drift.git
Add LazyDatabase wrapper to create a database async
This commit is contained in:
parent
7d962a1f01
commit
87c50de1e1
|
@ -54,6 +54,8 @@ TODO: Describe ffi port
|
|||
### Minor changes
|
||||
- a `Constant<String>` can now be written to SQL, it used to throw before. This is useful
|
||||
if you need default values for strings columns.
|
||||
- new `LazyDatabase` when you want to construct a database asynchronously (for instance, if
|
||||
you first need to find a file before you can open a database).
|
||||
|
||||
### Breaking changes
|
||||
- __THIS LIKELY AFFECTS YOUR APP:__ Removed the `transaction` parameter for callbacks
|
||||
|
|
|
@ -35,3 +35,4 @@ export 'package:moor/src/runtime/migration.dart';
|
|||
export 'package:moor/src/runtime/exceptions.dart';
|
||||
export 'package:moor/src/utils/expand_variables.dart';
|
||||
export 'package:moor/src/utils/hash.dart';
|
||||
export 'package:moor/src/utils/lazy_database.dart';
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:moor/backends.dart';
|
||||
|
||||
/// Signature of a function that opens a database connection when instructed to.
|
||||
typedef DatabaseOpener = FutureOr<QueryExecutor> Function();
|
||||
|
||||
/// A special database executor that delegates work to another [QueryExecutor].
|
||||
/// The other executor is lazily opened by a [DatabaseOpener].
|
||||
class LazyDatabase extends QueryExecutor {
|
||||
QueryExecutor _delegate;
|
||||
Completer<void> _openDelegate;
|
||||
|
||||
/// The function that will open the database when this [LazyDatabase] gets
|
||||
/// opened for the first time.
|
||||
final DatabaseOpener opener;
|
||||
|
||||
LazyDatabase(this.opener);
|
||||
|
||||
Future<void> _awaitOpened() {
|
||||
if (_delegate != null) {
|
||||
return Future.value();
|
||||
} else if (_openDelegate != null) {
|
||||
return _openDelegate.future;
|
||||
} else {
|
||||
_openDelegate = Completer();
|
||||
Future.value(opener()).then((database) {
|
||||
_delegate = database;
|
||||
_openDelegate.complete();
|
||||
});
|
||||
return _openDelegate.future;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionExecutor beginTransaction() => _delegate.beginTransaction();
|
||||
|
||||
@override
|
||||
Future<bool> ensureOpen() {
|
||||
return _awaitOpened().then((_) => _delegate.ensureOpen());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> runBatched(List<BatchedStatement> statements) =>
|
||||
_delegate.runBatched(statements);
|
||||
|
||||
@override
|
||||
Future<void> runCustom(String statement, [List args]) =>
|
||||
_delegate.runCustom(statement, args);
|
||||
|
||||
@override
|
||||
Future<int> runDelete(String statement, List args) =>
|
||||
_delegate.runDelete(statement, args);
|
||||
|
||||
@override
|
||||
Future<int> runInsert(String statement, List args) =>
|
||||
_delegate.runInsert(statement, args);
|
||||
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> runSelect(String statement, List args) =>
|
||||
_delegate.runSelect(statement, args);
|
||||
|
||||
@override
|
||||
Future<int> runUpdate(String statement, List args) =>
|
||||
_delegate.runUpdate(statement, args);
|
||||
}
|
|
@ -34,6 +34,11 @@ class MockExecutor extends Mock implements QueryExecutor {
|
|||
return transactions;
|
||||
});
|
||||
|
||||
when(ensureOpen()).thenAnswer((i) {
|
||||
_opened = true;
|
||||
return Future.value(true);
|
||||
});
|
||||
|
||||
when(doWhenOpened(any)).thenAnswer((i) {
|
||||
_opened = true;
|
||||
final action = i.positionalArguments.single as _EnsureOpenAction;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:moor/moor.dart';
|
||||
import 'package:pedantic/pedantic.dart';
|
||||
import 'package:test_api/test_api.dart';
|
||||
|
||||
import '../data/utils/mocks.dart';
|
||||
|
||||
void main() {
|
||||
test('lazy database delegates work', () async {
|
||||
final inner = MockExecutor();
|
||||
final lazy = LazyDatabase(() => inner);
|
||||
|
||||
await lazy.ensureOpen();
|
||||
clearInteractions(inner);
|
||||
|
||||
lazy.beginTransaction();
|
||||
await lazy.runBatched(null);
|
||||
await lazy.runCustom('custom_stmt');
|
||||
await lazy.runDelete('delete_stmt', [1]);
|
||||
await lazy.runInsert('insert_stmt', [2]);
|
||||
await lazy.runSelect('select_stmt', [3]);
|
||||
await lazy.runUpdate('update_stmt', [4]);
|
||||
|
||||
verifyInOrder([
|
||||
inner.runBatched(null),
|
||||
inner.runCustom('custom_stmt'),
|
||||
inner.runDelete('delete_stmt', [1]),
|
||||
inner.runInsert('insert_stmt', [2]),
|
||||
inner.runSelect('select_stmt', [3]),
|
||||
inner.runUpdate('update_stmt', [4]),
|
||||
]);
|
||||
});
|
||||
|
||||
test('database is only opened once', () async {
|
||||
final inner = MockExecutor();
|
||||
var openCount = 0;
|
||||
final lazy = LazyDatabase(() {
|
||||
openCount++;
|
||||
return inner;
|
||||
});
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
unawaited(lazy.ensureOpen());
|
||||
}
|
||||
|
||||
await pumpEventQueue();
|
||||
expect(openCount, 1);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue