tbdb 0.0.0 → 0.0.5
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/README.md +72 -0
- package/dist/adapter/IndexedDB/IndexedDBAdapter.d.ts +29 -0
- package/dist/adapter/IndexedDB/index.d.ts +1 -0
- package/dist/adapter/IndexedDB/test/indexeddb.test.d.ts +1 -0
- package/dist/adapter/SQLite/SQLiteAdapter.d.ts +137 -15
- package/dist/adapter/SQLite/benchmark/query_analysis.bench.d.ts +1 -0
- package/dist/adapter/SQLite/benchmark/sqlite-extended.bench.d.ts +9 -0
- package/dist/adapter/SQLite/benchmark/sqlite.bench.d.ts +1 -0
- package/dist/adapter/SQLite/driver/BetterSqlite3Driver.d.ts +27 -0
- package/dist/adapter/SQLite/driver/BunSqliteDriver.d.ts +68 -0
- package/dist/adapter/SQLite/driver/NodeSqliteDriver.d.ts +60 -0
- package/dist/adapter/SQLite/driver/index.d.ts +51 -0
- package/dist/adapter/SQLite/driver/test/driver.test.d.ts +6 -0
- package/dist/adapter/SQLite/driver/types.d.ts +106 -0
- package/dist/adapter/SQLite/index.d.ts +3 -0
- package/dist/adapter/SQLite/test/dirty-tracking-bugs.test.d.ts +24 -0
- package/dist/adapter/SQLite/test/dirty-tracking-production.test.d.ts +11 -0
- package/dist/adapter/SQLite/test/side-table-bug-verify.test.d.ts +14 -0
- package/dist/adapter/SQLite/test/side-table-bugs.test.d.ts +17 -0
- package/dist/adapter/SQLite/test/side-table-edge-cases.test.d.ts +15 -0
- package/dist/adapter/SQLite/test/sqlite-datatypes.test.d.ts +5 -0
- package/dist/adapter/SQLite/test/sqlite-multi-driver.test.d.ts +6 -0
- package/dist/adapter/SQLite/test/sqlite-query-ops.test.d.ts +4 -0
- package/dist/adapter/SQLite/utils/mongoToSql.d.ts +4 -1
- package/dist/adapter/SQLite/utils/projection.d.ts +16 -0
- package/dist/adapter/SQLite/utils/queryAnalysis.d.ts +54 -0
- package/dist/adapter/SQLite/utils/serializer.d.ts +19 -2
- package/dist/adapter/SQLite/utils/zstdHelper.d.ts +2 -2
- package/dist/adapter/adapter.d.ts +62 -3
- package/dist/benchmark/dist/base.try.d.ts +1 -0
- package/dist/core/Table.d.ts +15 -9
- package/dist/core/defineTable.d.ts +10 -4
- package/dist/core/event.d.ts +24 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/extension/tree/TableTree.d.ts +49 -0
- package/dist/extension/tree/core/copyNodes.d.ts +36 -0
- package/dist/extension/tree/core/createNodes.d.ts +33 -0
- package/dist/extension/tree/core/deleteNodes.d.ts +33 -0
- package/dist/extension/tree/core/listNodes.d.ts +32 -0
- package/dist/extension/tree/core/listNodesByCursor.d.ts +31 -0
- package/dist/extension/tree/core/moveNodes.d.ts +25 -0
- package/dist/extension/tree/core/preOverwriteNodes.d.ts +41 -0
- package/dist/extension/tree/core/presyncNodes.d.ts +30 -0
- package/dist/extension/tree/core/setNodes.d.ts +49 -0
- package/dist/extension/tree/core/unDeleteNodes.d.ts +28 -0
- package/dist/extension/tree/core/updateNodes.d.ts +29 -0
- package/dist/extension/tree/demo/dist-web/assets/index-DT1zZc4B.d.ts +1 -0
- package/dist/extension/tree/demo/src/main.d.ts +1 -0
- package/dist/extension/tree/demo/src/server.d.ts +1 -0
- package/dist/extension/tree/demo/vite.config.d.ts +2 -0
- package/dist/extension/tree/index.d.ts +1 -0
- package/dist/extension/tree/test/benchmark/ManyMany.bench.d.ts +1 -0
- package/dist/extension/tree/test/benchmark/table-tree.bench.d.ts +1 -0
- package/dist/extension/tree/test/gemini/table-tree-gemini-TableTree.test.d.ts +1 -0
- package/dist/extension/tree/test/human/table-tree-humam.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-clearDeadNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-copyNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-createNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-deleteNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-fs-comb.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-index-comb.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-listNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-metadata-comb.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-moveNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-multi-user-comb.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-preOverwriteNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-presyncNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-setNdoes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree-updateNodes.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree.test.d.ts +1 -0
- package/dist/extension/tree/test/table-tree.try.d.ts +1 -0
- package/dist/extension/tree/tool/clearDeadNodes.d.ts +22 -0
- package/dist/extension/tree/tool/refreshTreeMetadata.d.ts +9 -0
- package/dist/extension/tree/tree.types.d.ts +111 -0
- package/dist/extension/tree/util/applyTreeMetadataDelta.d.ts +29 -0
- package/dist/extension/tree/util/assertTreeParent.d.ts +8 -0
- package/dist/extension/tree/util/collectAncestorIds.d.ts +4 -0
- package/dist/extension/tree/util/collectDescendantNodes.d.ts +10 -0
- package/dist/extension/tree/util/collectExistingParentIds.d.ts +9 -0
- package/dist/extension/tree/util/collectTopSelectedNodes.d.ts +10 -0
- package/dist/extension/tree/util/getNodeValueByPath.d.ts +2 -0
- package/dist/extension/tree/util/getUniqueFileNames.d.ts +13 -0
- package/dist/extension/tree/util/groupNodesByParentId.d.ts +8 -0
- package/dist/extension/tree/util/newEmptyNode.d.ts +2 -0
- package/dist/extension/tree/util/newNodeId.d.ts +2 -0
- package/dist/extension/tree/util/normalizeWritableNode.d.ts +9 -0
- package/dist/extension/tree/util/rebalanceTreeIndexes.d.ts +11 -0
- package/dist/extension/tree/util/refreshTreeMetadata.d.ts +16 -0
- package/dist/extension/tree/util/repairDuplicatedSiblingConflicts.d.ts +4 -0
- package/dist/extension/tree/util/repairDuplicatedSiblingNames.d.ts +4 -0
- package/dist/extension/tree/util/repairTreeOverwriteConflicts.d.ts +10 -0
- package/dist/extension/tree/util/resolveOverwriteNodes.d.ts +26 -0
- package/dist/extension/tree/util/resolveTreeIndex.d.ts +4 -0
- package/dist/extension/tree/util/setTreeNumberStat.d.ts +9 -0
- package/dist/extension/tree/util/stripTreeManagedFields.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4017 -1188
- package/dist/test/auto-metadata.test.d.ts +1 -0
- package/dist/test/getTestTable.d.ts +3 -1
- package/dist/test/globals.d.ts +1 -0
- package/dist/test/table-event.test.d.ts +1 -0
- package/dist/test/table-index.test.d.ts +1 -0
- package/dist/test/table-type.test.d.ts +1 -0
- package/dist/test/try/doc.try.d.ts +1 -1
- package/dist/test/try/getTestUserTable.d.ts +1 -1
- package/dist/test/try/insert.try.d.ts +1 -1
- package/dist/test/try/mongodb-try/id-test.d.ts +1 -0
- package/dist/test/try//345/210/233/345/273/272350/344/270/207/346/225/260/346/215/256.d.ts +1 -1
- package/dist/test/try//346/223/215/344/275/234350/344/270/207/346/225/260/346/215/256.d.ts +1 -1
- package/package.json +26 -8
- package/dist/rslib-runtime.js +0 -18
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode, ITreeOverwriteOptions, ITreeIndexOptions, ITreeChangeResult } from "../tree.types";
|
|
3
|
+
/** 移动节点选项 */
|
|
4
|
+
export interface ITreeMoveNodesOptions extends ITreeOverwriteOptions {
|
|
5
|
+
/** 自动更新排序索引配置 */
|
|
6
|
+
index?: ITreeIndexOptions;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 移动节点
|
|
10
|
+
*
|
|
11
|
+
* 把节点移动到新的父级下,并按覆盖策略处理目标父级中的冲突节点。
|
|
12
|
+
*
|
|
13
|
+
* 核心流程:
|
|
14
|
+
* 1. 去重输入 ID、校验目标父级,并过滤掉父子混合选择中的后代节点。
|
|
15
|
+
* 2. 先校验不会移动到自身或后代,避免形成父级环。
|
|
16
|
+
* 3. 按覆盖策略解析目标父级冲突:replace 删除冲突目标,skip 跳过来源,merge 递归合并目录。
|
|
17
|
+
* 4. 为仍需移动的节点分配目标父级下的新 index,并在写入前再次校验父级环。
|
|
18
|
+
* 5. 批量更新 parentId/index/modif,写入后再次检测并发造成的环;若发现坏状态立即回滚本次移动。
|
|
19
|
+
* 6. 重排目标父级 index,刷新新旧父级及祖先 metadata,并做并发冲突兜底修复。
|
|
20
|
+
*/
|
|
21
|
+
export declare function moveNodes(this: TableTree<ITreeNode>,
|
|
22
|
+
/** 要移动的节点 id 列表 */
|
|
23
|
+
nodeIds: string[],
|
|
24
|
+
/** 目标父节点 id ,如果为 "/" 表示根节点 */
|
|
25
|
+
parentId: string, options?: ITreeMoveNodesOptions): Promise<ITreeChangeResult>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode, ITreeOverwriteOptions } from "../tree.types";
|
|
3
|
+
/** 检测节点冲突的选项
|
|
4
|
+
*
|
|
5
|
+
* 这里直接复用树覆盖策略选项,保证预检语义与 moveNodes / setNodes 一致。
|
|
6
|
+
*/
|
|
7
|
+
export interface ITreePreOverwriteOptions extends ITreeOverwriteOptions {
|
|
8
|
+
/** existNodes 返回的投影字段
|
|
9
|
+
*
|
|
10
|
+
* 可以是字符串数组,表示包含的字段列表\
|
|
11
|
+
* 也可以是字段映射对象,1 表示包含该字段,-1 表示排除该字段\
|
|
12
|
+
* 不能同时包含和排除字段
|
|
13
|
+
*/
|
|
14
|
+
projection?: string[] | Record<string, 1 | -1>;
|
|
15
|
+
}
|
|
16
|
+
/** 检测节点冲突的结果 */
|
|
17
|
+
export interface ITreePreOverwriteResult<TNode extends ITreeNode = ITreeNode> {
|
|
18
|
+
/** 是否存在冲突 */
|
|
19
|
+
isConflict: boolean;
|
|
20
|
+
/** 已存在的节点列表 */
|
|
21
|
+
existNodes: Partial<TNode>[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 预覆盖检测
|
|
25
|
+
*
|
|
26
|
+
* 在不修改任何数据的前提下,检查一批待写入节点或待移动节点在目标父级下是否会发生唯一键冲突。
|
|
27
|
+
*
|
|
28
|
+
* 核心流程:
|
|
29
|
+
* 1. 根据 uniqueBy 收集待写入 nodes 中的唯一键值。
|
|
30
|
+
* 2. 读取待移动 nodeIds 对应的最外层节点,并收集它们的唯一键值;父子混合移动时后代不参与预检。
|
|
31
|
+
* 3. 如果没有可检测值,直接返回无冲突。
|
|
32
|
+
* 4. 在目标 parentId 的直属子节点里查找这些唯一键值,并排除正在移动的节点自身。
|
|
33
|
+
* 5. 返回冲突节点列表;overwriteMode 不会改变预检结果,因为这里不执行覆盖动作。
|
|
34
|
+
*/
|
|
35
|
+
export declare function preOverwriteNodes(this: TableTree<ITreeNode>,
|
|
36
|
+
/** 要检查的节点数据列表 */
|
|
37
|
+
nodes: Partial<ITreeNode>[],
|
|
38
|
+
/** 要移动的节点 id 列表 */
|
|
39
|
+
nodeIds: string[],
|
|
40
|
+
/** 目标父节点 id ,如果为 "/" 表示根节点 */
|
|
41
|
+
parentId: string, options?: ITreePreOverwriteOptions): Promise<ITreePreOverwriteResult<ITreeNode>>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
export interface ITreePreSyncNodeResult {
|
|
4
|
+
/** 是否需要同步 */
|
|
5
|
+
needSync: boolean;
|
|
6
|
+
/** 需要同步的节点 ID 列表 */
|
|
7
|
+
syncNodeIds: string[];
|
|
8
|
+
/** 线上不存在的 ID 列表 */
|
|
9
|
+
deletedNodeIds: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 预同步节点
|
|
13
|
+
*
|
|
14
|
+
* 用客户端保存的 modif / cmodif 与当前数据库中的节点状态做轻量对比,
|
|
15
|
+
* 帮助客户端在写入或拉取前判断哪些节点需要重新同步。
|
|
16
|
+
*
|
|
17
|
+
* 核心流程:
|
|
18
|
+
* 1. 逐个读取当前可见节点;软删除节点在默认读取语义下视为不存在。
|
|
19
|
+
* 2. 找不到节点时放入 deletedNodeIds,表示客户端本地节点已经失效。
|
|
20
|
+
* 3. 如果传入的 modif 或 cmodif 任意一个与线上值不同,放入 syncNodeIds。
|
|
21
|
+
* 4. 未传 modif/cmodif 的已有节点不触发同步,便于调用方只检查自己关心的计数。
|
|
22
|
+
* 5. 保留重复输入对应的重复结果,避免调用方依赖输入顺序时丢失信息。
|
|
23
|
+
*/
|
|
24
|
+
export declare function presyncNodes(this: TableTree<ITreeNode>,
|
|
25
|
+
/** 要检查的节点数据列表 */
|
|
26
|
+
nodeModifs: {
|
|
27
|
+
id: string;
|
|
28
|
+
modif?: number;
|
|
29
|
+
cmodif?: number;
|
|
30
|
+
}[]): Promise<ITreePreSyncNodeResult>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode, ITreeOverwriteOptions, ITreeIndexOptions, ITreeChangeResult } from "../tree.types";
|
|
3
|
+
import type { ITreePreSyncNodeResult } from "./presyncNodes";
|
|
4
|
+
/** 设置节点选项 */
|
|
5
|
+
export type ITreeSetNodesOptions = ITreeOverwriteOptions & {
|
|
6
|
+
/** 是否只更新已存在的节点(不会创建新节点) */
|
|
7
|
+
updateOnly?: boolean;
|
|
8
|
+
/** 自动更新排序索引配置 */
|
|
9
|
+
index?: ITreeIndexOptions;
|
|
10
|
+
/**
|
|
11
|
+
* 是否进行预同步(pre-sync)检查。
|
|
12
|
+
* 开启后会根据传入节点里的 oldModif/oldCmodif 返回过期、缺失等同步状态。
|
|
13
|
+
*/
|
|
14
|
+
presync?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 是否返回被更新的节点 id
|
|
17
|
+
*/
|
|
18
|
+
returnChangedNodesIds?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 赋值模式,同 setMany() 的赋值模式。
|
|
21
|
+
* 默认 "default" 相当于 `Object.assign(oldDoc, newDoc)`。
|
|
22
|
+
*/
|
|
23
|
+
setMode?: "default" | "overwrite" | "merge";
|
|
24
|
+
};
|
|
25
|
+
export interface ITreeSetNodesResult extends ITreeChangeResult, Partial<ITreePreSyncNodeResult> {
|
|
26
|
+
/** 被更新的节点 id 列表 */
|
|
27
|
+
changedNodeIds?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 设置节点
|
|
31
|
+
*
|
|
32
|
+
* 设置节点数据,已存在的节点会被覆盖,不存在的节点会被创建。
|
|
33
|
+
*
|
|
34
|
+
* 如果在 `nodes` 中提供了 `oldModif`, `oldCmodif` 字段,它们会被用来进行预同步检查(pre-sync)而不会被设置到节点上。
|
|
35
|
+
*
|
|
36
|
+
* 流程:
|
|
37
|
+
* 1. 生成本次写入统一使用的 modif。
|
|
38
|
+
* 2. 按需执行 presync,并剥离只用于同步检查的 oldModif/oldCmodif。
|
|
39
|
+
* 3. updateOnly 模式先过滤不可见或不存在的节点,避免把缺失节点误创建回来。
|
|
40
|
+
* 4. 根据覆盖策略解析最终要写入的节点、要删除的冲突节点,以及 merge 后要清理的来源目录。
|
|
41
|
+
* 5. 在任何真实写入前完成父级存在、批次重复 ID、最终父级环和排序锚点校验,尽量保证失败时不留下半写入。
|
|
42
|
+
* 6. 写入前记录旧父级,写入后重排受影响父级 index,并刷新新旧父级及祖先 metadata。
|
|
43
|
+
* 7. 最后执行并发冲突兜底修复,让多用户同时写入同一父级时最终仍收敛到覆盖策略要求的状态。
|
|
44
|
+
*
|
|
45
|
+
* 要注意如果修改了节点的 parentId 需要触发相应的 metadata 变更,并且遵守 ITreeOverwriteOptions 覆盖设置和 index 规则
|
|
46
|
+
*/
|
|
47
|
+
export declare function setNodes(this: TableTree<ITreeNode>,
|
|
48
|
+
/** 要设置的节点数据列表 */
|
|
49
|
+
nodes: Partial<ITreeNode>[], options?: ITreeSetNodesOptions): Promise<ITreeSetNodesResult>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/** 删除节点结果 */
|
|
4
|
+
export interface ITreeDeleteResult {
|
|
5
|
+
/** 是否有节点被删除 */
|
|
6
|
+
hasDeleted: boolean;
|
|
7
|
+
/** 是否有子节点被删除 */
|
|
8
|
+
hasChildDeleted: boolean;
|
|
9
|
+
/** 被删除的节点数量 */
|
|
10
|
+
deletedCount: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 恢复已删除的节点
|
|
14
|
+
*
|
|
15
|
+
* 如果 TableTree 设置了 `enableMarkDelete: true`,
|
|
16
|
+
* 则删除节点时会把节点标记为已删除而不是直接从数据库中删除
|
|
17
|
+
* 这时就可以通过 `unDeleteNodes()` 方法来恢复这些被标记为已删除的节点。
|
|
18
|
+
*
|
|
19
|
+
* 核心流程:
|
|
20
|
+
* 1. 读取待恢复节点的整棵后代子树,同时读取祖先链,避免恢复深层节点后出现可见孤儿节点。
|
|
21
|
+
* 2. 只对当前确实处于 _isDeleted 状态的节点执行恢复,未删除节点不改动。
|
|
22
|
+
* 3. 先基于“本次真实恢复的节点集合”重建被恢复目录内部统计,避免把仍然删除的后代计入 metadata。
|
|
23
|
+
* 4. 用最外层恢复节点的贡献量增量刷新外部父级和祖先。
|
|
24
|
+
* 5. 单独修正被恢复目录自身的 ctotal/cftotal/csize/childLastIndex,让恢复后的子树内部也保持一致。
|
|
25
|
+
*/
|
|
26
|
+
export declare function unDeleteNodes(this: TableTree<ITreeNode>,
|
|
27
|
+
/** 要恢复的节点 id 列表 */
|
|
28
|
+
nodeIds: string[]): Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ITableFilter, ITableUpdateOp } from "../../../core/types";
|
|
2
|
+
import type { TableTree } from "../TableTree";
|
|
3
|
+
import type { ITreeChangeResult, ITreeNode } from "../tree.types";
|
|
4
|
+
/** 更新节点选项 */
|
|
5
|
+
export interface ITreeUpdateNodesOptions {
|
|
6
|
+
/** 是否递归更新子节点
|
|
7
|
+
* 如果使用递归,并且更新 parentId 时要注意,不要把后代节点的 parentId 也一并改写为目标父级,应该抛出错误
|
|
8
|
+
*/
|
|
9
|
+
deep?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 更新节点
|
|
13
|
+
*
|
|
14
|
+
* 更底层的更新接口,可以一次更新多个经 filter 筛选的文档。
|
|
15
|
+
* 可以通过 `options.deep` 参数递归更新子节点。
|
|
16
|
+
*
|
|
17
|
+
* 一次操作更新的所有节点都有相同的 modif, cmodif 值
|
|
18
|
+
*
|
|
19
|
+
* 核心流程:
|
|
20
|
+
* 1. 先判断 updateOp 是否会影响树统计字段,决定读取轻量投影还是统计投影。
|
|
21
|
+
* 2. 根据 filter 收集目标节点;deep 模式会把目标节点的后代也纳入同一次更新。
|
|
22
|
+
* 3. 校验 updateOp 不会破坏树结构:不能改 id,不能移除必填字段,deep 不能同时改 parentId。
|
|
23
|
+
* 4. 清理外部传入的系统维护字段,并补齐本次统一 modif。
|
|
24
|
+
* 5. 执行真实更新;批量移动 parentId 时为每个移动节点分配独立 index。
|
|
25
|
+
* 6. 如果能从旧节点和 $set 直接推导统计变化,就走增量 metadata;否则用 refreshTreeMetadata 全量刷新兜底。
|
|
26
|
+
*
|
|
27
|
+
* 注意:此接口不会执行覆盖检查。调用方直接修改 parentId 时,需要自行确保目标父级下不会出现业务冲突。
|
|
28
|
+
*/
|
|
29
|
+
export declare function updateNodes(this: TableTree<ITreeNode>, filter: ITableFilter, updateOp: ITableUpdateOp<ITreeNode>, options?: ITreeUpdateNodesOptions): Promise<ITreeChangeResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./styles.css";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TableTree, defineTableTree } from "./TableTree";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/**
|
|
4
|
+
* 清理无效的死节点(孤立节点)
|
|
5
|
+
*
|
|
6
|
+
* 无效节点是指那些不再满足树形可达性条件的节点,例如:
|
|
7
|
+
* 1. 父级节点被删除了,但子节点还存在(例如递归删除时,程序被意外中断,导致子节点残留)。
|
|
8
|
+
* 2. 某个节点虽然父级存在,但父级的父级被删除了(祖先断链)。
|
|
9
|
+
*
|
|
10
|
+
* 算法策略:
|
|
11
|
+
* 1. 生成一个唯一的时间戳/标识,从根节点(parentId 为 "/" 且未被标记删除的节点)开始遍历。
|
|
12
|
+
* 2. 通过 BFS 广度优先遍历树,将每个可达节点的临时属性 `__checkIsNotDead` 标记为该标识。
|
|
13
|
+
* 3. 遍历结束后,未被打上该标记的节点即为死节点。
|
|
14
|
+
* 4. 根据表是否启用 `enableMarkDelete`,在物理删除时保留已标记删除的节点(即排除 `_isDeleted: true` 节点),而只清理其他孤立的正常节点。
|
|
15
|
+
* 5. 清理完死节点后,移除所有存活节点上的临时标记。
|
|
16
|
+
*
|
|
17
|
+
* 由于此操作需要遍历所有节点,可能会比较耗时,工具会使用 chalk 在控制台输出多彩的日志提示进度和结果。
|
|
18
|
+
*
|
|
19
|
+
* @param table 目录树表实例
|
|
20
|
+
* @returns 返回清理掉的无效死节点数量
|
|
21
|
+
*/
|
|
22
|
+
export declare function clearDeadNodes<TNode extends ITreeNode = ITreeNode>(table: TableTree<TNode>): Promise<number>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/**
|
|
4
|
+
* 递归刷新树的元数据
|
|
5
|
+
* 从一个文件夹向下递归刷新 metadata 属性,保证 `ctotal`,`cftotal`,`csize` 正确
|
|
6
|
+
*/
|
|
7
|
+
export declare function refreshTreeMetadata(table: TableTree<ITreeNode>,
|
|
8
|
+
/** 要刷新元数据的文件夹 ID,可以指定为 "/" 来刷新整个树的元数据 */
|
|
9
|
+
parentId: string): Promise<void>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ITableDoc } from "../../adapter/adapter";
|
|
2
|
+
export interface ITreeNode extends ITableDoc {
|
|
3
|
+
/** 节点 ID */
|
|
4
|
+
id: string;
|
|
5
|
+
/** 父级的 ID
|
|
6
|
+
* 如果为 "/" 表示父级为根节点 */
|
|
7
|
+
parentId: string;
|
|
8
|
+
/** 节点名称
|
|
9
|
+
* 用于显示和识别节点
|
|
10
|
+
* 内部限制不能允许包含 "/" 字符,如果有会抛出错误,以避免和路径混淆
|
|
11
|
+
*/
|
|
12
|
+
name: string;
|
|
13
|
+
/** 节点类型 */
|
|
14
|
+
type?: string;
|
|
15
|
+
/** 修改计数 */
|
|
16
|
+
modif: number;
|
|
17
|
+
/** 子级修改计数 */
|
|
18
|
+
cmodif?: number;
|
|
19
|
+
/** 是否是文件夹节点
|
|
20
|
+
*
|
|
21
|
+
* 标记是否是文件夹节点(之所以需要标记是因为无论是否是文件夹节点,任何节点都可以有子节点)
|
|
22
|
+
*/
|
|
23
|
+
isDir: boolean;
|
|
24
|
+
/** 排序索引 (indexless 分数索引) */
|
|
25
|
+
index?: string;
|
|
26
|
+
/** 子级排序序号(子级最后一个节点的序号) */
|
|
27
|
+
childLastIndex?: string;
|
|
28
|
+
/** 子级大小 (所有子级节点,不包括自身节点的大小) */
|
|
29
|
+
csize?: number;
|
|
30
|
+
/** 子级数量 (所有子级节点的数量,包括文件夹和文件 ) */
|
|
31
|
+
ctotal?: number;
|
|
32
|
+
/** 子级文件数量 (所有子级节点的数量,仅包含文件) */
|
|
33
|
+
cftotal?: number;
|
|
34
|
+
/** 节点尺寸(byte) */
|
|
35
|
+
size: number;
|
|
36
|
+
}
|
|
37
|
+
/** 树结构元数据字段
|
|
38
|
+
*
|
|
39
|
+
* 这些字段会被系统管理,用户无法自行修改。
|
|
40
|
+
*/
|
|
41
|
+
export interface ITreeNodeMetadataKeys {
|
|
42
|
+
/** 子级总大小,不包含当前节点自身 size */
|
|
43
|
+
csize: number;
|
|
44
|
+
/** 子级总数量,包含文件夹和文件 */
|
|
45
|
+
ctotal: number;
|
|
46
|
+
/** 子级文件总数量,仅统计文件节点 */
|
|
47
|
+
cftotal: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 树结构节点排序索引选项
|
|
51
|
+
*/
|
|
52
|
+
export interface ITreeIndexOptions {
|
|
53
|
+
/**
|
|
54
|
+
* 指定一个父节点下已存在的子节点 ID
|
|
55
|
+
* 新创建的节点将被插入到该节点之后
|
|
56
|
+
*/
|
|
57
|
+
prevNodeId?: string;
|
|
58
|
+
/**
|
|
59
|
+
* 指定一个父节点下已存在的子节点 ID
|
|
60
|
+
* 新创建的节点将被插入到该节点之前
|
|
61
|
+
*/
|
|
62
|
+
nextNodeId?: string;
|
|
63
|
+
/** 新创建的节点将被插入到子节点列表的开头 */
|
|
64
|
+
toStart?: boolean;
|
|
65
|
+
/** 新创建的节点将被插入到子节点列表的末尾 */
|
|
66
|
+
toEnd?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** 节点覆盖选项 */
|
|
69
|
+
export type ITreeOverwriteOptions = {
|
|
70
|
+
/** 以什么方式进行唯一标识,默认按 id
|
|
71
|
+
* 也可以是任意键,例如 "name","meta.hash_md5" 等等
|
|
72
|
+
*/
|
|
73
|
+
uniqueBy?: "id" | "name" | string;
|
|
74
|
+
/** 当出现文件覆盖文件夹的情况时
|
|
75
|
+
* 是否要允许 file 覆盖 dir,默认不允许
|
|
76
|
+
* 如果不允许,则会跳过单个文件的覆盖,保留原有文件夹节点
|
|
77
|
+
*/
|
|
78
|
+
enableFileOverwriteDir?: boolean;
|
|
79
|
+
/** 当出现覆盖的情况,要执行的逻辑
|
|
80
|
+
*
|
|
81
|
+
* - `replace`:直接替换目标节点(默认)
|
|
82
|
+
* (遵守 Table 的删除逻辑,可能是标记删除,要注意如果是文件夹会递归删除)
|
|
83
|
+
*
|
|
84
|
+
* - `skip`:跳过已存在的冲突节点,不写入新节点。
|
|
85
|
+
*
|
|
86
|
+
* - `merge`:删除已存在的冲突节点,再写入新节点;
|
|
87
|
+
* 但如果冲突节点和新节点都是文件夹节点,
|
|
88
|
+
* 则不删除冲突节点,而是把它们的子节点进行合并
|
|
89
|
+
* (如果子节点也有冲突则继续按 merge 规则进行处理)。
|
|
90
|
+
* 相当于目录的递归合并。
|
|
91
|
+
*
|
|
92
|
+
* - `mergeByModif`: 类似 `merge`,处理冲突节点时不是用新节点
|
|
93
|
+
* 直接覆盖已存在节点,而是判断节点 `modif` 的大小,
|
|
94
|
+
* 保留 `modif` 较大的节点。
|
|
95
|
+
*
|
|
96
|
+
* - `newName`:不覆盖目标节点,而是为新节点生成一个新的名称(例如在原有名称后添加 " (1)")
|
|
97
|
+
*
|
|
98
|
+
*/
|
|
99
|
+
overwriteMode?: "replace" | "skip" | "merge" | "mergeByModif" | "newName";
|
|
100
|
+
};
|
|
101
|
+
/** 树变更结果
|
|
102
|
+
* 更新、创建等树操作的返回值,便于客户端同步
|
|
103
|
+
*/
|
|
104
|
+
export interface ITreeChangeResult {
|
|
105
|
+
/** 此次操作的 modif 值
|
|
106
|
+
* 每个改变的节点都会被设置为这个 modif 值 */
|
|
107
|
+
modif?: number;
|
|
108
|
+
/** 此次操作的 cmodif 值
|
|
109
|
+
* 每个改变的节点的子级都会被设置为这个 cmodif 值 */
|
|
110
|
+
cmodif?: number;
|
|
111
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
export interface ITreeMetadataStatsDelta {
|
|
4
|
+
/** 直接受影响的父级,增量会沿着该父级的祖先链向上应用。 */
|
|
5
|
+
parentId: string | undefined;
|
|
6
|
+
/** 子树节点数量增量。 */
|
|
7
|
+
ctotal?: number;
|
|
8
|
+
/** 子树文件数量增量。 */
|
|
9
|
+
cftotal?: number;
|
|
10
|
+
/** 子树大小增量。 */
|
|
11
|
+
csize?: number;
|
|
12
|
+
/** 新写入的直接子级 index 候选值,用于无需扫描兄弟节点地推进 childLastIndex。 */
|
|
13
|
+
childLastIndexCandidate?: string;
|
|
14
|
+
/** 删除、移动或 index 变化可能移除最后一个子级时,需要用一次 limit=1 查询修正直接父级 childLastIndex。 */
|
|
15
|
+
refreshChildLastIndex?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** 将节点自身连同其后代,换算成它对父级统计字段的贡献。 */
|
|
18
|
+
export declare function calcTreeNodeContribution(node: Pick<ITreeNode, "isDir" | "size" | "ctotal" | "cftotal" | "csize">): {
|
|
19
|
+
ctotal: number;
|
|
20
|
+
cftotal: number;
|
|
21
|
+
csize: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 按增量维护目录 metadata。
|
|
25
|
+
*
|
|
26
|
+
* 目标是把结构性变更从“扫描每个受影响目录的全部子级”降为“沿父级祖先链做加减法”。
|
|
27
|
+
* 这里仍会读取祖先节点当前值,用于保持 0 值字段 unset 的历史语义。
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyTreeMetadataDelta<TNode extends ITreeNode>(table: TableTree<TNode>, deltas: ITreeMetadataStatsDelta[], cmodif?: number): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/** 确认父级节点存在,根节点 "/" 视为合法父级。 */
|
|
4
|
+
export declare function assertTreeParentExists<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string): Promise<void>;
|
|
5
|
+
/** 校验节点名称不会破坏路径语义。 */
|
|
6
|
+
export declare function assertTreeNodeName(name: unknown): void;
|
|
7
|
+
/** 确认移动目标不会落入节点自身或后代中。 */
|
|
8
|
+
export declare function assertNotMoveIntoSelfOrDescendant<TNode extends ITreeNode>(table: TableTree<TNode>, nodeIds: string[], parentId: string): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/** 从一个父级 ID 开始向上收集祖先节点 ID,不包含根节点 "/"。 */
|
|
4
|
+
export declare function collectAncestorIds<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string | undefined): Promise<string[]>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
export interface ICollectDescendantNodesOptions {
|
|
4
|
+
/** 是否包含传入的根节点自身。 */
|
|
5
|
+
includeSelf?: boolean;
|
|
6
|
+
/** 是否包含已标记删除的节点。 */
|
|
7
|
+
ignoreMarkDelete?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** 递归收集一批节点的全部后代节点。 */
|
|
10
|
+
export declare function collectDescendantNodes<TNode extends ITreeNode>(table: TableTree<TNode>, nodeIds: string[], options?: ICollectDescendantNodesOptions): Promise<TNode[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/**
|
|
4
|
+
* 收集节点写入前所在的父级,用于移动后刷新旧父级及其祖先统计。
|
|
5
|
+
*
|
|
6
|
+
* setNodes 可以同时创建、更新和移动节点;如果节点 parentId 发生变化,
|
|
7
|
+
* 只刷新新父级是不够的,旧父级也需要扣减统计并推进 cmodif。
|
|
8
|
+
*/
|
|
9
|
+
export declare function collectExistingParentIds<TNode extends ITreeNode>(table: TableTree<TNode>, nodes: Pick<TNode, "id">[]): Promise<string[]>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/**
|
|
4
|
+
* 根据 ID 读取可见节点,并过滤掉已被选中祖先覆盖的后代节点。
|
|
5
|
+
*
|
|
6
|
+
* 这个工具服务于 copy/move/preOverwrite:
|
|
7
|
+
* 当调用方同时选择“目录”和“目录里的子节点”时,真实操作只需要处理目录本身,
|
|
8
|
+
* 子节点会随目录复制或移动;如果不在这里过滤,后代会被额外平铺到目标父级。
|
|
9
|
+
*/
|
|
10
|
+
export declare function collectTopSelectedNodes(table: TableTree<ITreeNode>, nodeIds: string[]): Promise<ITreeNode[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取一组文件名的唯一不冲突的文件名列表
|
|
3
|
+
* 如果有重复的文件名,则在后面添加 "(1)"、"(2)" 等后缀来区分
|
|
4
|
+
* 如果没有重复的文件名,则返回原名
|
|
5
|
+
*
|
|
6
|
+
* 要注意的是如果文件名是 `文件(2).txt`,会识别出已有的 `(2)` 后缀
|
|
7
|
+
* 并在数字基础上继续递增,例如 `文件(2).txt` -> `文件(3).txt`,而不是 `文件(2) (1).txt`。
|
|
8
|
+
|
|
9
|
+
*
|
|
10
|
+
* @param oldNames 原文件名
|
|
11
|
+
* @param existsNames 已经占用的文件名
|
|
12
|
+
*/
|
|
13
|
+
export declare function getUniqueFileNames(oldNames: string[], existsNames?: string[]): Promise<string[]>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ITreeNode } from "../tree.types";
|
|
2
|
+
/**
|
|
3
|
+
* 按 parentId 分组节点,方便同级批量处理覆盖、排序和 metadata。
|
|
4
|
+
*
|
|
5
|
+
* 目录树的大部分规则都以“同一个父级的直属子节点”为边界:
|
|
6
|
+
* 覆盖冲突只在同级内判断,index 也只在同级内排序,因此 core 流程会频繁按 parentId 分组。
|
|
7
|
+
*/
|
|
8
|
+
export declare function groupNodesByParentId<TNode extends Pick<ITreeNode, "parentId">>(nodes: TNode[]): Map<string, TNode[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ITreeNode } from "../tree.types";
|
|
2
|
+
export interface INormalizeWritableNodeOptions {
|
|
3
|
+
/** 指定写入父级,提供后会覆盖外部传入的 parentId。 */
|
|
4
|
+
parentId?: string;
|
|
5
|
+
/** 本次操作默认 modif,外部没有提供 modif 时使用。 */
|
|
6
|
+
modif?: number;
|
|
7
|
+
}
|
|
8
|
+
/** 将外部传入的节点数据整理为 TableTree 可写入的数据。 */
|
|
9
|
+
export declare function normalizeWritableNode<TNode extends ITreeNode>(node: Partial<TNode>, options?: INormalizeWritableNodeOptions): Partial<TNode>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
export interface IRebalanceTreeIndexesOptions {
|
|
4
|
+
/** 触发重排的 index 最大长度。 */
|
|
5
|
+
maxIndexLength?: number;
|
|
6
|
+
}
|
|
7
|
+
/** 对单个父级下刚写入的 index 区间执行智能重排。 */
|
|
8
|
+
export declare function rebalanceTreeIndexes<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string, items: {
|
|
9
|
+
id: string;
|
|
10
|
+
index?: string;
|
|
11
|
+
}[], options?: IRebalanceTreeIndexesOptions): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
export interface IRefreshTreeMetadataOptions {
|
|
4
|
+
/** 可能受影响的父级 ID。 */
|
|
5
|
+
parentIds?: string[];
|
|
6
|
+
/** 可能受影响的节点 ID,会读取其 parentId 后刷新祖先链。 */
|
|
7
|
+
nodeIds?: string[];
|
|
8
|
+
/** 只需要重算自身统计的节点 ID,不会推进这些节点的 cmodif。 */
|
|
9
|
+
statIds?: string[];
|
|
10
|
+
/** 本次操作的子树修改计数。 */
|
|
11
|
+
cmodif?: number;
|
|
12
|
+
/** 是否需要重新统计子级数量、文件数、大小和末尾 index;普通内容更新只需要推进 cmodif。 */
|
|
13
|
+
statsChanged?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** 统一刷新目录树统计字段,第一版优先保证正确性。 */
|
|
16
|
+
export declare function refreshTreeMetadata<TNode extends ITreeNode>(table: TableTree<TNode>, options: IRefreshTreeMetadataOptions): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode, ITreeOverwriteOptions } from "../tree.types";
|
|
3
|
+
/** 多用户并发覆盖时可能同时写入同一唯一键,这里兜底只保留同一父级下最新的冲突节点。 */
|
|
4
|
+
export declare function repairDuplicatedSiblingConflicts<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string, uniqueBy: string, candidateIds: string[], overwriteMode?: ITreeOverwriteOptions["overwriteMode"]): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode } from "../tree.types";
|
|
3
|
+
/** 多用户并发重命名时可能基于同一份旧列表生成相同名称,写入后再兜底收敛为唯一名称。 */
|
|
4
|
+
export declare function repairDuplicatedSiblingNames<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string, candidateIds?: string[]): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TableTree } from "../TableTree";
|
|
2
|
+
import type { ITreeNode, ITreeOverwriteOptions } from "../tree.types";
|
|
3
|
+
/**
|
|
4
|
+
* 覆盖写入后做并发兜底收敛,避免同级残留重复名称或重复唯一键。
|
|
5
|
+
*
|
|
6
|
+
* 预先解析覆盖策略只能基于当时读到的同级节点;多用户同时写入同一父级时,
|
|
7
|
+
* 仍可能在写入后产生重复 name 或 uniqueBy。这个函数统一放在 core 操作末尾,
|
|
8
|
+
* 按实际落库结果再做一次修复,让最终状态符合覆盖模式。
|
|
9
|
+
*/
|
|
10
|
+
export declare function repairTreeOverwriteConflicts<TNode extends ITreeNode>(table: TableTree<TNode>, parentId: string, candidateIds: string[], options?: ITreeOverwriteOptions): Promise<void>;
|