feat: 升级 samber/do v1 → v2
This commit is contained in:
+222
-249
@@ -5,21 +5,26 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
"github.com/samber/do"
|
||||
"github.com/samber/do/v2"
|
||||
"github.com/samber/lo"
|
||||
|
||||
"git.fsdpf.net/go/condition"
|
||||
"git.fsdpf.net/go/contracts"
|
||||
"git.fsdpf.net/go/db"
|
||||
"git.fsdpf.net/go/db/engine"
|
||||
"git.fsdpf.net/go/db/exec"
|
||||
"git.fsdpf.net/go/db/exp"
|
||||
"git.fsdpf.net/go/db/schema"
|
||||
"git.fsdpf.net/go/req"
|
||||
)
|
||||
|
||||
// 资源变更事件
|
||||
// ResChangeEventTopic 资源变更事件
|
||||
const ResChangeEventTopic = "res-change-event-topic"
|
||||
|
||||
// 资源变更数据
|
||||
// ResChangeRecordTopic 资源变更数据
|
||||
const ResChangeRecordTopic = "res-change-record-topic"
|
||||
|
||||
type ResChangeEventTopicPayload struct {
|
||||
@@ -37,61 +42,72 @@ type ResChangeRecordTopicPayload struct {
|
||||
New []map[string]any // 新数据
|
||||
}
|
||||
|
||||
// 资源
|
||||
// ResVirtualTableSetup 由 framework-v2 在 sqlite_vtable build tag 下注册到容器。
|
||||
// resource.DB() 通过 do.Invoke 取出后调用,完成 vtab 模块注册和 CREATE VIRTUAL TABLE。
|
||||
// res 提供 Code / Table / Fields 信息,vt 是 ResVirtualTable 的具体实现。
|
||||
type ResVirtualTableSetup func(res Resource) error
|
||||
|
||||
// Resource 资源
|
||||
type Resource struct {
|
||||
container *do.Injector
|
||||
container do.Injector
|
||||
initOnce *sync.Once
|
||||
|
||||
Uuid string `db:"uuid"`
|
||||
PUuid string `db:"pUuid"`
|
||||
Code string `db:"code"`
|
||||
Name string `db:"name"`
|
||||
IsResSystem bool `db:"isSystem"`
|
||||
IsResVirtual bool `db:"isVirtual"`
|
||||
Table string `db:"table"`
|
||||
Primarykey string `db:"primaryKey"`
|
||||
IsHistoryRecord bool `db:"isHistoryRecord"`
|
||||
HistoryCacheMax int `db:"historyCacheMax"`
|
||||
Fields ResFields `db:"fields"`
|
||||
Roles map[string]any `db:"roles"`
|
||||
UpdatedAt string `db:"updated_at"`
|
||||
CreatedAt string `db:"created_at"`
|
||||
Uuid string `db:"uuid"`
|
||||
PUuid string `db:"pUuid"`
|
||||
Code string `db:"code"`
|
||||
Name string `db:"name"`
|
||||
Conn string `db:"conn"`
|
||||
IsResVirtual bool `db:"isVirtual"`
|
||||
Table string `db:"table"`
|
||||
Primarykey string `db:"primaryKey"`
|
||||
HistoryRoles []string `db:"historyRoles"`
|
||||
Fields []ResField `db:"fields"`
|
||||
Roles map[string]any `db:"roles"`
|
||||
UpdatedAt string `db:"updated_at"`
|
||||
CreatedAt string `db:"created_at"`
|
||||
}
|
||||
|
||||
func (this *Resource) InitContainer(container *do.Injector) {
|
||||
func (this *Resource) InitContainer(container do.Injector) {
|
||||
this.container = container
|
||||
this.initOnce = &sync.Once{}
|
||||
}
|
||||
|
||||
// 资源UUID
|
||||
// GetUuid 资源UUID
|
||||
func (this Resource) GetUuid() string {
|
||||
return this.Uuid
|
||||
}
|
||||
|
||||
// 资源CODE
|
||||
// GetCode 资源CODE
|
||||
func (this Resource) GetCode() string {
|
||||
return this.Code
|
||||
}
|
||||
|
||||
// 资源名
|
||||
// GetName 资源名
|
||||
func (this Resource) GetName() string {
|
||||
return this.Name
|
||||
}
|
||||
|
||||
// 主键
|
||||
// GetConn 数据库连接
|
||||
func (this Resource) GetConn() string {
|
||||
return this.Conn
|
||||
}
|
||||
|
||||
// GetPrimarykey 主键
|
||||
func (this Resource) GetPrimarykey() string {
|
||||
return this.Primarykey
|
||||
}
|
||||
|
||||
// 是否虚拟资源
|
||||
// IsVirtual 是否虚拟资源
|
||||
func (this Resource) IsVirtual() bool {
|
||||
return this.IsResVirtual
|
||||
}
|
||||
|
||||
// 是否系统资源
|
||||
// IsSystem 是否系统资源
|
||||
func (this Resource) IsSystem() bool {
|
||||
return this.IsResSystem
|
||||
return this.Conn == "service-support"
|
||||
}
|
||||
|
||||
// 资源字段
|
||||
// GetFields 资源字段
|
||||
func (this Resource) GetFields() (result []req.ResField) {
|
||||
for _, item := range this.Fields {
|
||||
result = append(result, item)
|
||||
@@ -99,137 +115,145 @@ func (this Resource) GetFields() (result []req.ResField) {
|
||||
return result
|
||||
}
|
||||
|
||||
// 资源字段
|
||||
// GetField 资源字段
|
||||
func (this Resource) GetField(code string) (req.ResField, bool) {
|
||||
return lo.Find(this.GetFields(), func(v req.ResField) bool {
|
||||
return v.GetCode() == code
|
||||
})
|
||||
}
|
||||
|
||||
// 判断资源字段
|
||||
// HasField 判断资源字段
|
||||
func (this Resource) HasField(code string) bool {
|
||||
return lo.SomeBy(this.GetFields(), func(v req.ResField) bool {
|
||||
return v.GetCode() == code
|
||||
})
|
||||
}
|
||||
|
||||
// 开启事物
|
||||
func (this Resource) BeginTransaction() (*db.Transaction, error) {
|
||||
return this.GetDBConn().BeginTransaction()
|
||||
// BeginTransaction 开启事物
|
||||
func (this Resource) BeginTransaction() (*db.TxDatabase, error) {
|
||||
return this.DB().Begin()
|
||||
}
|
||||
|
||||
// 获取资源链接
|
||||
func (this Resource) GetDBConn() *db.Connection {
|
||||
db := do.MustInvoke[db.DB](this.container)
|
||||
// DB 获取资源链接
|
||||
func (this Resource) DB() *db.Database {
|
||||
dbEngine := do.MustInvoke[engine.Engine](this.container)
|
||||
conn := dbEngine.Connection(this.Conn)
|
||||
|
||||
if this.IsSystem() {
|
||||
return db.Connection("service-support")
|
||||
}
|
||||
|
||||
return db.Connection("default")
|
||||
}
|
||||
|
||||
// 获取资源对应的数据库连接
|
||||
func (this Resource) GetDBBuilder() *db.Builder {
|
||||
return this.GetDBConn().Query()
|
||||
}
|
||||
|
||||
// 获取资源对应的数据表
|
||||
func (this Resource) GetTable() db.Expression {
|
||||
if this.IsVirtual() {
|
||||
return db.Raw("(" + this.Table + ")")
|
||||
}
|
||||
|
||||
return db.Raw(this.Table)
|
||||
}
|
||||
|
||||
func (this Resource) GetDBDriver() string {
|
||||
return this.GetDBConn().GetConfig().Driver
|
||||
}
|
||||
|
||||
func (this Resource) GetAuthDBTable(u req.User, params ...any) *db.Builder {
|
||||
builder := this.GetDBTable(append(params, u)...)
|
||||
|
||||
// 数据权限过滤
|
||||
builder.Before(func(b *db.Builder, t string, data ...map[string]any) {
|
||||
if t == db.TYPE_SELECT || t == db.TYPE_UPDATE || t == db.TYPE_DELETE {
|
||||
this.WithRolesCondition(b, t, u)
|
||||
}
|
||||
})
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// GetDBTable("Test", contracts.User)
|
||||
func (this Resource) GetDBTable(params ...any) *db.Builder {
|
||||
builder := this.GetDBBuilder()
|
||||
|
||||
var user req.User
|
||||
alias := this.Code
|
||||
|
||||
for _, param := range params {
|
||||
switch v := param.(type) {
|
||||
case *db.Transaction:
|
||||
builder.Tx = v
|
||||
case string:
|
||||
alias = v
|
||||
case req.User:
|
||||
user = v
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化数据库存储数据
|
||||
builder.Before(func(b *db.Builder, t string, data ...map[string]any) {
|
||||
if t == db.TYPE_UPDATE {
|
||||
// 格式化保存数据
|
||||
this.formatSaveValue(data[0])
|
||||
}
|
||||
if t == db.TYPE_INSERT {
|
||||
// 移除 table alias
|
||||
b.Table(string(this.GetTable()))
|
||||
for i := 0; i < len(data); i++ {
|
||||
// 格式化保存数据
|
||||
this.formatSaveValue(data[i])
|
||||
// 填充保存数据
|
||||
this.fillSaveValue(data[i], user, db.TYPE_INSERT)
|
||||
if isLocalDB(conn.Dialect()) && !this.IsResVirtual && this.Table != "" && this.initOnce != nil {
|
||||
this.initOnce.Do(func() {
|
||||
if err := this.autoCreateTable(conn); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 资源事件
|
||||
this.onResEvent(builder)
|
||||
|
||||
// 用户事件
|
||||
if this.IsHistoryRecord {
|
||||
this.onUserEvent(builder, user)
|
||||
})
|
||||
}
|
||||
|
||||
// 虚拟资源暂时不考虑鉴权
|
||||
if !this.IsVirtual() {
|
||||
// 返回鉴权后的 DB Builder
|
||||
// return
|
||||
// vtable 资源:查询走 engine 中的 :memory: 连接("__"+Conn),
|
||||
// 原文件连接仅用于 _vtab_cache 持久化,两者互不阻塞。
|
||||
if conn.Dialect() == "vtable" && this.Table != "" && this.initOnce != nil {
|
||||
memConn := dbEngine.Connection("__" + this.Conn)
|
||||
this.initOnce.Do(func() {
|
||||
if err := this.autoSetupVtab(memConn); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
return memConn
|
||||
}
|
||||
|
||||
return builder.Table(string(this.GetTable()), alias)
|
||||
return conn
|
||||
}
|
||||
|
||||
func (this Resource) WithRolesCondition(b *db.Builder, t string, u req.User) error {
|
||||
// autoSetupVtab 通过容器获取 ResVirtualTableSetup(由 framework-v2 在 sqlite_vtable tag 下注册),
|
||||
// 再从 App 取出当前资源对应的 ResVirtualTable 实现,完成 vtab 注册和 CREATE VIRTUAL TABLE。
|
||||
func (this Resource) autoSetupVtab(conn *db.Database) error {
|
||||
_, err := conn.Exec(fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS %s USING %s_mod()`, this.Table, this.Table))
|
||||
return err
|
||||
}
|
||||
|
||||
// autoCreateTable 自动创建数据表
|
||||
func (this Resource) autoCreateTable(conn *db.Database) error {
|
||||
sb := schema.New(conn)
|
||||
return sb.Create(this.Table, func(bp *schema.Blueprint) {
|
||||
bp.Comment = this.Name
|
||||
for _, field := range this.Fields {
|
||||
field.ToBlueprint(bp)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GetTable 获取资源对应的数据表
|
||||
func (this Resource) GetTable() exp.LiteralExpression {
|
||||
if this.IsResVirtual {
|
||||
return db.L("(" + this.Table + ")")
|
||||
}
|
||||
return db.V(db.T(this.Table))
|
||||
}
|
||||
|
||||
// GetDBTable 获取资源对应的数据库连接
|
||||
func (this Resource) GetDBTable(u req.User, opts ...req.ResOption) (sd *db.SelectDataset) {
|
||||
if u == nil {
|
||||
panic("GetDBTable: user cannot be nil")
|
||||
}
|
||||
|
||||
op := &req.ResOptions{}
|
||||
|
||||
for _, cb := range opts {
|
||||
cb(op)
|
||||
}
|
||||
|
||||
alias := this.GetCode()
|
||||
|
||||
if op.Alias != "" {
|
||||
alias = op.Alias
|
||||
}
|
||||
|
||||
sd = this.DB().From(this.GetTable().As(alias))
|
||||
|
||||
if op.Tx != nil {
|
||||
sd = op.Tx.From(this.GetTable().As(alias))
|
||||
}
|
||||
|
||||
sd.WithHook(&ResourceHooks{res: this, u: u, tx: op.Tx})
|
||||
|
||||
return sd
|
||||
}
|
||||
|
||||
func (this Resource) GetRolesCondition(u req.User) (*db.SelectDataset, db.Expression) {
|
||||
isFullRight := false
|
||||
isFullNot := false
|
||||
|
||||
if u == nil {
|
||||
u = GetAnonymous()
|
||||
}
|
||||
|
||||
// 如果是系统用户, 则不做校验
|
||||
if u.Uuid() == "ffffffff-ffff-ffff-ffff-ffffffffffff" {
|
||||
return nil, nil
|
||||
}
|
||||
// 这里不能放在 u.Uuid() == "ffffffff-ffff-ffff-ffff-ffffffffffff" 前面
|
||||
// 会导致初始化数据时循环依赖
|
||||
GetResRoles, err := do.Invoke[GetResRoles](this.container)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
items := GetResRoles(this.GetUuid(), u.Roles()...)
|
||||
|
||||
if len(items) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
GetResource := do.MustInvoke[contracts.GetResource](this.container)
|
||||
NewOrm := do.MustInvoke[contracts.NewOrm](this.container)
|
||||
NewOrmModel := do.MustInvoke[contracts.NewOrmModel](this.container)
|
||||
NewOrmJoin := do.MustInvoke[contracts.NewOrmJoin](this.container)
|
||||
|
||||
GetResRelationResource := do.MustInvoke[GetResRelationResource](this.container)
|
||||
GetResRelations := do.MustInvoke[GetResRelations](this.container)
|
||||
GetResource := do.MustInvoke[contracts.GetResource](this.container)
|
||||
GetOrmConditions := do.MustInvoke[contracts.GetOrmConditions](this.container)
|
||||
|
||||
items := do.MustInvoke[GetResRoles](this.container)(this.GetUuid(), u.Roles()...)
|
||||
|
||||
subTables := lo.Reduce(items, func(carry string, item ResRole, _ int) string {
|
||||
db := this.GetDBBuilder().Table(string(this.GetTable()), this.GetCode()).Select(db.Raw("distinct `" + this.GetCode() + "`.*"))
|
||||
sub := lo.Reduce(items, func(carry *db.SelectDataset, item ResRole, _ int) *db.SelectDataset {
|
||||
sd := this.DB().From(this.GetTable().As(this.GetCode())).Select(db.T(this.GetCode()).All())
|
||||
|
||||
joins := lo.Filter(GetResRelations(item.Uuid), func(item ResRelation, _ int) bool {
|
||||
return item.Type == "inner" || item.Type == "left" || item.Type == "right"
|
||||
@@ -249,106 +273,52 @@ func (this Resource) WithRolesCondition(b *db.Builder, t string, u req.User) err
|
||||
// 关联扩展条件
|
||||
join.SetCondition(GetOrmConditions(joins[i].Uuid, condition.Describe("关联扩展条件")))
|
||||
|
||||
join.Inject(db, NewOrmModel(rResource, rResource.GetCode(), rResource.GetName()))
|
||||
join.Inject(sd, NewOrmModel(rResource, rResource.GetCode(), rResource.GetName()))
|
||||
}
|
||||
|
||||
conditions := GetOrmConditions(item.Uuid, condition.Describe("关联扩展条件"))
|
||||
|
||||
if len(joins) == 0 && conditions.IsEmpty() {
|
||||
// 无权限, 直接跳过这个 unoin 语句
|
||||
if carry != "" {
|
||||
if carry != nil {
|
||||
return carry
|
||||
}
|
||||
// 第一个无权限除外, 避免所有用户所属角色都是无权限
|
||||
db.WhereRaw("false")
|
||||
sd = sd.Where(db.V(false))
|
||||
isFullNot = true
|
||||
} else if len(joins) == 0 && conditions.IsNotEmpty() && conditions.IsAlwaysRight() /* 1=1 的这种条件*/ {
|
||||
// 只要有1个满权限, 直接返回单条语句
|
||||
isFullRight = true
|
||||
return db.ToSql()
|
||||
return sd
|
||||
} else if conditions.IsNotEmpty() {
|
||||
oOrm := NewOrm(this, nil)
|
||||
oOrm.SetGlobalParams(req.NewGlobalParam("{}", u))
|
||||
oOrm.SetGlobalParams(req.NewGlobalParams("{}", u))
|
||||
|
||||
db.Where(conditions.ToSql(oOrm.GetModel()))
|
||||
sd = sd.Where(conditions.ToSql(oOrm.GetModel()))
|
||||
|
||||
// 如果前面是无权限的sql查看, 这直接返回本次查询
|
||||
if isFullNot {
|
||||
isFullNot = false
|
||||
return db.ToSql()
|
||||
return sd
|
||||
}
|
||||
}
|
||||
|
||||
if carry != "" {
|
||||
carry += " UNION "
|
||||
if carry != nil {
|
||||
return carry.Union(sd)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s(%s)", carry, db.ToSql())
|
||||
}, "")
|
||||
return sd
|
||||
}, nil)
|
||||
|
||||
if isFullRight {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if isFullNot {
|
||||
b.WhereRaw("false")
|
||||
} else if subTables != "" {
|
||||
if t == db.TYPE_SELECT {
|
||||
b.FromSub(subTables, b.TableAlias)
|
||||
} else {
|
||||
b.WhereRaw(fmt.Sprintf(
|
||||
"`%s`.`id` in (SELECT `temp`.`id` FROM (%s) as `temp`)",
|
||||
lo.Ternary(b.TableAlias != "", b.TableAlias, this.GetCode()),
|
||||
subTables,
|
||||
))
|
||||
}
|
||||
return nil, db.V(false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 格式化保存数据
|
||||
func (this Resource) formatSaveValue(data map[string]any) {
|
||||
//
|
||||
for k, v := range data {
|
||||
if k == "id" || k == "created_user" || k == "created_at" || k == "deleted_at" || k == "updated_at" {
|
||||
delete(data, k)
|
||||
} else if val, ok := v.(db.Expression); ok {
|
||||
data[k] = val
|
||||
} else if field, ok := this.GetField(k); ok {
|
||||
data[k] = field.ToValue(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 填充保存数据
|
||||
func (this Resource) fillSaveValue(data map[string]any, u req.User, t string) {
|
||||
for _, field := range this.GetFields() {
|
||||
fCode := field.GetCode()
|
||||
|
||||
if fCode == "id" || fCode == "created_user" || fCode == "created_at" || fCode == "deleted_at" || fCode == "updated_at" || fCode == "owned_user" {
|
||||
continue
|
||||
}
|
||||
|
||||
// 只有新增默认字段
|
||||
if _, ok := data[fCode]; !ok {
|
||||
data[fCode] = field.GetRawDefault(this.GetDBDriver())
|
||||
}
|
||||
}
|
||||
|
||||
// 拥有者
|
||||
if _, ok := data["owned_user"]; !ok {
|
||||
data["owned_user"] = u.Uuid()
|
||||
}
|
||||
// 创建者
|
||||
data["created_user"] = u.Uuid()
|
||||
if this.GetDBDriver() == "sqlite" {
|
||||
// 更新时间
|
||||
// sqlite 不能自动更新时间, "DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
|
||||
data["updated_at"] = db.Raw("CURRENT_TIMESTAMP")
|
||||
} else {
|
||||
|
||||
}
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
func (this Resource) GetStruct(extends ...reflect.StructField) any {
|
||||
@@ -379,67 +349,66 @@ func (this Resource) GetSliceStruct(extends ...reflect.StructField) any {
|
||||
return reflect.New(st).Interface()
|
||||
}
|
||||
|
||||
// 资源事件
|
||||
func (this Resource) onResEvent(builder *db.Builder) {
|
||||
builder.After(func(b *db.Builder, t string, result sql.Result, err error, data ...map[string]any) {
|
||||
if err != nil || t == db.TYPE_SELECT {
|
||||
return
|
||||
} else if num, err := result.RowsAffected(); num == 0 || err != nil {
|
||||
return
|
||||
}
|
||||
// onResEvent 资源事件
|
||||
func (this Resource) onResEvent(t string, result sql.Result) {
|
||||
if num, err := result.RowsAffected(); num == 0 || err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 有些地方可能没有注册 contracts.Queue
|
||||
if qu, err := do.Invoke[contracts.Queue](this.container); err == nil {
|
||||
// 全局触发器
|
||||
// 1. 清除系统缓存
|
||||
if err := do.MustInvoke[contracts.Queue](this.container).Publish(ResChangeEventTopic, ResChangeEventTopicPayload{
|
||||
if err := qu.Publish(ResChangeEventTopic, ResChangeEventTopicPayload{
|
||||
Type: t,
|
||||
Res: this,
|
||||
Result: result,
|
||||
}); err != nil {
|
||||
log.Println("Queue Publish Err:", ResChangeEventTopic, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 用户事件
|
||||
func (this Resource) onUserEvent(builder *db.Builder, user req.User) {
|
||||
old := []map[string]any{}
|
||||
// onUserEvent 用户事件
|
||||
func (this Resource) onUserEvent(builder exec.QueryExecutor, user req.User) {
|
||||
// old := []map[string]any{}
|
||||
|
||||
builder.Before(func(b *db.Builder, t string, data ...map[string]any) {
|
||||
if t != db.TYPE_UPDATE && t != db.TYPE_DELETE {
|
||||
return
|
||||
}
|
||||
// 查询保存之前的数据
|
||||
if _, err := b.Get(&old); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
// builder.Before(func(b *db.Builder, t string, data ...map[string]any) {
|
||||
// if t != db.TYPE_UPDATE && t != db.TYPE_DELETE {
|
||||
// return
|
||||
// }
|
||||
// // 查询保存之前的数据
|
||||
// if _, err := b.Get(&old); err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// })
|
||||
|
||||
builder.After(func(b *db.Builder, t string, result sql.Result, err error, data ...map[string]any) {
|
||||
if err != nil || t == db.TYPE_SELECT {
|
||||
return
|
||||
} else if num, err := result.RowsAffected(); num == 0 || err != nil {
|
||||
return
|
||||
}
|
||||
// builder.After(func(b *db.Builder, t string, result sql.Result, err error, data ...map[string]any) {
|
||||
// if err != nil || t == db.TYPE_SELECT {
|
||||
// return
|
||||
// } else if num, err := result.RowsAffected(); num == 0 || err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
if user == nil {
|
||||
user = GetAnonymous()
|
||||
}
|
||||
// if user == nil {
|
||||
// user = GetAnonymous()
|
||||
// }
|
||||
|
||||
// 触发消息队列
|
||||
if err := do.MustInvoke[contracts.Queue](this.container).Publish(ResChangeRecordTopic, ResChangeRecordTopicPayload{
|
||||
Type: t,
|
||||
User: user,
|
||||
Res: this,
|
||||
Old: old,
|
||||
New: data,
|
||||
Result: result,
|
||||
}); err != nil {
|
||||
log.Println("Queue Publish Err:", ResChangeRecordTopic, err)
|
||||
}
|
||||
})
|
||||
// // 触发消息队列
|
||||
// if err := do.MustInvoke[contracts.Queue](this.container).Publish(ResChangeRecordTopic, ResChangeRecordTopicPayload{
|
||||
// Type: t,
|
||||
// User: user,
|
||||
// Res: this,
|
||||
// Old: old,
|
||||
// New: data,
|
||||
// Result: result,
|
||||
// }); err != nil {
|
||||
// log.Println("Queue Publish Err:", ResChangeRecordTopic, err)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
func NewVirtualResource(pRes req.Resource, code, name, sql string, fields []ResField) req.Resource {
|
||||
func NewVirtualResource(pRes req.Resource, code, name string, sd *db.SelectDataset, fields []ResField) req.Resource {
|
||||
fieldsCopy := make([]ResField, len(fields))
|
||||
|
||||
copy(fieldsCopy, fields)
|
||||
@@ -448,17 +417,21 @@ func NewVirtualResource(pRes req.Resource, code, name, sql string, fields []ResF
|
||||
fieldsCopy[i].CodeResource = code
|
||||
}
|
||||
|
||||
sql, _, err := sd.WithDialect(pRes.DB().Dialect()).ToSQL()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &Resource{
|
||||
Uuid: code,
|
||||
PUuid: pRes.GetUuid(),
|
||||
Code: code,
|
||||
Name: name,
|
||||
IsResVirtual: true,
|
||||
IsResSystem: pRes.IsSystem(),
|
||||
Table: sql,
|
||||
IsHistoryRecord: false,
|
||||
HistoryCacheMax: 0,
|
||||
Fields: fieldsCopy,
|
||||
Roles: nil,
|
||||
Uuid: code,
|
||||
PUuid: pRes.GetUuid(),
|
||||
Code: code,
|
||||
Name: name,
|
||||
IsResVirtual: true,
|
||||
Conn: pRes.GetConn(),
|
||||
Table: sql,
|
||||
Fields: fieldsCopy,
|
||||
Roles: nil,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user