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
|
### Minor changes
|
||||||
- a `Constant<String>` can now be written to SQL, it used to throw before. This is useful
|
- 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.
|
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
|
### Breaking changes
|
||||||
- __THIS LIKELY AFFECTS YOUR APP:__ Removed the `transaction` parameter for callbacks
|
- __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/runtime/exceptions.dart';
|
||||||
export 'package:moor/src/utils/expand_variables.dart';
|
export 'package:moor/src/utils/expand_variables.dart';
|
||||||
export 'package:moor/src/utils/hash.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;
|
return transactions;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
when(ensureOpen()).thenAnswer((i) {
|
||||||
|
_opened = true;
|
||||||
|
return Future.value(true);
|
||||||
|
});
|
||||||
|
|
||||||
when(doWhenOpened(any)).thenAnswer((i) {
|
when(doWhenOpened(any)).thenAnswer((i) {
|
||||||
_opened = true;
|
_opened = true;
|
||||||
final action = i.positionalArguments.single as _EnsureOpenAction;
|
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