Skip to content

流查询(Stream queries)

摘要

在 drift 中观察 SQL 查询。


drift 的一个核心功能是,每个查询都可以转换成一个自动更新的流。无论查询是返回单行还是多行,或者查询是从单个表读取还是连接多个其他表,这都有效。

基础

在 drift 中,一个可运行的查询由 Selectable<T> 接口表示,该接口具有以下方法:

  • Future<List<T>> get():运行查询一次,返回所有行。
  • Future<T> getSingle():运行查询一次,断言它产生单行并返回。
  • Future<T?> getSingleOrNull():类似于 getSingle(),但允许为空结果集返回 null

这些方法中的每一个都有一个匹配的 watch() 方法,返回一个流:

  • Stream<List<T>> watch():观察查询,返回所有行。
  • Stream<T> watchSingle():观察查询,断言每次查询运行时都报告单行。
  • Stream<T?> watchSingleOrNull():类似于 watchSingle(),但将空结果集作为 null 返回。

所有用于构建查询的 drift API 都返回一个可以被观察的 Selectable

dart
Selectable<TodoItem> allItemsAfter(DateTime min) {
  return managers.todoItems.filter((c) => c.createdAt.isAfter(min));
}
  1. Drift 需要知道查询中涉及哪些表才能观察它们。在大多数情况下,这是自动推断的,但对于自定义查询,此信息是必需的。

当在 drift 文件中定义 SELECT 语句时,drift 会在数据库类中生成一个返回 Selectable 的方法。例如,

sql
allItemsAfter: SELECT * FROM todo_items WHERE created_at > :min;

将使 drift 生成此方法:

dart
Selectable<TodoItem> allItemsAfter({required DateTime min}) {
    // ...
}

无论使用哪种方法,都可以使用 allItemsAfter(value).watch() 创建一个流。由于 Stream 是 Dart 中的常见构建块,因此它们可以被大多数框架使用:

所有 drift 流在侦听它们后都会发出一个最新的结果(因此即使表从未更改,你也会收到一个快照,并且不必组合 get()watch())。

高级用法

除了侦听查询之外,你还可以直接侦听表上的更新事件:

请注意,整个查询流功能是在 drift 中实现的,因此流更新是一种可能比必要时更频繁触发的启发式方法。也可以手动将表标记为已更新:

注意事项

虽然流对于自动获取你正在运行的任何查询的更新很有用,但了解其功能和局限性很重要。流查询在 drift 中是作为一种启发式方法实现的:对于每个活动的流,drift 会跟踪它正在侦听的表(可从查询构建器获得的信息)。每当通过 drift API 进行插入、更新或删除时,关联的查询都会被重新调度并再次运行。

这意味着:

  1. 数据库的其他用法,例如本机 SQLite 客户端,不会触发流查询更新。你可以手动注入更新作为一种变通方法。
  2. 流查询通常比它们必须的更新更频繁,因为我们无法仅针对特定行的更新进行过滤。这通常不是问题,但需要注意。流查询通常应返回相对较少的行,并且执行起来在计算上不要太昂贵。