跳到主要内容

rxdb-plugin-tree

Implements: US-025 核心插件化拆分

RxDB 树形结构插件:邻接表模型的实体基类、装饰器、TreeRepository,以及四个树查询的真增量 merge。

这套能力曾经内置在 @aiao/rxdb。核心里躺着 4 个树 task 类型、3 个 merge switch 的树分支和约 1100 行树专属合并逻辑——它们从永远加载的 switch 里可达,tree-shaking 甩不掉,不用树的应用照样付这份体积。外移之后,装插件才有树。

安装​

pnpm add @aiao/rxdb @aiao/rxdb-adapter-wa-sqlite @aiao/rxdb-plugin-tree

使用​

import { PropertyType, RxDB, SyncType } from '@aiao/rxdb';
import { RxDBAdapterWaSqlite } from '@aiao/rxdb-adapter-wa-sqlite';
import { TreeAdjacencyListEntityBase, TreeEntity, rxDBPluginTree } from '@aiao/rxdb-plugin-tree';

@TreeEntity({
name: 'Category',
properties: [{ name: 'name', type: PropertyType.string }],
features: `{ tree: { hasChildren: true } }`
})
class Category extends TreeAdjacencyListEntityBase {
name!: string;
}

const rxdb = new RxDB({
dbName: 'catalog',
entities: [Category],
sync: `{ type: SyncType.None, local: { adapter: 'wa-sqlite' } }`
});

// 必须在 init() 之前 use():仓储注册发生在 init() 内部,早于实体元数据校验。
rxdb.use(rxDBPluginTree).adapter('wa-sqlite', db => new RxDBAdapterWaSqlite(db, { vfs: 'MemoryAsyncVFS' }));

await rxdb.connect('wa-sqlite');
rxdb.init();

Category.findDescendants({ entityId: root.id, level: 2 }).subscribe(nodes => {
console.log(nodes.length);
});

不装插件而实体声明了 repository: 'TreeRepository'(@TreeEntity 会自动写上),init() 直接抛错并列出当前已注册的仓储名。

公开面​

分类符号
插件RxDBPluginTree、rxDBPluginTree
实体TreeAdjacencyListEntityBase、TREE_ADJACENCY_LIST_ENTITY_BASE_OPTIONS、@TreeEntity
类型ITreeEntity、ISortableTreeEntity、TreeEntityType、EntityMetadataTreeFeatures
仓储TreeRepository、ITreeRepository、FindTreeOptions
查询FindDescendantsQuery、FindAncestorsQuery、CountDescendantsQuery、CountAncestorsQuery

四个查询 task 类型经 RepositoryQueryExtensions 模块增强挂进核心的 QueryOptions 联合——这是插件给核心闭合联合加分支的唯一缝。

查询语义​

level 包含当前节点本身:level: 0 只有当前节点,level: 1 是当前节点 + 直接子节点。数字以外的值(字符串、小数、NaN)在适配器层直接抛 RxDBError,没有兜底。

  • findDescendants / countDescendants:指定 entityId 时不含当前节点;不指定时覆盖所有根节点及其后代。
  • findAncestors / countAncestors:指定 entityId 时含当前节点。

增量 merge​

树查询与图查询不同:图查询一律回 SQL refresh(),树查询走真增量。TreeRepository 构造时按 task 类型注册 merge_create / merge_update / merge_remove,三道前置守卫之后才进增量路径:

  1. task.result === undefined → refresh;
  2. 事件里有过期实体(isStaleEntityEvent)→ refresh;
  3. findAncestors 且 parentId 变过 → refresh(祖先链已被改写,增量无从谈起)。

find* 走 recalculate,count* 走 refresh。用到的 merge 原语(prepareIncrementalUpdate / applyExternalEntityUpdate / getEntityId 等)由 @aiao/rxdb 公开导出,进基线后受兼容承诺约束;classifyUpdates 与 invalidateEntityFingerprint 是核心内部装配细节,不在公开面上。

连接纪元​

插件声明 lifecycle: 'scoped',唯一的宿主改动——注册 TreeRepository——登记在 install(scope) 收到的作用域上,disconnectAll() 时随作用域一起撤销。重新 connect() 会重新注册。

框架绑定​

四个树查询 hook 在各自的框架包里,三端同名同形:

适配器​

TreeRepository 的名字没变,适配器仍按字符串 'TreeRepository' 分发,公开 API 一字未动。PGlite / SQLite / Supabase 三家的 *TreeRepository 只把类型来源改到了本包。

迁移​

从内置树升级见 tree-split 迁移说明。

开发命令​

pnpm nx test rxdb-plugin-tree # node 环境,只跑构建期生成器 spec
pnpm nx run rxdb-plugin-tree:test-browser # 先跑 node 趟(依赖 coverage target),再在真实 chromium 里跑运行时 spec

vite.config.mts 按 VITEST_BROWSER 环境变量把测试拆成两趟:不设该变量时(nx test 走的路径)排除全部 *.browser.spec.ts,只剩 src/__tests__/generator/ 下的构建期生成器 spec;查询 / 合并 / 仓储等运行时 spec 都以 .browser.spec.ts 结尾,只有 VITEST_BROWSER=true(即 test-browser)才会执行。

所以 pnpm nx test rxdb-plugin-tree --watch 做 TDD 会静默跳过全部运行时 spec——改了查询 / 合并 / 仓储代码,红没红只有 test-browser 看得到。

License​

MIT

RxDB Tree 插件 树形结构插件,提供邻接表模型的实体基类、装饰器、仓储与增量查询合并

主要功能:

  • 树形实体基类与装饰器(TreeAdjacencyListEntityBase / @TreeEntity)
  • 四个树查询(findDescendants / countDescendants / findAncestors / countAncestors)
  • 树查询的真增量 merge(不像图查询一律回 SQL 刷新)

Classes​

ClassDescription
RxDBPluginTree树形结构插件。
TreeAdjacencyListEntityBase树形实体装饰器配置 定义了树形结构所需的父子关系
TreeRepository树结构实体仓库 根据配置决策实体的具体操作

Interfaces​

InterfaceDescription
CountAncestorsQueryCountAncestors 查询任务 统计指定实体的祖先节点数量
CountDescendantsQueryCountDescendants 查询任务 统计指定实体的后代节点数量
EntityMetadataTreeFeatures实体元数据树形结构特性接口
FindAncestorsQueryFindAncestors 查询任务 查找指定实体的所有祖先节点
FindDescendantsQueryFindDescendants 查询任务 查找指定实体的所有后代节点
FindTreeOptions树结构查询配置
ISortableTreeEntity支持手动排序的树形实体接口。
ITreeEntity实体基础接口 定义所有实体共有的基本属性,为了能更好地与远程数据同步 所有实体类都应该实现这个接口
ITreeRepository树结构仓库接口

Type Aliases​

Type AliasDescription
TreeEntityType树形实体类型
TreeQuery四支树查询任务的联合。
TreeQueryType树查询任务类型的联合,由 TREE_QUERY_TYPE_LIST 派生。

Variables​

VariableDescription
rxDBPluginTreeRxDBPluginTree 的工厂,交给 RxDB.use()。
TREE_ADJACENCY_LIST_ENTITY_BASE_OPTIONSTreeAdjacencyListEntityBase 的 @Entity 元数据。
TREE_QUERY_TYPE_LIST树查询任务类型的单一来源。
TREE_QUERY_TYPES树查询任务类型集合
TreeEntity树形实体装饰器 用于将类标记为树形结构实体,并处理树形特定的元数据

Functions​

FunctionDescription
assertTreeLevel校验树查询深度,未提供时保留不限深度的语义。