mirror of https://github.com/AMT-Cheif/drift.git
61 lines
2.4 KiB
Dart
61 lines
2.4 KiB
Dart
import 'dart:io';
|
|
import 'dart:isolate';
|
|
|
|
import 'package:drift/drift.dart';
|
|
import 'package:drift/isolate.dart';
|
|
import 'package:drift/native.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// Obtains a database connection for running drift in a Dart VM.
|
|
///
|
|
/// The [NativeDatabase] from drift will synchronously use sqlite3's C APIs.
|
|
/// To move synchronous database work off the main thread, we use a
|
|
/// [DriftIsolate], which can run queries in a background isolate under the
|
|
/// hood.
|
|
DatabaseConnection connect() {
|
|
return DatabaseConnection.delayed(Future.sync(() async {
|
|
// Background isolates can't use platform channels, so let's use
|
|
// `path_provider` in the main isolate and just send the result containing
|
|
// the path over to the background isolate.
|
|
final appDir = await getApplicationDocumentsDirectory();
|
|
final dbPath = p.join(appDir.path, 'todos.db');
|
|
|
|
final receiveDriftIsolate = ReceivePort();
|
|
await Isolate.spawn(_entrypointForDriftIsolate,
|
|
_IsolateStartRequest(receiveDriftIsolate.sendPort, dbPath));
|
|
|
|
final driftIsolate = await receiveDriftIsolate.first as DriftIsolate;
|
|
return driftIsolate.connect();
|
|
}));
|
|
}
|
|
|
|
/// The entrypoint of isolates can only take a single message, but we need two
|
|
/// (a send port to reach the originating isolate and the database's path that
|
|
/// should be opened on the background isolate). So, we bundle this information
|
|
/// in a single class.
|
|
class _IsolateStartRequest {
|
|
final SendPort talkToMain;
|
|
final String databasePath;
|
|
|
|
_IsolateStartRequest(this.talkToMain, this.databasePath);
|
|
}
|
|
|
|
/// The entrypoint for a background isolate launching a drift server.
|
|
///
|
|
/// The main isolate can then connect to that isolate server to transparently
|
|
/// run queries in the background.
|
|
void _entrypointForDriftIsolate(_IsolateStartRequest request) {
|
|
// The native database synchronously uses sqlite3's C API with `dart:ffi` for
|
|
// a fast database implementation that doesn't require platform channels.
|
|
final databaseImpl = NativeDatabase(File(request.databasePath));
|
|
|
|
// We can use DriftIsolate.inCurrent because this function is the entrypoint
|
|
// of a background isolate itself.
|
|
final driftServer =
|
|
DriftIsolate.inCurrent(() => DatabaseConnection(databaseImpl));
|
|
|
|
// Inform the main isolate about the server we just created.
|
|
request.talkToMain.send(driftServer);
|
|
}
|