# treebark
**Repository Path**: damengde/treebark
## Basic Information
- **Project Name**: treebark
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MulanPSL-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-06-05
- **Last Updated**: 2024-06-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# treebark
## 契机
在我们实际开发中,经常会需要处理“树状结构”的数据,如部门结构,菜单结构,权限结构等。由于这种类型的数据,多用于展示,所以我们通常会使用在数据库中加入“parentId”,然后通过
递归来查询全量的数据。
但随着需求的迭代,很多“树状结构”的数据需要被使用到更多的查询中,比如:需要频繁的查询某个节点的所有子节点,查询某个节点的所有兄弟节点。
这种情况下,“parentId+迭代”就显得不那么友好了。
于是我们开发了treebark,它能用来帮助你,从“parentId+迭代”转变为MPTT!(我们还提供了数据清洗的方法)
## 预排序遍历树算法(MPTT)树
预排序遍历树算法全称是:Modified Preorder Tree Traversal 简称 MPTT。主要应用于层级关系的存储和遍历。
MPTT在遍历的时候很快,但是其他的操作就会变得很慢。对于需要频繁查询,但修改不是很频繁的树状数据结构, 使用MPTT树进行存储,可以让数据查询更为高效。
一棵标准的树结构:

## 约定大于配置
### 字段标签:`bark`
1. 属性:`name`: 字段绑定关系,可选,默认当前字段名首字母小写的形式 ,
2. 属性:`column`: 数据库字段名,可选,默认当前字段名称小写下划线形式
3. 字段关系表:
| name | column | name | type |
|:----------:|:-----------:|:-----:|:-------------:|
| `id` | `id` | 节点id | string or int |
| `parentId` | `parent_id` | 父节点id | string or int |
| `level` | `level` | 节点等级 | int |
| `treeId` | `tree_id` | 树根id | string or int |
| `lft` | `lft` | 节点左序号 | int |
| `rgt` | `rgt` | 节点右序号 | int |
> 注意:name属性是强绑定的,上述表格字段必须全部包含, column属性可任意
#### 示例
1. 满配
```go
type SysDepartModel struct {
Id string `gorm:"primaryKey" bark:"name:id;colum:id" ` // 节点id
ParentId string `gorm:"column:parent_id" bark:"name:parentId;colum:parent_id"` // 父节点id
Level int64 `gorm:"column:level" bark:"name:level;colum:level" ` // 节点等级
TopParentId string `gorm:"column:top_parent_id" bark:"name:treeId;colum:top_parent_id"` // 顶级父节点id
Lft int64 `gorm:"column:lft" bark:"name:lft;colum:lft"` // 左节点序号
Rgt int64 `gorm:"column:rgt" bark:"name:rgt;colum:rgt"` // 右节点序号
}
```
2. 简配
```go
type SysDepartModel struct {
Id string `gorm:"primaryKey" bark:"colum:id" ` // 节点id
ParentId string `gorm:"column:parent_id" ` // 父节点id
Level int64 `gorm:"column:level" ` // 节点等级
TopParentId string `gorm:"column:top_parent_id" bark:"treeId"` // 顶级父节点id
Lft int64 `gorm:"column:lft"` // 左节点序号
Rgt int64 `gorm:"column:rgt"` // 右节点序号
}
```
> 拿TopParentId举例:treebark中的name:treeId是必须指定的,而TopParentId不管怎么转换与treebark都不相同,所以需要指定。
TopParentId驼峰转下划线之后等于top_parent_id,与数据库字段名一致,所以不需要指定column。
## 使用方法
1. 项目引入treebark
```shell
go get gitlab.zhijiasoft.com/golang/treebark.git
```
2. 定义`model` 并绑定bark标签
```go
type SysDepartModel struct {
Id string `gorm:"primaryKey" bark:"colum:id" ` // 节点id
ParentId string `gorm:"column:parent_id" ` // 父节点id
Level int64 `gorm:"column:level" ` // 节点等级
TopParentId string `gorm:"column:top_parent_id" bark:"treeId"` // 顶级父节点id
Lft int64 `gorm:"column:lft"` // 左节点序号
Rgt int64 `gorm:"column:rgt"` // 右节点序号
}
````
3. 创建树`treeService`。其中db类型为`*gorm.DB`。
```go
treeService, err := service.CreateTreeServiceFactory[SysDepartModel,mapper.GORM](db, &SysDepartModel{})
```
### 操作
#### 节点增加
使用`Create`方法可以快速创建节点。需要确保`node`的`ParentId`和`Level`信息正确。如果`Level`=1为空,则将插入一棵新的树的根节点。
```go
err := treeService.Create(node)
```
#### 节点删除
按ID删除方法`DeleteById`
```go
err := manager.DeleteById(19)
```
#### 节点查询
```go
// 查询node节点的所有子孙节点,不包含本身
models, err = treeService.QueryDescendentByParentId(11)
```
#### Rebuild方法
使用场景:
1. 当有节点不是通过`TreeService`中的方法创建,需要修正树中节点的MPTT信息;
2. 当并发处理导致树上的MPTT信息错乱时;
3. 其他任何导致树上MPTT信息不准确,需要修正这些数据时
都可以调用`Rebuild`来修正整个森林,`PartialRebuild`修正特定的树:
```go
err = treeService.Rebuild()
err = treeService.PartialRebuild(treeID)
```
## 后续计划
~~1. 字段映射动态配置,支持在创建`Service`时指定字段映射关系~~
~~2. 字段要求简化,除 `lft`, `rgt` 外,其他字段去除限制~~
3. 查询和创建方法扩展,增加左节点,右节点等插入和查询方法