tableDB/README.md

145 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# go/tableDB v1.1.8
`tableDB` 是基于 `@go/db` 的高级数据库抽象引擎,支持动态 Schema 管理、身份驱动的行级隔离 (RLS) 以及 ABAC 权限策略。
## 🎯 核心设计理念
- **动态 Schema**: 像操作数据一样操作表和字段,无需手动 SQL 迁移。
- **内置标准字段**: 所有数据表强制且自动携带 5 个标准字段:`id` (全局唯一)、`creator``createTime``updater``updateTime`。系统会自动在插入和更新时维护它们。
- **身份驱动**: 所有操作强制绑定 `userID`,系统基于此自动拦截并填充创建者、更新者。
- **ABAC 权限模型**: 支持 SQL 条件过滤、属性权限及关系继承,替代传统的 Role 体系。
- **极速性能**: 通过内存展平策略实现零 RTT 鉴权,支持 O(1) 字段验证。
## 📦 安装
```bash
go get apigo.cc/go/tableDB
```
## 🛠 API 指南
### 1. 初始化与授权
```go
// 获取未授权实例 (无法直接操作数据),可传入 redis 地址用于分布式 ID 生成
unauth := tableDB.GetDB("sqlite://data.db", logger, "")
// 必须绑定身份后才能使用
app := unauth.Auth("user_123")
sys := unauth.Auth(tableDB.SystemUserID) // 超管权限,绕过所有 RLS
```
### 2. 动态架构管理 (Schema)
```go
// 1. 设置表元数据
sys.SetTable(tableDB.TableSchema{
Name: "orders",
EnableRLS: true, // 开启行级安全拦截
Memo: "业务订单表",
})
// 2. 批量维护字段 (支持动态迁移)
app.Table("orders").SetField(
tableDB.FieldSchema{Name: "title", Type: "v128", IsIndex: true},
tableDB.FieldSchema{Name: "amount", Type: "i"},
tableDB.FieldSchema{Name: "status", Type: "i", IsIndex: true},
)
// 3. 查看有权访问的表
tables, _ := app.Tables()
```
### 3. 数据操作 (CRUD)
```go
table := app.Table("orders")
// 保存数据 (自动填充 creator)
table.Set(map[string]any{"title": "测试订单", "amount": 100})
// 获取单条 (自动进行权限校验)
order, err := table.Get("id_xxx")
// 列表查询 (自动注入过滤条件: creator = userID OR policy_conditions)
list, _ := table.List(map[string]any{"amount >": 50})
// 结构化查询 (支持 Join 和 Select 验证)
res, _ := table.Query(tableDB.QueryRequest{
Select: []string{"id", "title"},
Where: "status = ?",
Args: []any{1},
})
```
### 4. 策略与权限管理 (ABAC)
策略允许用户访问非自己创建的数据。
```go
// 1. 授权策略: 允许 user_A 读取订单,但仅限金额小于 1000 的
sys.SetPolicy(tableDB.PolicySchema{
UserID: "user_A",
Type: "table",
Targets: []string{"orders"},
Action: "read",
Condition: "amount < ?",
ConditionArgs: []any{1000},
})
// 2. 继承策略: manager 继承 clerk 的所有权限
sys.SetPolicy(tableDB.PolicySchema{
UserID: "manager",
Type: "inherit",
Targets: []string{"clerk"},
})
// 3. 自主授权: 对表拥有 'full' 权限的用户,可以给其他人授权该表
manager.SetPolicy(tableDB.PolicySchema{
UserID: "clerk",
Type: "table",
Targets: []string{"orders"},
Action: "read",
})
```
## 🛡 安全契约
1. **隐式隔离**: 只要表开启了 `EnableRLS` 且包含 `creator` 字段,查询将自动限制在用户创建的数据范围内。
2. **零开销拦截**: 鉴权逻辑已下推至 SQL WHERE 层,消除 N+1 查询隐患。
3. **特权保护**: 系统表 `_Table`, `_Field`, `_Policy` 禁止普通用户通过 Table API 直接修改,必须通过专属 API 进行管理。
4. **命名规范**: 全局强制驼峰命名,禁止使用 `json` tag。
## 🔗 Hook 事件 (Hooks)
`tableDB` 提供了一系列 Hook允许开发者在表结构变更或数据更新时注入自定义逻辑缓存同步、消息推送、业务校验等
### 1. 注册 Hook
Hook 需要在 `Auth` 之前,在 `TableDBUnauthorized` 实例上注册。
```go
unauth := tableDB.GetDB("sqlite://data.db", logger, "")
// 监听数据更新 (用于缓存同步)
unauth.Hooks.OnUpdatedRows = func(rows []map[string]any, table *tableDB.TableSchema, fields []tableDB.FieldSchema) {
for _, row := range rows {
fmt.Printf("表 %s 的数据已更新: %v\n", table.Name, row["id"])
}
}
// 数据写入前校验 (返回 error 将中断操作)
unauth.Hooks.OnUpdatingRow = func(row map[string]any, table *tableDB.TableSchema, fields []tableDB.FieldSchema) error {
if table.Name == "orders" && cast.Int(row["amount"]) > 1000000 {
return errors.New("金额过大,需要人工审核")
}
return nil
}
app := unauth.Auth("user_123")
```
### 2. 支持的事件列表
| 事件名 | 触发时机 | 参数说明 |
| :--- | :--- | :--- |
| `OnCreatedTable` | 新表创建后 | `table`: 表架构信息 |
| `OnRemovedTable` | 表被删除后 | `table`: 表架构信息 |
| `OnUpdatedField` | 字段新增或修改后 | `table`: 表架构,`field`: 字段架构 |
| `OnRemovedField` | 字段删除后 | `table`: 表架构,`fieldName`: 字段名 |
| `OnUpdatingRow` | **数据写入前** | `row`: 待写入数据,`table`: 表架构。**返回 error 可拦截写入**。 |
| `OnUpdatedRows` | 数据写入/更新后 | `rows`: 已更新的数据列表(包含完整字段) |
| `OnRemovedRows` | 数据删除后 | `ids`: 已删除的主键列表 |