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 }