[官网文档翻译]Flutter持久化库drift - 其它引擎 - 原生drift(桌面支持)
本文翻译自 drift 的 官方文档 Native Drift (Desktop support) (simonbinder.eu)。
肉翻多有不足,不吝赐教。
原生drift(桌面支持)
同时在移动端和桌面端运行 drift。
支持的平台
drift/native.dart
库使用 sqlite3
的包来发送查询。现在的时点,这个包支持 iOS 、 Mac 和 Android (开箱即用)。大多数的 Linux 发行版都带有 sqlite 作为共享库,这些发行版也都被支持。
如果要在 Windows 和 Linux 上装载应用,建议捆绑上 sqlite3.so
和 sqlite3.dll
。可以通过在打开数据库之前运动下面的代码让 drift
支持安装:
import 'dart:ffi';
import 'dart:io';
import 'package:sqlite3/sqlite3.dart';
import 'package:sqlite3/open.dart';
void main() {
open.overrideFor(OperatingSystem.linux, _openOnLinux);
final db = sqlite3.openInMemory();
db.dispose();
}
DynamicLibrary _openOnLinux() {
final script = File(Platform.script.toFilePath());
final libraryNextToScript = File('${script.path}/sqlite3.so');
return DynamicLibrary.open(libraryNextToScript.path);
}
// _openOnWindows 也和打开 `sqlite3.dll` 一样会生效。
从 moor_flutter 迁移到 drift/navitve
首先,修改 pubspec.yaml
:可以移除 moor_flutter
依赖,取而代之的是添加 drfit
和 sqlite3_flutter_libs
依赖:
dependencies:
drift: ^1.0.1
sqlite3_flutter_libs:
sqflite: ^1.1.7 # 仍用来获取数据库的位置
dev_dependencies:
drift_dev: ^1.0.2
修改导入:
- 在创建
FlutterQueryExecutor
的文件中,用package:drift/native.dart
替换moor_flutter
的 导入。 - 所有其它导入
moor_flutter
的文件,只需要导入package:drift/drift.dart
。
替换执行器。代码如下:
FlutterQueryExecutor.inDatabaseFolder(path: 'db.sqlite')
现在代码可以写为如下的样子:
import 'package:sqflite/sqflite.dart' show getDatabasesPath;
import 'package:path/path.dart' as p;
LazyDatabase(() async {
final dbFolder = await getDatabasesPath();
final file = File(p.join(dbFolder, 'db.sqlite'));
return NativeDatabase(file);
})
注:如果没有为用户装载 moor_flutter
的一个版本,可以去掉 sqflite
的依赖。可以使用用在桌面端的 path_provider
。要注意到在Android上, FlutterQueryExecutor.inDatabaseFolder
可能会生成一个和 path_provider
不同的目录。如果已经装载了一个使用 moor_flutter
的版本,这可能会造成数据丢失。这种情况下,推荐的解决方案是使用 sqflite 的 getDatabasePath
。
用现有的数据库使用 drift
如果现有的 sqlite 数据库保存为了一个文件,使用 NativeDatabase(thatFile)
即可,不需要进一步的修改。
如果想要从 assets 或者其它来源加载数据库,可以使用 LazyDatabase
。这允许在打开数据库之前进行一些异步处理:
// (上文中)前面的内容
NativeDatabase(File('...'));
// (上文中)后面的内容
LazyDatabase(() async {
final file = File('...');
if (!await file.exists()) {
// 从 asset 、 网络或其它来源复制文件。
}
return NativeDatabase(file);
});
Android 上使用的编译选项
在 Android, iOS 和 macOs 上,依赖 sqlite3_flutter_libs
会包含一个自定义的构建,而不是系统的构建。选中的选项会通过移除 drift 不使用的特性来帮助减少二进制包的大小。重要的选项标记为粗体:
-
使用
-03
性能选项 -
**SQLITE_DQS=0:
这会使 sqlite 不接收双引号字符串(会把它们当作标识符)。这和 drift 还有编译后查询的行为相匹配。
-
**SQLITE_THREADSAFE=0:
因为大部分的 Flutter 应用只使用一个 isolate,所以线程安全是关闭的。注意仍然可以使用 isolate api 用于后台操作。正如数据库访问是发生在同样的同样的线程,这么做也没什么问题。
-
SQLITE_DEFAULT_MEMSTATUS=0:
sqlite3_status()
接口没有被 drift 暴露出来,所以这里没有必要使用这些。 -
SQLITE_OMIT_AUTHORIZATION
,SQLITE_OMIT_DECLTYPE
, SQLITE_OMIT_DEPRECATED,SQLITE_OMIT_GET_TABLE
,SQLITE_OMIT_LOAD_EXTENSION
,SQLITE_OMIT_PROGRESS_CALLBACK
,SQLITE_OMIT_SHARED_CACHE
,SQLITE_OMIT_TCL_VARIABLE
,SQLITE_OMIT_TRACE
:禁用 drift 不支持的特性。
-
SQLITE_USE_ALLOCA
:在堆栈上分配临时内存。
-
SQLITE_UNTESTABLE
:移除所有只在测试 sqlite3 用到的函数。
-
SQLITE_HAVE_ISNAN
:使用系统的
isnan
函数,代替使用 sqlite3 中装载的此函数。 -
SQLITE_ENABLE_FTS5
:将 fts5 引擎设为可用以进行全文检索。
-
SQLITE_ENABLE_JSON1
:将 json1 扩展设为可用以在 sql 查询中支持 json 。
更多关于 sqlite 编译选项的详细内容,参考 sqlite 的 文档 。
仅用于 drift 的函数
NativeDatabase
包含附加的 sql 函数,这些函数在标准的 sqlite 中不可用:
-
pow(base, exponent)
和power(base, exponent)
:这个函数接收两个数字参数,返回
base
的exponent
次方。 如果base
或exponent
不是数字或是 null ,该函数会返回null
。该函数和dart:math
中的pow
行为完全一致。 -
sqrt
、sin
、cos
、tan
、asin
、acos
、atan
:这些函数接收一个参数。如果参数是 null 或者不是数字,会返回 null。 否则,会返回
dart:math
中匹配的函数的结果。 -
regexp
:对 Dart 中的
RegExp
api 的包装,所以foo REGEXP bar
等同于RegExp(bar).hasMatch(foo)
。注意需要为每次regexp
sql 的调用创建一个新的RegExp
,对于大规模的查询会影响性能。 -
current_time_millis
:返回现在的 UNIX 时间戳,单位毫秒。 等同于 Dart 中的
DateTime.now().millisecondsSinceEpoch
。
注意 NaN
、 -infinity
或 +infinity
在 sql 中表现为 NULL
。
要在 Dart 中使用这些方法,需要导入 package:drift/extensions/native.dart
。 可以如下使用这些附加函数:
import 'package:drift/drift.dart';
// 这些方法隐藏在其它 import 后面,因为它们只在 NativeDatabase` 中可用。
import 'package:drift/extensions/native.dart';
class Coordinates extends Table {
RealColumn get x => real()();
RealColumn get y => real()();
}
// 现在可以如下使用:
Future<List<Coordinate>> findNearby(Coordinate center, int radius) {
return (select(coordinates)..where((other) {
// 查找 sqrt((center - x)² + (center.y - y)²) < radius 的坐标
// sqrt:开平方根 radius:半径
final distanceSquared = sqlPow(center.x - row.x, 2) + sqlPow(center.y - row.y, 2);
return sqlSqrt(distanceSquared).isLessThanValue(radius);
})).get();
}
所有其它的函数也都有可用的类似名称( sqlSin
、 sqlCos
、 sqlAtan
等). 它们都有 sql
前缀避免和 dart:math
冲突。
转载自:https://juejin.cn/post/7036025109819162637