npm package: @knotx/data
Description: Data for Knotx
Author: boenfu
Latest version: 0.5.10

# @knotx/data

一个基于 RxJS 的响应式数据管理库，提供强大的数据操作和双向关系管理功能。

## 📦 安装

```bash
npm install @knotx/data
```

```bash
yarn add @knotx/data
```

```bash
pnpm add @knotx/data
```

## 🔧 基本概述

`@knotx/data` 是 Knotx 生态系统的核心数据管理包，提供两个主要的数据管理工具：

- **DataManager**: 用于管理数据的增删改查操作，支持草稿模式、批量操作、版本控制等高级功能
- **DualRelation**: 用于管理父子节点之间的双向关系，支持层级管理、循环引用检测等功能

## 🚀 快速开始

```typescript
import { DataManager, DualRelation } from '@knotx/data'

// 创建数据管理器
const dataManager = new DataManager('my-data')

// 创建双向关系管理器
const relation = new DualRelation<string, string>()
```

## 📚 API 文档

### DataManager

#### 类型定义

```typescript
interface IData {
  id: string
}

// DataManager 类的类型定义
interface DataManager<TData extends IData = IData, TTag extends string = any> {
  // 数据管理器的方法和属性
}
```

#### 构造函数

```typescript
const dataManager = new DataManager<MyData>('my-tag')
```

**参数:**
- `tag`: 数据管理器的标识符

#### 核心方法

##### `init(initialDataList?: TData[]): void`

初始化数据管理器，设置初始数据列表。

```typescript
interface User {
  id: string
  name: string
  age: number
}

const userManager = new DataManager<User>('users')
userManager.init([
  { id: '1', name: 'Alice', age: 25 },
  { id: '2', name: 'Bob', age: 30 }
])
```

##### `getDataList$(): Observable<TData[]>`

获取数据列表的响应式流。

```typescript
userManager.getDataList$().subscribe((users) => {
  console.log('用户列表更新:', users)
})
```

##### `getDataList(): TData[]`

获取当前数据列表。

```typescript
const users = userManager.getDataList()
console.log('当前用户:', users)
```

##### `getData$(id: string, equal?: (a?: TData, b?: TData) => boolean): Observable<TData | undefined>`

获取指定ID数据的响应式流。

```typescript
userManager.getData$('1').subscribe((user) => {
  console.log('用户1数据:', user)
})
```

##### `getData(id: string): TData | undefined`

获取指定ID的数据。

```typescript
const user = userManager.getData('1')
console.log('用户1:', user)
```

##### `dispatch(operation: DataOperation<TData>): void`

分发数据操作。

```typescript
// 添加用户
userManager.dispatch({
  type: 'add',
  data: { id: '3', name: 'Charlie', age: 28 }
})

// 更新用户
userManager.dispatch({
  type: 'update',
  id: '1',
  data: { age: 26 }
})

// 删除用户
userManager.dispatch({
  type: 'remove',
  id: '2'
})

// 批量操作
userManager.dispatch({
  type: 'batch',
  operations: [
    { type: 'add', data: { id: '4', name: 'David', age: 35 } },
    { type: 'update', id: '3', data: { age: 29 } }
  ]
})
```

#### 草稿模式

草稿模式允许你在不影响主数据的情况下进行数据操作。

##### `dispatch` 草稿操作

```typescript
// 开始草稿
userManager.dispatch({
  type: 'startDraft',
  draftId: 'my-draft'
})

// 在草稿中操作
userManager.dispatch({
  type: 'draftOperation',
  draftId: 'my-draft',
  operation: {
    type: 'add',
    data: { id: '5', name: 'Eve', age: 24 }
  }
})

// 提交草稿
userManager.dispatch({
  type: 'commitDraft',
  draftId: 'my-draft'
})

// 或者丢弃草稿
userManager.dispatch({
  type: 'discardDraft',
  draftId: 'my-draft'
})
```

##### `getDraftDataList(draftId: string): TData[] | undefined`

获取草稿中的数据列表。

```typescript
const draftUsers = userManager.getDraftDataList('my-draft')
```

##### `getDraftData(draftId: string, dataId: string): TData | undefined`

获取草稿中的特定数据。

```typescript
const draftUser = userManager.getDraftData('my-draft', '5')
```

##### `dryRun(operation: DataOperation<TData>): Map<string, TData>`

模拟执行操作，返回结果但不实际修改数据。

```typescript
const result = userManager.dryRun({
  type: 'commitDraft',
  draftId: 'my-draft'
})
```

#### 版本控制

DataManager 提供版本控制功能，跟踪数据变更。

```typescript
// 监听版本变更
userManager.patchVersion$.subscribe((version) => {
  console.log('补丁版本:', version)
})

userManager.mapVersion$.subscribe((version) => {
  console.log('映射版本:', version)
})

// 获取当前版本
console.log('当前版本:', userManager.version)
```

#### 操作管道

操作管道允许你在数据操作的不同阶段插入自定义逻辑。

```typescript
interface DataOperationPipe<T extends IData = IData> {
  transform?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
  preOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<DataOperation<T>, DataOperation<T>>
  postOperation?: (operations$: Subject<DataOperation<T>>) => OperatorFunction<
    { dataMap: Map<string, T>, operations: DataOperation<T>[] },
    { dataMap: Map<string, T>, operations: DataOperation<T>[] }
  >
}

// 添加操作管道
const removePipe = userManager.addDataOperationPipe({
  preOperation: () => tap((operation) => {
    console.log('执行操作前:', operation)
  }),
  postOperation: () => tap(({ dataMap, operations }) => {
    console.log('执行操作后:', { dataMap, operations })
  })
})

// 移除管道
removePipe()
```

