@aiao/rxdb-plugin-tree 0.0.0-stage → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -2
- package/dist/constants-DRludxr-.js +41 -0
- package/dist/constants.d.ts +49 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/entity/tree-entity-base.d.ts +44 -0
- package/dist/entity/tree-entity-base.d.ts.map +1 -0
- package/dist/entity/tree-entity.decorator.d.ts +7 -0
- package/dist/entity/tree-entity.decorator.d.ts.map +1 -0
- package/dist/entity/tree-entity.interface.d.ts +36 -0
- package/dist/entity/tree-entity.interface.d.ts.map +1 -0
- package/dist/entity/tree-metadata.interface.d.ts +34 -0
- package/dist/entity/tree-metadata.interface.d.ts.map +1 -0
- package/dist/generator/TreeRepositoryGenerator.d.ts +37 -0
- package/dist/generator/TreeRepositoryGenerator.d.ts.map +1 -0
- package/dist/generator/index.d.ts +17 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator.js +87 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +564 -0
- package/dist/plugin.d.ts +84 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/query/merge-update-tree.d.ts +80 -0
- package/dist/query/merge-update-tree.d.ts.map +1 -0
- package/dist/query/merge_create.d.ts +9 -0
- package/dist/query/merge_create.d.ts.map +1 -0
- package/dist/query/merge_remove.d.ts +9 -0
- package/dist/query/merge_remove.d.ts.map +1 -0
- package/dist/query/merge_update.d.ts +9 -0
- package/dist/query/merge_update.d.ts.map +1 -0
- package/dist/query/query-tree.utils.d.ts +87 -0
- package/dist/query/query-tree.utils.d.ts.map +1 -0
- package/dist/query/tree-helper.d.ts +143 -0
- package/dist/query/tree-helper.d.ts.map +1 -0
- package/dist/query/tree-query.interface.d.ts +53 -0
- package/dist/query/tree-query.interface.d.ts.map +1 -0
- package/dist/repository/TreeRepository.d.ts +56 -0
- package/dist/repository/TreeRepository.d.ts.map +1 -0
- package/dist/repository/tree-level.utils.d.ts +9 -0
- package/dist/repository/tree-level.utils.d.ts.map +1 -0
- package/dist/repository/tree-repository.interface.d.ts +70 -0
- package/dist/repository/tree-repository.interface.d.ts.map +1 -0
- package/package.json +63 -3
- package/src/constants.ts +97 -0
- package/src/entity/tree-entity-base.ts +100 -0
- package/src/entity/tree-entity.decorator.ts +37 -0
- package/src/entity/tree-entity.interface.ts +43 -0
- package/src/entity/tree-metadata.interface.ts +35 -0
- package/src/generator/TreeRepositoryGenerator.ts +153 -0
- package/src/generator/index.ts +17 -0
- package/src/index.ts +23 -0
- package/src/plugin.ts +111 -0
- package/src/query/merge-update-tree.ts +558 -0
- package/src/query/merge_create.ts +125 -0
- package/src/query/merge_remove.ts +164 -0
- package/src/query/merge_update.ts +132 -0
- package/src/query/query-tree.utils.ts +204 -0
- package/src/query/tree-helper.ts +342 -0
- package/src/query/tree-query.interface.ts +66 -0
- package/src/repository/TreeRepository.ts +133 -0
- package/src/repository/tree-level.utils.ts +14 -0
- package/src/repository/tree-repository.interface.ts +76 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { EntityType, QueryTask, RxDBEntityLocalUpdatedEventData, UpdateClassification, UpdateDataCache } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 处理 findDescendants 查询的增量更新
|
|
4
|
+
*
|
|
5
|
+
* UPDATE 场景下的复杂性:
|
|
6
|
+
* 1. 实体的 parentId 可能变化,导致树形结构重组
|
|
7
|
+
* 2. 实体可能从不是后代变成后代,或从后代变成非后代
|
|
8
|
+
* 3. 实体仍然是后代,但字段值变化(如名称、描述等)
|
|
9
|
+
* 4. 需要考虑 level 限制(只查询特定层级的后代)
|
|
10
|
+
*
|
|
11
|
+
* 更新策略:
|
|
12
|
+
* - 移除: 不再匹配 where 条件 或 不再是后代 或 超出 level 范围
|
|
13
|
+
* - 更新: 仍在结果集中的实体,更新其字段值
|
|
14
|
+
* - 添加: 新匹配 where 条件 且 成为后代 且 在 level 范围内
|
|
15
|
+
*
|
|
16
|
+
* @param task 查询任务
|
|
17
|
+
* @param data 更新的实体数据列表
|
|
18
|
+
* @param classification 更新分类结果
|
|
19
|
+
* @param cache 更新数据缓存
|
|
20
|
+
*/
|
|
21
|
+
export declare const handleFindDescendantsUpdate: <T extends EntityType>(task: QueryTask<T>, data: RxDBEntityLocalUpdatedEventData<T>[], classification: UpdateClassification, cache: UpdateDataCache<T>) => void;
|
|
22
|
+
/**
|
|
23
|
+
* 处理 findAncestors 查询的增量更新
|
|
24
|
+
*
|
|
25
|
+
* UPDATE 场景下的复杂性:
|
|
26
|
+
* 1. 目标实体的祖先链路可能因为其他实体的 parentId 变化而改变
|
|
27
|
+
* 2. 实体可能从不是祖先变成祖先,或从祖先变成非祖先
|
|
28
|
+
* 3. 实体仍然是祖先,但字段值变化
|
|
29
|
+
* 4. 目标实体本身也是结果的一部分(level=0)
|
|
30
|
+
*
|
|
31
|
+
* 特殊情况:
|
|
32
|
+
* - 如果目标实体的 parentId 变化,整个祖先链都会改变,需要完全刷新
|
|
33
|
+
*
|
|
34
|
+
* @param task 查询任务
|
|
35
|
+
* @param data 更新的实体数据列表
|
|
36
|
+
* @param classification 更新分类结果
|
|
37
|
+
* @param cache 更新数据缓存
|
|
38
|
+
*/
|
|
39
|
+
export declare const handleFindAncestorsUpdate: <T extends EntityType>(task: QueryTask<T>, data: RxDBEntityLocalUpdatedEventData<T>[], classification: UpdateClassification, cache: UpdateDataCache<T>) => void;
|
|
40
|
+
/**
|
|
41
|
+
* 处理 countDescendants 查询的增量更新
|
|
42
|
+
*
|
|
43
|
+
* 计数查询的特点:
|
|
44
|
+
* - 只需要返回数量,不需要返回具体实体
|
|
45
|
+
* - 没有实体级追踪,看不到不在本批事件里的子孙
|
|
46
|
+
*
|
|
47
|
+
* UPDATE 场景下的计数变化:
|
|
48
|
+
* 1. scope 内(或无法判定)的非基准节点 parentId 变化 → 子树整体进出 / 平移深度,触发 SQL 刷新
|
|
49
|
+
* 2. scope 内(或无法判定)的非基准节点 where 命中翻转 → 递归遍历在它这里被截断或放开,
|
|
50
|
+
* 名下子孙随之进出,触发 SQL 刷新
|
|
51
|
+
* 3. 只改了其他字段、或变化发生在 scope 之外 → 计数不变,不通知
|
|
52
|
+
*
|
|
53
|
+
* @param task 查询任务
|
|
54
|
+
* @param data 更新的实体数据列表
|
|
55
|
+
* @param classification 更新分类结果
|
|
56
|
+
* @param cache 更新数据缓存
|
|
57
|
+
*/
|
|
58
|
+
export declare const handleCountDescendantsUpdate: <T extends EntityType>(task: QueryTask<T>, data: RxDBEntityLocalUpdatedEventData<T>[], classification: UpdateClassification, cache: UpdateDataCache<T>) => void;
|
|
59
|
+
/**
|
|
60
|
+
* 处理 countAncestors 查询的增量更新
|
|
61
|
+
*
|
|
62
|
+
* 计数查询的特点:
|
|
63
|
+
* - 只需要返回数量,不需要返回具体实体
|
|
64
|
+
* - 没有实体级追踪,看不到不在本批事件里的上方祖先
|
|
65
|
+
* - 如果无法确定关系(父实体链中断)或目标实体的 parentId 变化,则触发 SQL 刷新
|
|
66
|
+
*
|
|
67
|
+
* UPDATE 场景下的计数变化:
|
|
68
|
+
* 1. 目标实体的 parentId 变化 → 整个祖先链改变,必须触发刷新
|
|
69
|
+
* 2. 链上(或无法判定)的祖先 parentId 变化 → 它上方整段链被换掉,触发刷新
|
|
70
|
+
* 3. 链上(或无法判定)的祖先 where 命中翻转 → 递归遍历在它这里被截断或放开,
|
|
71
|
+
* 上方祖先随之进出,触发刷新
|
|
72
|
+
* 4. 只改了其他字段、或变化发生在链外 → 计数不变,不通知
|
|
73
|
+
*
|
|
74
|
+
* @param task 查询任务
|
|
75
|
+
* @param data 更新的实体数据列表
|
|
76
|
+
* @param classification 更新分类结果
|
|
77
|
+
* @param cache 更新数据缓存
|
|
78
|
+
*/
|
|
79
|
+
export declare const handleCountAncestorsUpdate: <T extends EntityType>(task: QueryTask<T>, data: RxDBEntityLocalUpdatedEventData<T>[], classification: UpdateClassification, cache: UpdateDataCache<T>) => void;
|
|
80
|
+
//# sourceMappingURL=merge-update-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-update-tree.d.ts","sourceRoot":"","sources":["../../src/query/merge-update-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EAEV,SAAS,EAET,+BAA+B,EAC/B,oBAAoB,EACpB,eAAe,EAChB,MAAM,YAAY,CAAC;AAgBpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,2BAA2B,GAAI,CAAC,SAAS,UAAU,EAC9D,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,MAAM,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAC1C,gBAAgB,oBAAoB,EACpC,OAAO,eAAe,CAAC,CAAC,CAAC,SA6M1B,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,UAAU,EAC5D,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,MAAM,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAC1C,gBAAgB,oBAAoB,EACpC,OAAO,eAAe,CAAC,CAAC,CAAC,SAoG1B,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,SAAS,UAAU,EAC/D,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,MAAM,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAC1C,gBAAgB,oBAAoB,EACpC,OAAO,eAAe,CAAC,CAAC,CAAC,SA2D1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,0BAA0B,GAAI,CAAC,SAAS,UAAU,EAC7D,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,MAAM,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAC1C,gBAAgB,oBAAoB,EACpC,OAAO,eAAe,CAAC,CAAC,CAAC,SAwE1B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EntityType, QueryTask, RxDBEntityLocalCreatedEventData } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 处理树查询 CREATE 事件的缓存合并
|
|
4
|
+
*
|
|
5
|
+
* @param task 查询任务
|
|
6
|
+
* @param entities 创建的实体事件数据
|
|
7
|
+
*/
|
|
8
|
+
export declare const merge_create: <T extends EntityType>(task: QueryTask<T>, entities: RxDBEntityLocalCreatedEventData<T>[]) => void;
|
|
9
|
+
//# sourceMappingURL=merge_create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge_create.d.ts","sourceRoot":"","sources":["../../src/query/merge_create.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,UAAU,EAIV,SAAS,EAET,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAwDpB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,UAAU,EAC/C,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,UAAU,+BAA+B,CAAC,CAAC,CAAC,EAAE,SA6C/C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EntityType, QueryTask, RxDBEntityLocalRemovedEventData } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 处理树查询 REMOVE 事件的缓存合并
|
|
4
|
+
*
|
|
5
|
+
* @param task 查询任务
|
|
6
|
+
* @param entities 删除的实体事件数据
|
|
7
|
+
*/
|
|
8
|
+
export declare const merge_remove: <T extends EntityType>(task: QueryTask<T>, entities: RxDBEntityLocalRemovedEventData<T>[]) => void;
|
|
9
|
+
//# sourceMappingURL=merge_remove.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge_remove.d.ts","sourceRoot":"","sources":["../../src/query/merge_remove.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,UAAU,EAGV,SAAS,EAGT,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAkGpB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,UAAU,EAC/C,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,UAAU,+BAA+B,CAAC,CAAC,CAAC,EAAE,SA2C/C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EntityType, QueryTask, RxDBEntityLocalUpdatedEventData } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 处理树查询 UPDATE 事件的缓存合并
|
|
4
|
+
*
|
|
5
|
+
* @param task 查询任务
|
|
6
|
+
* @param entities 更新的实体事件数据
|
|
7
|
+
*/
|
|
8
|
+
export declare const merge_update: <T extends EntityType>(task: QueryTask<T>, entities: RxDBEntityLocalUpdatedEventData<T>[]) => void;
|
|
9
|
+
//# sourceMappingURL=merge_update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge_update.d.ts","sourceRoot":"","sources":["../../src/query/merge_update.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,UAAU,EAGV,SAAS,EAET,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAmCpB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,UAAU,EAC/C,MAAM,SAAS,CAAC,CAAC,CAAC,EAClB,UAAU,+BAA+B,CAAC,CAAC,CAAC,EAAE,SA0E/C,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 树形遍历配置
|
|
3
|
+
*/
|
|
4
|
+
interface TreeTraversalOptions {
|
|
5
|
+
maxLevel?: number;
|
|
6
|
+
maxDepth?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 获取实体的父级 ID
|
|
10
|
+
* 处理 parentId 可能是对象或字符串的情况
|
|
11
|
+
*/
|
|
12
|
+
export declare const get_tree_parent_id: <ID = string>(entity: object | null | undefined) => ID | null;
|
|
13
|
+
/**
|
|
14
|
+
* 判断一条更新事件是否**真的**改动了 `parentId`
|
|
15
|
+
*
|
|
16
|
+
* @param event 带 `patch` / `inversePatch` 的更新事件
|
|
17
|
+
* @returns `true` 表示父节点发生了位移
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* 两条都不能省:
|
|
21
|
+
*
|
|
22
|
+
* - **key 存在 ≠ 值变了**:只改 `isActive` 时 patch 仍可能带上未变的 `parentId`,
|
|
23
|
+
* 单看 `'parentId' in patch` 会把纯字段更新误判成"移动",触发不必要的 refresh。
|
|
24
|
+
* - **两侧都要归一**:在树语义里「缺失」「`null`」「`undefined`」都是「挂在根上」,
|
|
25
|
+
* 所以两侧统一走 {@link get_tree_parent_id}。裸 `Reflect.get` 比较会把
|
|
26
|
+
* `undefined → null` 这种无变化算成移动。
|
|
27
|
+
*
|
|
28
|
+
* 这是全插件判断"父节点变了没有"的**唯一**实现:此前 `merge_update.ts` 与
|
|
29
|
+
* `merge-update-tree.ts` 各有一套拼写,null/undefined 语义在两套之间分叉。
|
|
30
|
+
*/
|
|
31
|
+
export declare const hasTreeParentChanged: (event: {
|
|
32
|
+
patch: object;
|
|
33
|
+
inversePatch: object;
|
|
34
|
+
}) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* 向上遍历父级链路
|
|
37
|
+
*
|
|
38
|
+
* @param entity 起始实体
|
|
39
|
+
* @param entitiesMap 实体 ID 映射表
|
|
40
|
+
* @param options 遍历配置
|
|
41
|
+
* @yields 每一层的父级实体和层级
|
|
42
|
+
*/
|
|
43
|
+
export declare function traverseAncestors<T extends object, ID>(entity: T, entitiesMap: Map<ID, T>, options?: TreeTraversalOptions): Generator<{
|
|
44
|
+
entity: T;
|
|
45
|
+
level: number;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* 检查实体是否是目标实体的后代
|
|
49
|
+
*
|
|
50
|
+
* @param entity 要检查的实体
|
|
51
|
+
* @param targetId 目标实体 ID (为 null 或 undefined 时表示查找根节点)
|
|
52
|
+
* @param entitiesMap 实体 ID 映射表
|
|
53
|
+
* @param maxLevel 最大层级 (undefined 表示无限制)
|
|
54
|
+
* @returns 如果是后代则返回 true
|
|
55
|
+
*/
|
|
56
|
+
export declare function isDescendantOf<T extends object, ID>(entity: T, targetId: ID | null | undefined, entitiesMap: Map<ID, T>, maxLevel?: number): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 检查实体是否是目标实体的祖先
|
|
59
|
+
*
|
|
60
|
+
* @param candidateEntity 候选祖先实体
|
|
61
|
+
* @param targetId 目标实体 ID (为 null 或 undefined 时直接返回 false,无 isDescendantOf 那种"查找根节点"语义)
|
|
62
|
+
* @param entitiesMap 实体 ID 映射表
|
|
63
|
+
* @param maxLevel 最大层级
|
|
64
|
+
* @returns 如果是祖先则返回 true
|
|
65
|
+
*/
|
|
66
|
+
export declare function isAncestorOf<T extends object, ID>(candidateEntity: T, targetId: ID | null | undefined, entitiesMap: Map<ID, T>, maxLevel?: number): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* 顺序串联多个可迭代源,不物化中间数组
|
|
69
|
+
*
|
|
70
|
+
* @param sources 按顺序遍历的可迭代源
|
|
71
|
+
* @yields 各源中的元素,顺序与传入顺序一致
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* 专为 {@link buildEntityMap} 的「旧结果 `Set` + 本批事件数组」场景而设:
|
|
75
|
+
* `Array.from(set)` 再展开拼接会把旧结果集整体物化两遍,只为建一张查找表。
|
|
76
|
+
*/
|
|
77
|
+
export declare function concatIterables<T>(...sources: Iterable<T>[]): Generator<T>;
|
|
78
|
+
/**
|
|
79
|
+
* 构建实体 ID 映射表(优化查找性能)
|
|
80
|
+
*
|
|
81
|
+
* @param entities 实体来源;接受任意可迭代对象(数组、`Set`、{@link concatIterables} 的产物)
|
|
82
|
+
* @param getIdFn 获取实体 ID 的函数
|
|
83
|
+
* @returns 实体 ID 到实体的映射表
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildEntityMap<T, ID>(entities: Iterable<T>, getIdFn: (entity: T) => ID | null | undefined): Map<ID, T>;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=query-tree.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-tree.utils.d.ts","sourceRoot":"","sources":["../../src/query/query-tree.utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,EAAE,GAAG,MAAM,EAAE,QAAQ,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,EAAE,GAAG,IAGxF,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,KAAG,OACmB,CAAC;AAE1G;;;;;;;GAOG;AACH,wBAAiB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EACvB,OAAO,GAAE,oBAAyB,GACjC,SAAS,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,EACjD,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,EAAE,GAAG,IAAI,GAAG,SAAS,EAC/B,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAmDT;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,EAC/C,eAAe,EAAE,CAAC,EAClB,QAAQ,EAAE,EAAE,GAAG,IAAI,GAAG,SAAS,EAC/B,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAWT;AAED;;;;;;;;;GASG;AACH,wBAAiB,eAAe,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAI3E;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAClC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,GAAG,SAAS,GAC5C,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAOZ"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { EntityType, RxDBEntityId, UpdateDataCache } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 目标实体的祖先 id 集合,{@link TreeHelper.collectAncestorIdsForCount} 的产物
|
|
4
|
+
*/
|
|
5
|
+
export interface TreeAncestorIdSet {
|
|
6
|
+
/** 自目标向上、`maxLevel` 以内解析到的全部祖先 id */
|
|
7
|
+
ids: ReadonlySet<RxDBEntityId>;
|
|
8
|
+
/**
|
|
9
|
+
* 父链是否走到了尽头。
|
|
10
|
+
*
|
|
11
|
+
* `false` 表示中途有一环取不到实体 —— 集合**之外**的候选无从判定,只能回 SQL;
|
|
12
|
+
* 集合**之内**的候选仍是确定的 `true`(走链在断点之前就已经经过它)。
|
|
13
|
+
*/
|
|
14
|
+
complete: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 用预先收集的祖先集合判定单个候选实体(`count` 口径)
|
|
18
|
+
*
|
|
19
|
+
* @param ancestors {@link TreeHelper.collectAncestorIdsForCount} 的结果
|
|
20
|
+
* @param candidateEntity 候选祖先实体
|
|
21
|
+
* @returns true=是祖先, false=不是祖先, undefined=无法确定(调用方回 SQL 重算)
|
|
22
|
+
*/
|
|
23
|
+
export declare const resolveAncestorForCount: <T extends EntityType>(ancestors: TreeAncestorIdSet, candidateEntity: InstanceType<T> | null | undefined) => boolean | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* 树形结构辅助函数管理器
|
|
26
|
+
*
|
|
27
|
+
* 提供树形查询所需的核心功能:
|
|
28
|
+
* - 解析父实体引用
|
|
29
|
+
* - 判断后代/祖先关系(普通 + count 专用变体)
|
|
30
|
+
* - 支持层级限制和循环检测
|
|
31
|
+
*
|
|
32
|
+
* @template T 实体类型
|
|
33
|
+
*
|
|
34
|
+
* @internal 由 merge-update-tree.ts 的 handle*Update 函数使用
|
|
35
|
+
*/
|
|
36
|
+
export declare class TreeHelper<T extends EntityType> {
|
|
37
|
+
private cache;
|
|
38
|
+
private oldResultMap;
|
|
39
|
+
constructor(cache: UpdateDataCache<T>, oldResultMap: Map<RxDBEntityId, InstanceType<T>>);
|
|
40
|
+
/**
|
|
41
|
+
* 解析父实体
|
|
42
|
+
*
|
|
43
|
+
* 从更新缓存或旧结果集中获取父实体,避免重复查询数据库
|
|
44
|
+
*
|
|
45
|
+
* @param id 父实体ID
|
|
46
|
+
* @returns 父实体实例,如果不存在则返回 undefined
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* **更新缓存优先,旧结果集兜后**。`oldResultMap` 是本批事件**之前**的快照;
|
|
50
|
+
* 同一批里父节点自己也被移动时(`Y.parentId A→null` 与 `M.parentId Z→Y` 同批到达),
|
|
51
|
+
* 先读旧结果集会顺着过期的 `parentId` 往上走,把已经移出子树的节点判成仍在子树内。
|
|
52
|
+
* `cache.getSerializedUpdate` 给的是本批应用后的状态,与 `merge-update-tree.ts`
|
|
53
|
+
* 孤儿复查里的 `resolveParent` 同口径。
|
|
54
|
+
*/
|
|
55
|
+
resolveParentEntity(id: RxDBEntityId): InstanceType<T> | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* 检查实体是否是目标实体的后代
|
|
58
|
+
*
|
|
59
|
+
* 从实体向上遍历父级链,检查是否能到达目标实体
|
|
60
|
+
* 包含循环检测,防止无限递归
|
|
61
|
+
*
|
|
62
|
+
* @param entity 要检查的实体
|
|
63
|
+
* @param targetEntityId 目标实体ID (潜在的祖先),为 null 或 undefined 时表示查找所有树(所有节点都有效)
|
|
64
|
+
* @returns 包含是否为后代和层级深度的对象
|
|
65
|
+
*/
|
|
66
|
+
isEntityDescendant(entity: InstanceType<T>, targetEntityId: RxDBEntityId | null | undefined): {
|
|
67
|
+
isDescendant: boolean;
|
|
68
|
+
level: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* 检查实体是否是目标的祖先
|
|
72
|
+
*
|
|
73
|
+
* 从目标实体向上遍历父级链,检查是否能到达候选实体
|
|
74
|
+
*
|
|
75
|
+
* @param targetEntity 目标实体 (要查找其祖先)
|
|
76
|
+
* @param candidateEntity 候选祖先实体
|
|
77
|
+
* @param maxLevel 层级上限,口径同 `FindTreeOptions.level`:目标自身为 0、父节点为 1。
|
|
78
|
+
* `undefined` 表示不限层级。
|
|
79
|
+
* @returns true 表示候选实体是目标的祖先
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* `maxLevel` 不是可选的性能优化,而是正确性要求:调用方给了 `level` 时,
|
|
83
|
+
* 适配器的递归成员带 `c.__level < level`,`__level` 超出上限的祖先 SQL 根本不会返回;
|
|
84
|
+
* 这里不跟着截断就会把深处的祖先并进增量结果,与全量刷新分叉。
|
|
85
|
+
* 调用方没给 `level`(不限深度)时传 `undefined`,两边都走到根。
|
|
86
|
+
*/
|
|
87
|
+
isEntityAncestor(targetEntity: InstanceType<T>, candidateEntity: InstanceType<T>, maxLevel?: number): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* 检查实体是否是目标的后代 (用于 count 查询)
|
|
90
|
+
*
|
|
91
|
+
* 与 isEntityDescendant 类似,但返回 undefined 表示无法确定
|
|
92
|
+
* 当父实体链中有实体不在更新数据中时,无法继续追踪,返回 undefined
|
|
93
|
+
* 此时需要触发 SQL 刷新以获取准确结果
|
|
94
|
+
*
|
|
95
|
+
* @param entity 要检查的实体
|
|
96
|
+
* @param targetEntityId 目标实体ID,为 null 或 undefined 时表示查找所有树(所有节点都有效)
|
|
97
|
+
* @returns true=是后代, false=不是后代, undefined=无法确定
|
|
98
|
+
*/
|
|
99
|
+
isEntityDescendantForCount(entity: InstanceType<T> | null | undefined, targetEntityId: RxDBEntityId | null | undefined): boolean | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* 计算实体相对目标实体的后代深度 (用于 count 查询)
|
|
102
|
+
*
|
|
103
|
+
* @param entity 要检查的实体
|
|
104
|
+
* @param targetEntityId 目标实体ID;为 null 或 undefined 时表示查询所有树,深度从根节点算起
|
|
105
|
+
* @returns `{ isDescendant, depth }`;无法确定时返回 `undefined`
|
|
106
|
+
*
|
|
107
|
+
* @remarks
|
|
108
|
+
* {@link isEntityDescendantForCount} 只回答「是不是后代」,答不出「隔了几层」,
|
|
109
|
+
* 于是 `countDescendants` 的 `level` 限制在增量合并里整个缺席:`{ entityId, level: 0 }`
|
|
110
|
+
* (只数目标节点自己,后代一个都不算)会被一个直接子节点的 where 翻转加成 1。
|
|
111
|
+
*
|
|
112
|
+
* 深度口径与 `FindTreeOptions.level` 一致:给了 `entityId` 时目标节点自身深度为 0、
|
|
113
|
+
* 直接子节点为 1;没给 `entityId` 时根节点深度为 0。调用方用 `depth <= level` 过滤。
|
|
114
|
+
*
|
|
115
|
+
* 与 {@link isEntityDescendantForCount} 一样,父链上任何一环取不到就返回 `undefined`
|
|
116
|
+
* 让调用方回 SQL 重算 —— 深度算不准时不能猜。
|
|
117
|
+
*/
|
|
118
|
+
descendantDepthForCount(entity: InstanceType<T> | null | undefined, targetEntityId: RxDBEntityId | null | undefined): {
|
|
119
|
+
isDescendant: boolean;
|
|
120
|
+
depth: number;
|
|
121
|
+
} | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* 收集目标实体的祖先 id 集合 (用于 count 查询)
|
|
124
|
+
*
|
|
125
|
+
* @param targetEntity 目标实体(要查找其祖先)
|
|
126
|
+
* @param maxLevel 层级上限,口径同 {@link isEntityAncestor};`undefined` 表示不限层级。
|
|
127
|
+
* @returns 祖先 id 集合 + 「父链是否完整」标记,交给 {@link resolveAncestorForCount} 判定候选
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* `countAncestors` 的目标祖先链在一批事件内是**不变**的(目标自己改父会被调用方
|
|
131
|
+
* 提前 `refresh()` 拦掉),而这条链只取决于起点的 `parentId` 加逐跳的
|
|
132
|
+
* `cache.getSerializedUpdate` —— 对批内每个候选各走一遍是 O(N×depth) 的逐字节重复。
|
|
133
|
+
* 走一次建 Set,候选判定降到 O(1)。
|
|
134
|
+
*
|
|
135
|
+
* 与 {@link isEntityAncestor} 同因,`maxLevel` 不是性能优化而是正确性要求:
|
|
136
|
+
* `countAncestors` 数的是 `__level <= level` 的祖先,不带上限会把超深祖先也计进去。
|
|
137
|
+
* 超出 `maxLevel` 时停止收集并标记 `complete: true` —— 更上方的祖先 SQL 不会返回,
|
|
138
|
+
* 「不是祖先」是能确定的答案,不必为此回一次 SQL。只有父链中途取不到实体
|
|
139
|
+
* 才标记 `complete: false`。环由 `ids` 自身兜住,无需额外的跳数上限。
|
|
140
|
+
*/
|
|
141
|
+
collectAncestorIdsForCount(targetEntity: InstanceType<T>, maxLevel?: number): TreeAncestorIdSet;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=tree-helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-helper.d.ts","sourceRoot":"","sources":["../../src/query/tree-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAe,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGpF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,GAAG,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,UAAU,EAC1D,WAAW,iBAAiB,EAC5B,iBAAiB,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,KAClD,OAAO,GAAG,SASZ,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,UAAU;IAExC,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,YAAY;gBADZ,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EACzB,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAG1D;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAWlE;;;;;;;;;OASG;IACH,kBAAkB,CAChB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,cAAc,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAC9C;QAAE,YAAY,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IA+C3C;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAwC7G;;;;;;;;;;OAUG;IACH,0BAA0B,CACxB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAC1C,cAAc,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAC9C,OAAO,GAAG,SAAS;IAkCtB;;;;;;;;;;;;;;;;;OAiBG;IACH,uBAAuB,CACrB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAC1C,cAAc,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAC9C;QAAE,YAAY,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IA6BvD;;;;;;;;;;;;;;;;;;OAkBG;IACH,0BAA0B,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB;CAwBhG"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EntityType } from '@aiao/rxdb';
|
|
2
|
+
import { TreeQueryType } from '../constants.js';
|
|
3
|
+
import { FindTreeOptions } from '../repository/tree-repository.interface.js';
|
|
4
|
+
/**
|
|
5
|
+
* FindDescendants 查询任务
|
|
6
|
+
* 查找指定实体的所有后代节点
|
|
7
|
+
*/
|
|
8
|
+
export interface FindDescendantsQuery<T extends EntityType> {
|
|
9
|
+
type: Extract<TreeQueryType, 'findDescendants'>;
|
|
10
|
+
options: FindTreeOptions<T>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* FindAncestors 查询任务
|
|
14
|
+
* 查找指定实体的所有祖先节点
|
|
15
|
+
*/
|
|
16
|
+
export interface FindAncestorsQuery<T extends EntityType> {
|
|
17
|
+
type: Extract<TreeQueryType, 'findAncestors'>;
|
|
18
|
+
options: FindTreeOptions<T>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CountDescendants 查询任务
|
|
22
|
+
* 统计指定实体的后代节点数量
|
|
23
|
+
*/
|
|
24
|
+
export interface CountDescendantsQuery<T extends EntityType> {
|
|
25
|
+
type: Extract<TreeQueryType, 'countDescendants'>;
|
|
26
|
+
options: FindTreeOptions<T>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* CountAncestors 查询任务
|
|
30
|
+
* 统计指定实体的祖先节点数量
|
|
31
|
+
*/
|
|
32
|
+
export interface CountAncestorsQuery<T extends EntityType> {
|
|
33
|
+
type: Extract<TreeQueryType, 'countAncestors'>;
|
|
34
|
+
options: FindTreeOptions<T>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 四支树查询任务的联合。
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* 与 {@link TreeQueryType} 的双向一致性由
|
|
41
|
+
* `__tests__/contracts/tree-query-type-parity.spec.ts` 钉死:这里加一支而
|
|
42
|
+
* {@link TREE_QUERY_TYPE_LIST} 没加(或反过来),那条断言编译失败。
|
|
43
|
+
*/
|
|
44
|
+
export type TreeQuery<T extends EntityType> = FindDescendantsQuery<T> | FindAncestorsQuery<T> | CountDescendantsQuery<T> | CountAncestorsQuery<T>;
|
|
45
|
+
declare module '@aiao/rxdb' {
|
|
46
|
+
interface RepositoryQueryExtensions<T extends EntityType> {
|
|
47
|
+
treeFindDescendants: FindDescendantsQuery<T>;
|
|
48
|
+
treeFindAncestors: FindAncestorsQuery<T>;
|
|
49
|
+
treeCountDescendants: CountDescendantsQuery<T>;
|
|
50
|
+
treeCountAncestors: CountAncestorsQuery<T>;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=tree-query.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-query.interface.d.ts","sourceRoot":"","sources":["../../src/query/tree-query.interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAE7E;;;GAGG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,UAAU;IACxD,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IAChD,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,UAAU;IACtD,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IAC9C,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,UAAU;IACzD,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;IACjD,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,UAAU;IACvD,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAC/C,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,UAAU,IACxC,oBAAoB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAEtG,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,yBAAyB,CAAC,CAAC,SAAS,UAAU;QACtD,mBAAmB,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;QAC7C,iBAAiB,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACzC,oBAAoB,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,kBAAkB,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;KAC5C;CACF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { EntityType, Repository, RxDB } from '@aiao/rxdb';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { ITreeEntity } from '../entity/tree-entity.interface.js';
|
|
4
|
+
import { FindTreeOptions, ITreeRepository } from './tree-repository.interface.js';
|
|
5
|
+
/**
|
|
6
|
+
* 树结构实体仓库
|
|
7
|
+
* 根据配置决策实体的具体操作
|
|
8
|
+
*
|
|
9
|
+
* @template T - 必须是实现 ITreeEntity 接口的实体类型(通常继承 TreeAdjacencyListEntityBase)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // ✅ 正确:继承 TreeAdjacencyListEntityBase
|
|
14
|
+
* // 不必写 repository:`repository: 'TreeRepository'` 与 `features.tree` 都由基类声明,
|
|
15
|
+
* // 沿原型链继承下来(要覆盖就在自己的 @Entity 里显式声明)
|
|
16
|
+
* @Entity({ name: 'Category' })
|
|
17
|
+
* class Category extends TreeAdjacencyListEntityBase {
|
|
18
|
+
* name!: string;
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* // 可以使用树查询方法
|
|
22
|
+
* Category.findDescendants({ entityId: 'root-id' });
|
|
23
|
+
* Category.findAncestors({ entityId: 'leaf-id' });
|
|
24
|
+
*
|
|
25
|
+
* // ❌ 错误:只继承 EntityBase,没有实现 ITreeEntity
|
|
26
|
+
* @Entity({ name: 'User' })
|
|
27
|
+
* class User extends EntityBase {
|
|
28
|
+
* name!: string;
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // 编译错误:User 不满足 TreeRepository 的类型约束
|
|
32
|
+
* // User.findDescendants({ entityId: 'id' }); // TypeScript 错误
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class TreeRepository<T extends EntityType & (new (...args: never[]) => ITreeEntity), RepositoryType extends ITreeRepository<T> = ITreeRepository<T>> extends Repository<T, RepositoryType> {
|
|
36
|
+
#private;
|
|
37
|
+
protected static _STATIC_METHODS: string[];
|
|
38
|
+
constructor(rxdb: RxDB, EntityType: T);
|
|
39
|
+
/**
|
|
40
|
+
* 查询子孙
|
|
41
|
+
*/
|
|
42
|
+
findDescendants(options: FindTreeOptions<T>): Observable<InstanceType<T>[]>;
|
|
43
|
+
/**
|
|
44
|
+
* 查询子孙数量
|
|
45
|
+
*/
|
|
46
|
+
countDescendants(options: FindTreeOptions<T>): Observable<number>;
|
|
47
|
+
/**
|
|
48
|
+
* 查询祖先
|
|
49
|
+
*/
|
|
50
|
+
findAncestors(options: FindTreeOptions<T>): Observable<InstanceType<T>[]>;
|
|
51
|
+
/**
|
|
52
|
+
* 查询祖先数量
|
|
53
|
+
*/
|
|
54
|
+
countAncestors(options: FindTreeOptions<T>): Observable<number>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=TreeRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeRepository.d.ts","sourceRoot":"","sources":["../../src/repository/TreeRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqD,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC7G,OAAO,EAAE,UAAU,EAAkB,MAAM,MAAM,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAKjE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,qBAAa,cAAc,CACzB,CAAC,SAAS,UAAU,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,WAAW,CAAC,EAC9D,cAAc,SAAS,eAAe,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAC9D,SAAQ,UAAU,CAAC,CAAC,EAAE,cAAc,CAAC;;IAGrC,iBAA0B,eAAe,WAAuD;gBAEpF,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAYrC;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAc3E;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;IAUjE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAczE;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;CAqBhE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 校验树查询深度,未提供时保留不限深度的语义。
|
|
3
|
+
*
|
|
4
|
+
* @param level - 查询深度
|
|
5
|
+
* @returns 非负安全整数;未提供时返回 `undefined`
|
|
6
|
+
* @throws 当深度不是非负安全整数时抛出 `RxDBError`
|
|
7
|
+
*/
|
|
8
|
+
export declare const assertTreeLevel: (level: number | undefined) => number | undefined;
|
|
9
|
+
//# sourceMappingURL=tree-level.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-level.utils.d.ts","sourceRoot":"","sources":["../../src/repository/tree-level.utils.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAIlE,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { EntityStaticType, EntityType, IRepository, RuleGroup } from '@aiao/rxdb';
|
|
2
|
+
/**
|
|
3
|
+
* 树结构查询配置
|
|
4
|
+
*/
|
|
5
|
+
export interface FindTreeOptions<T extends EntityType = EntityType, WhereType = RuleGroup<InstanceType<T>>> {
|
|
6
|
+
/**
|
|
7
|
+
* 查询的根实体 ID
|
|
8
|
+
*/
|
|
9
|
+
entityId?: EntityStaticType<T, 'idType'> | null;
|
|
10
|
+
/**
|
|
11
|
+
* 查询条件
|
|
12
|
+
*/
|
|
13
|
+
where?: WhereType;
|
|
14
|
+
/**
|
|
15
|
+
* 查询深度(层级数包含当前节点本身)
|
|
16
|
+
*
|
|
17
|
+
* - 不传:**不限深度** —— `findDescendants` 返回整棵子树、`findAncestors` 返回整条祖先链
|
|
18
|
+
* - `0`:仅当前节点(`entityId` 为空时即所有根节点)
|
|
19
|
+
* - `1`:当前节点 + 直接子节点
|
|
20
|
+
* - `n`:查询到第 n 层深度
|
|
21
|
+
*
|
|
22
|
+
* @defaultValue `undefined`(不限深度)
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* 不裁剪、不兜底:非负整数以外的值(负数、小数、`NaN`、字符串)一律抛 `RxDBError`。
|
|
26
|
+
* `level` 是树查询里唯一被直接插值进递归 CTE 比较式的选项,悄悄改写它等于把注入
|
|
27
|
+
* 变成一次静默的错误查询。插件的 `assertTreeLevel` 与各适配器复用核心的通用数值校验,
|
|
28
|
+
* 绕过 Repository 直接调适配器时同样抛错。
|
|
29
|
+
*
|
|
30
|
+
* 不传时递归深度由各 SQL 适配器内部的失控保护常量兜底(防脏数据把 `parentId` 连成环),
|
|
31
|
+
* 那是实现细节而非查询语义:正常树不会触到。
|
|
32
|
+
*/
|
|
33
|
+
level?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 树结构仓库接口
|
|
37
|
+
*/
|
|
38
|
+
export interface ITreeRepository<T extends EntityType> extends IRepository<T> {
|
|
39
|
+
/**
|
|
40
|
+
* 查询子孙实体
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* - 指定 entityId 时:包含当前节点 + 子孙节点
|
|
44
|
+
* - 不指定 entityId 时:返回所有根节点及其子孙
|
|
45
|
+
*/
|
|
46
|
+
findDescendants(options: FindTreeOptions<T>): Promise<InstanceType<T>[]>;
|
|
47
|
+
/**
|
|
48
|
+
* 查询子孙实体数量
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* - 指定 entityId 时:**不包含当前节点**,只统计后代数量
|
|
52
|
+
* - 不指定 entityId 时:统计所有根节点及其后代的总数
|
|
53
|
+
*/
|
|
54
|
+
countDescendants(options: FindTreeOptions<T>): Promise<number>;
|
|
55
|
+
/**
|
|
56
|
+
* 查询祖先节点
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* 指定 entityId 时:包含当前节点 + 祖先节点
|
|
60
|
+
*/
|
|
61
|
+
findAncestors(options: FindTreeOptions<T>): Promise<InstanceType<T>[]>;
|
|
62
|
+
/**
|
|
63
|
+
* 查询祖先节点数量
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* 指定 entityId 时:**不包含当前节点**,只统计祖先数量
|
|
67
|
+
*/
|
|
68
|
+
countAncestors(options: FindTreeOptions<T>): Promise<number>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=tree-repository.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-repository.interface.d.ts","sourceRoot":"","sources":["../../src/repository/tree-repository.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EAAE,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxG;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IAEhD;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;IAC3E;;;;;;OAMG;IACH,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEzE;;;;;;OAMG;IACH,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/D;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvE;;;;;OAKG;IACH,cAAc,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiao/rxdb-plugin-tree",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.28",
|
|
4
|
+
"description": "Tree entities, hierarchy queries and incremental merge for Aiao RxDB.",
|
|
5
|
+
"homepage": "https://rxdb.aiao.io/docs/plugins",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/aiao-io/rxdb/issues"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"aiao",
|
|
11
|
+
"rxdb",
|
|
12
|
+
"tree",
|
|
13
|
+
"hierarchy",
|
|
14
|
+
"query",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/aiao-io/rxdb.git",
|
|
21
|
+
"directory": "packages/rxdb-plugin-tree"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
"./package.json": "./package.json",
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./generator": {
|
|
36
|
+
"@aiao/source": "./src/generator/index.ts",
|
|
37
|
+
"import": "./dist/generator.js",
|
|
38
|
+
"types": "./dist/generator/index.d.ts"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src",
|
|
44
|
+
"!src/**/*.spec.*",
|
|
45
|
+
"!src/**/*.test.*",
|
|
46
|
+
"!src/**/__tests__/**",
|
|
47
|
+
"!**/*.tsbuildinfo"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"nx": {
|
|
53
|
+
"name": "rxdb-plugin-tree",
|
|
54
|
+
"tags": [
|
|
55
|
+
"js-lib"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"rxjs": "^7.8.2",
|
|
60
|
+
"@aiao/rxdb-client-generator": "^0.0.28",
|
|
61
|
+
"@aiao/utils": "^0.0.28"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@aiao/rxdb": "^0.0.28"
|
|
65
|
+
}
|
|
6
66
|
}
|