「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。
Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)
本文翻译自 drift 的 官方文档 Web (simonbinder.eu)。
肉翻多有不足,不吝赐教。
Web
对于 drift 和 Web 应用试验性地支持
可以试验性地在 Dart 的 Web 应用中使用 drift 。 drift web 支持 Flutter Web 、 AngularDart 、纯文本 dart:html 或其它 web 框架。
开始
从使用 Dart 代码的前景来看,Web 上的 drift 和其它平台上的 drift 类似。 可以跟着开始指南看一下使用 drift 的一般信息。
在数据库类中代替使用 NativeDatabase ,可以使用 WebDatabase 执行器:
import 'package:drift/web.dart';
@DriftDatabase(tables: [Todos, Categories])
class MyDatabase extends _$MyDatabase {
// 这里 "app" 是数据库的名称 - 可以使用任何想用的名称
MyDatabase() : super(WebDatabase('app'));
Dart Web 基于 sql.js 库构建, 需要引入此库。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script defer src="sql-wasm.js"></script>
<script defer src="main.dart.js" type="application/javascript"></script>
</head>
<body></body>
</html>
可以在这里抓取 sql-wasm.js 和 sql-wasm.wasm 的最新版本,然后把它们放到 web 目录中。
这里有一个完整的在 Web (和其它所有平台)上运行的例子。
Gotchas(整明白?)
数据库的实现使用了 WebAssembly ,需要浏览器支持 WebAssembly。
也要确认 Web 服务器能将 .wasm 文件识别为 application/wasm,否则浏览器不会接受。
在原生应用和 Web 共享代码
如果想要在原生应用和 Web 应用之间共享数据库代码,只需要将基本的 drift/drift.dart 库导入到数据库文件中。代替传递 一个 NativeDatabase 或 WebDatabase 给 super 构造方法,需要使 QueryExecutor 可定制:
// 不要在共享代码中导入 drift/web.dart 或 drift/native.dart
import 'package:drift/drift.dart';
@DriftDatabase(/* ... */)
class SharedDatabase extends _$MyDatabase {
SharedDatabase(QueryExecutor e): super(e);
}
在原生 Flutter 应用中,可以如下创建数据库的实例:
// native.dart
import 'package:drift/native.dart';
SharedDatabase constructDb() {
final db = LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
return NativeDatabase(file);
});
return SharedDatabase(db);
}
在 Web 应用中,可以使用:
// web.dart
import 'package:drift/web.dart';
SharedDatabase constructDb() {
return SharedDatabase(WebDatabase('db'));
}
最后,可以使用条件导入基于应用运行的位置自动选择正确的 constructDb 。要做到这个,首先创建一个默认实现的 unsupported.dart:
// unsupported.dart
SharedDatabase constructDb() => throw UnimplementedError();
现在,在 shared.dart 文件中使用条件导入来导出正确的函数:
// shared.dart
export 'unsupported.dart'
if (dart.library.ffi) 'native.dart'
if (dart.library.html) 'web.dart';
在这里找到这种构成的可用示例。
调试
可以通过将 WebDatabase 的 logStatements 设为可用,来看到 drift 发送给底层数据库的所有查询。这些信息会在控制台出现。如果断言可用(例如在调试模式), drift 会通过 window.db 暴露底层数据库对象。如果需要快速运行一个查询来检查数据库的状态,可以使用 db.exec(sql)。如果需要删除数据库(这里用 local storage 存储),可以用 localStorage.clear() 清空所有数据。
现在的时点,对 Web 的支持还是试验性的,所以请报告所有发现的问题。
使用 IndexedDb (索引数据库?)
默认的 WebDatabase 使用 local storage 来存储原始数据库文件。也可以在支持的浏览器上使用 IndexedDb 来存储 blob。通常,浏览器对于 IndexedDb 允许一个更大的容量。它的实现也有更好的性能,因为不需要把二进制编码为字符串。
要在支持的浏览器上使用这个实现,需要将 WebDatabase(name) 替换为以下内容:
WebDatabase.withStorage(await DriftWebStorage.indexedDbIfSupported(name))
IndexedDb 可用时,drift 会自动把数据从 local storage 迁移到 IndexedDb 中。
使用 web workers
可以通过使用 Web Workers 从后台线程中卸载数据库。 drift 也支持 shared workers,这允许无缝地同步跨多标签页的查询流和更新。
因为 web workers 不使用本地存储,所以需要使用 DriftWebStorage.indexedDb 代替常规实现。
以下的例子本来是要在一个常规的 Dart web 应用中使用,用 build_web_compilers 编译。
Flutter 用户需要使用一个不同的方式来编译 service workers。正如可以编译一个单独的 Dart 文件(用 main函数,不是应用)到一个 js 文件中,也可以用它来作为 worker 。
要为 drift 写一个服务请求的 web worker ,需要在应用的 web/ 目录下创建一个 worder.dart 的文件。它会有以下内容:
import 'dart:html';
import 'package:drift/drift.dart';
import 'package:drift/web.dart';
import 'package:drift/remote.dart';
void main() {
final self = SharedWorkerGlobalScope.instance;
self.importScripts('sql-wasm.js');
final db = WebDatabase.withStorage(DriftWebStorage.indexedDb('worker',
migrateFromLocalStorage: false, inWebWorker: true));
final server = DriftServer(DatabaseConnection.fromExecutor(db));
self.onConnect.listen((event) {
final msg = event as MessageEvent;
server.serve(msg.ports.first.channel());
});
}
更多关于此 api 的信息,参考 remote API 。
使用 drift 的 web 和 remote api ,连接这个 worker 非常简单。 在常规的应用代码( workder 之外)中,可以如下连接:
import 'dart:html';
import 'package:drift/remote.dart';
import 'package:drift/web.dart';
import 'package:web_worker_example/database.dart';
DatabaseConnection connectToWorker() {
final worker = SharedWorker('worker.dart.js');
return remote(worker.port!.channel());
}
可以通过使 generate_connect_constructor 构建选项可用来给数据库传递 DatabaseConnection 。关于 DatabaseConnection 类的更多信息,参考下 isolates 的文档。
在 drift 仓库中, extras/web_worker_example 下面有一个虽小但是可运行的示例。