### DualRelation

#### 类型定义

```typescript
// DualRelation 类的类型定义
interface DualRelation<P, C> {
  // 双向关系的方法和属性
}
```

**泛型参数:**
- `P`: 父节点类型
- `C`: 子节点类型

#### 构造函数

```typescript
interface DualRelationOptions {
  allowEmptyParent?: boolean // 是否允许父节点没有子节点
  historyDepth?: number // 历史变更记录的最大数量
}

const relation = new DualRelation<string, string>({
  allowEmptyParent: true,
  historyDepth: 50
})
```

#### 核心方法

##### `add(parent: P, child: C): void`

添加父子关系。

```typescript
// 创建文件系统关系
const fileSystem = new DualRelation<string, string>()

fileSystem.add('root', 'folder1')
fileSystem.add('root', 'folder2')
fileSystem.add('folder1', 'file1.txt')
fileSystem.add('folder1', 'file2.txt')
fileSystem.add('folder2', 'file3.txt')
```

##### `removeChild(child: C): boolean`

移除子节点及其父关系。

```typescript
const removed = fileSystem.removeChild('file1.txt')
console.log('是否成功移除:', removed)
```

##### `removeParent(parent: P): boolean`

移除父节点及其所有子关系。

```typescript
const removed = fileSystem.removeParent('folder1')
console.log('是否成功移除:', removed)
```

##### `getChildren(parent: P): Set<C>`

获取父节点的所有子节点。

```typescript
const children = fileSystem.getChildren('root')
console.log('root的子节点:', Array.from(children))
```

##### `getParent(child: C): P | undefined`

获取子节点的父节点。

```typescript
const parent = fileSystem.getParent('file1.txt')
console.log('file1.txt的父节点:', parent)
```

##### `getRootParent(node: C): P | C | null`

获取节点的根父节点。

```typescript
const rootParent = fileSystem.getRootParent('file1.txt')
console.log('file1.txt的根父节点:', rootParent)
```

##### `hasRelation(parent: P, child: C): boolean`

检查是否存在父子关系。

```typescript
const exists = fileSystem.hasRelation('folder1', 'file1.txt')
console.log('关系是否存在:', exists)
```

##### `hasCircularReference(): boolean`

检查是否存在循环引用。

```typescript
const hasCircular = fileSystem.hasCircularReference()
console.log('是否存在循环引用:', hasCircular)
```

##### `addSafe(parent: P, child: C): boolean`

安全地添加关系，会检查循环引用。

```typescript
const added = fileSystem.addSafe('file1.txt', 'root') // 会失败，因为会产生循环引用
console.log('是否成功添加:', added)
```

#### 层级管理

##### `getNodeLevel(node: P | C): number`

获取节点的层级。

```typescript
const level = fileSystem.getNodeLevel('file1.txt')
console.log('file1.txt的层级:', level)
```

##### `getDescendants(parent: P, includeSelf?: boolean): Set<C>`

获取父节点的所有后代。

```typescript
const descendants = fileSystem.getDescendants('root', true)
console.log('root的所有后代:', Array.from(descendants))
```

#### 批量操作

```typescript
// 开始批量操作
fileSystem.beginBatch()

// 执行多个操作
fileSystem.add('root', 'folder3')
fileSystem.add('folder3', 'file4.txt')
fileSystem.add('folder3', 'file5.txt')

// 提交批量操作
const hasChanges = fileSystem.commitBatch()
console.log('是否有变更:', hasChanges)

// 或者使用便捷方法
const hasChanges2 = fileSystem.batch(() => {
  fileSystem.add('root', 'folder4')
  fileSystem.add('folder4', 'file6.txt')
})
```

#### 变更历史

```typescript
// 监听版本变更
fileSystem.version.subscribe((version) => {
  console.log('版本:', version)
})

// 获取变更历史
const history = fileSystem.changeHistory
console.log('变更历史:', history)
```

#### 工具方法

```typescript
// 获取所有父节点
const allParents = fileSystem.getAllParents()

// 获取所有子节点
const allChildren = fileSystem.getAllChildren()

// 获取关系数量
const count = fileSystem.size()

// 清空所有关系
fileSystem.clear()
```

## 📁 目录结构

```
packages/data/
├── src/
│   ├── index.ts              # 主要导出文件
│   ├── data-manager.ts       # DataManager 类和相关接口
│   └── dual-relation.ts      # DualRelation 类和相关接口
├── dist/                     # 编译输出目录
├── package.json             # 包配置文件
├── README.md               # 中文文档
├── README.en.md            # 英文文档
├── CHANGELOG.md            # 变更日志
├── build.config.ts         # 构建配置
├── eslint.config.mjs       # ESLint 配置
└── tsconfig.json           # TypeScript 配置
```

### 源代码结构

- **`index.ts`**: 主要的导出文件，导出 DataManager 和 DualRelation
- **`data-manager.ts`**: 包含 DataManager 类的完整实现，提供数据管理功能
- **`dual-relation.ts`**: 包含 DualRelation 类的完整实现，提供双向关系管理功能

## 🔗 相关链接

- [GitHub 仓库](https://github.com/boenfu/knotx)
- [问题反馈](https://github.com/boenfu/knotx/issues)
- [贡献指南](https://github.com/boenfu/knotx/blob/main/CONTRIBUTING.md)

## 📄 许可证

MIT License - 详见 [LICENSE](../../LICENSE) 文件。

## 🤝 贡献

欢迎贡献代码！请查看 [CONTRIBUTING.md](../../CONTRIBUTING.md) 了解详细信息。