阅读 882

Flutter持久化库drift - 其它引擎 - 原生drift(桌面支持)

原生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 依赖,取而代之的是添加 drfitsqlite3_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_AUTHORIZATIONSQLITE_OMIT_DECLTYPESQLITE_OMIT_DEPRECATEDSQLITE_OMIT_GET_TABLESQLITE_OMIT_LOAD_EXTENSIONSQLITE_OMIT_PROGRESS_CALLBACKSQLITE_OMIT_SHARED_CACHESQLITE_OMIT_TCL_VARIABLESQLITE_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)

    这个函数接收两个数字参数,返回 baseexponent 次方。 如果 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(); } 复制代码

所有其它的函数也都有可用的类似名称( sqlSinsqlCossqlAtan 等). 它们都有 sql 前缀避免和 dart:math 冲突。


作者:bettersun
链接:https://juejin.cn/post/7036025109819162637

 伪原创工具 SEO网站优化  https://www.237it.com/ 


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