res_field.go/res_field_option.go(字段定义)、res_query_field.go/res_query_field_option.go(查询字段)、res_change_row.go(变更行)、res_mask_field.go(字段脱敏标记)及对应测试文件,配合此前已提交的 resource.go/res_interceptor.go 组成完整的 resx 资源实现包。
127 lines
4.0 KiB
Go
127 lines
4.0 KiB
Go
package resx
|
||
|
||
import (
|
||
"database/sql"
|
||
|
||
"github.com/samber/lo"
|
||
|
||
"git.fsdpf.net/go/db"
|
||
"git.fsdpf.net/go/reflux"
|
||
"git.fsdpf.net/go/req"
|
||
)
|
||
|
||
// ResEventType 资源操作类型:读(SELECT)+ 写(INSERT/UPDATE/DELETE)
|
||
type ResEventType string
|
||
|
||
const (
|
||
ResEventSelect ResEventType = "SELECT"
|
||
ResEventInsert ResEventType = "INSERT"
|
||
ResEventUpdate ResEventType = "UPDATE"
|
||
ResEventDelete ResEventType = "DELETE"
|
||
)
|
||
|
||
// ResChangeEvent 描述一次写操作触发的变更:类型、资源、用户、操作结果,不对应具体某一行数据。
|
||
// 只对应写操作,Type() 恒为 INSERT/UPDATE/DELETE 之一,不会是 ResEventSelect。
|
||
type ResChangeEvent interface {
|
||
Type() ResEventType // INSERT | UPDATE | DELETE
|
||
Res() req.Resource // 触发这次变更的资源
|
||
User() req.User // 触发这次变更的用户
|
||
Result() sql.Result // 本次写操作的执行结果
|
||
}
|
||
|
||
// resChangeEvent 是 ResChangeEvent 的具体实现
|
||
type resChangeEvent struct {
|
||
typ ResEventType
|
||
res req.Resource
|
||
user req.User
|
||
result sql.Result
|
||
}
|
||
|
||
func (e resChangeEvent) Type() ResEventType { return e.typ }
|
||
func (e resChangeEvent) Res() req.Resource { return e.res }
|
||
func (e resChangeEvent) User() req.User { return e.user }
|
||
func (e resChangeEvent) Result() sql.Result { return e.result }
|
||
|
||
// NewResChangeEvent 构造一个 ResChangeEvent
|
||
func NewResChangeEvent(typ ResEventType, res req.Resource, u req.User, result sql.Result) ResChangeEvent {
|
||
return resChangeEvent{typ: typ, res: res, user: u, result: result}
|
||
}
|
||
|
||
// ResChangeRow 描述一次资源写操作中某一行的变更内容。只对应写操作,Type() 恒为
|
||
// INSERT/UPDATE/DELETE 之一,不会是 ResEventSelect。
|
||
type ResChangeRow interface {
|
||
Type() ResEventType // INSERT | UPDATE | DELETE
|
||
Res() req.Resource // 触发这次变更的资源
|
||
User() req.User // 触发这次变更的用户
|
||
ID() int64 // 行主键(INSERT 时也是已经算好的自增 id)
|
||
Old() reflux.R // 变更前快照,INSERT 时为 reflux.Nil
|
||
New() reflux.R // 本次写入值,DELETE 时为 reflux.Nil
|
||
Cur() reflux.R // Old 与 New 合并后的视图(New 覆盖 Old 同名字段)
|
||
// Tx 与原始写操作共享的事务,仅当调用方要写入的资源与原始资源使用同一个数据库连接时才可复用。
|
||
Tx() *db.TxDatabase
|
||
}
|
||
|
||
type resChangeRow struct {
|
||
typ ResEventType
|
||
res req.Resource
|
||
user req.User
|
||
id int64
|
||
old map[string]any
|
||
new map[string]any
|
||
tx *db.TxDatabase
|
||
}
|
||
|
||
func (r resChangeRow) Type() ResEventType { return r.typ }
|
||
func (r resChangeRow) Res() req.Resource { return r.res }
|
||
func (r resChangeRow) User() req.User { return r.user }
|
||
func (r resChangeRow) ID() int64 { return r.id }
|
||
func (r resChangeRow) Tx() *db.TxDatabase { return r.tx }
|
||
|
||
func (r resChangeRow) Old() reflux.R {
|
||
if len(r.old) == 0 {
|
||
return reflux.Nil
|
||
}
|
||
return reflux.New(r.old)
|
||
}
|
||
|
||
func (r resChangeRow) New() reflux.R {
|
||
if len(r.new) == 0 {
|
||
return reflux.Nil
|
||
}
|
||
return reflux.New(r.new)
|
||
}
|
||
|
||
func (r resChangeRow) Cur() reflux.R {
|
||
if len(r.old) == 0 && len(r.new) == 0 {
|
||
return reflux.Nil
|
||
}
|
||
return reflux.New(lo.Assign(r.old, r.new))
|
||
}
|
||
|
||
// ResChangeRowOption 用于设置 NewResChangeRow 里非必填的字段
|
||
type ResChangeRowOption func(r *resChangeRow)
|
||
|
||
// WithOld 设置变更前快照,不设置则为 reflux.Nil
|
||
func WithOld(old map[string]any) ResChangeRowOption {
|
||
return func(r *resChangeRow) { r.old = old }
|
||
}
|
||
|
||
// WithNew 设置本次写入值,不设置则为 reflux.Nil
|
||
func WithNew(new map[string]any) ResChangeRowOption {
|
||
return func(r *resChangeRow) { r.new = new }
|
||
}
|
||
|
||
// WithTx 设置与原始写操作共享的事务,不设置则为 nil
|
||
func WithTx(tx *db.TxDatabase) ResChangeRowOption {
|
||
return func(r *resChangeRow) { r.tx = tx }
|
||
}
|
||
|
||
// NewResChangeRow 构造一个 ResChangeRow
|
||
func NewResChangeRow(typ ResEventType, res req.Resource, u req.User, id int64, opts ...ResChangeRowOption) ResChangeRow {
|
||
r := resChangeRow{typ: typ, res: res, user: u, id: id}
|
||
for _, opt := range opts {
|
||
opt(&r)
|
||
}
|
||
return r
|
||
}
|