Compare commits
11 Commits
Author | SHA1 | Date |
---|---|---|
|
3b130c9d14 | |
|
8409716217 | |
|
368a9e868c | |
|
206932038e | |
|
5c09f1eefc | |
|
0c1c0da166 | |
|
01a671dff8 | |
|
2631943904 | |
|
e85cc0b8ca | |
|
3020468afb | |
|
bb048abbb1 |
11
condition.go
11
condition.go
|
@ -84,9 +84,14 @@ func BuildConditions(ctx context.Context, r *http.Request, query *Query, schemas
|
||||||
}
|
}
|
||||||
//如果是多选的话,直接使用IN操作
|
//如果是多选的话,直接使用IN操作
|
||||||
columnName := row.Column + "[]"
|
columnName := row.Column + "[]"
|
||||||
if qs.Has(columnName) && len(qs[columnName]) > 1 {
|
if qs.Has(columnName) {
|
||||||
query.AndFilterWhere(newConditionWithOperator("IN", row.Column, qs[columnName]))
|
if len(qs[columnName]) > 1 {
|
||||||
continue
|
query.AndFilterWhere(newConditionWithOperator("IN", row.Column, qs[columnName]))
|
||||||
|
continue
|
||||||
|
} else if len(qs[columnName]) == 1 {
|
||||||
|
query.AndFilterWhere(newCondition(row.Column, qs[columnName][0]))
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
formValue = qs.Get(row.Column)
|
formValue = qs.Get(row.Column)
|
||||||
switch row.Format {
|
switch row.Format {
|
||||||
|
|
17
model.go
17
model.go
|
@ -28,6 +28,7 @@ import (
|
||||||
type Model struct {
|
type Model struct {
|
||||||
naming types.Naming //命名规则
|
naming types.Naming //命名规则
|
||||||
value reflect.Value //模块值
|
value reflect.Value //模块值
|
||||||
|
modelValue any //模块实例
|
||||||
db *gorm.DB //数据库
|
db *gorm.DB //数据库
|
||||||
primaryKey string //主键
|
primaryKey string //主键
|
||||||
urlPrefix string //url前缀
|
urlPrefix string //url前缀
|
||||||
|
@ -232,13 +233,17 @@ func (m *Model) ModuleName() string {
|
||||||
|
|
||||||
// TableName 表的名称
|
// TableName 表的名称
|
||||||
func (m *Model) TableName() string {
|
func (m *Model) TableName() string {
|
||||||
return m.naming.ModuleName
|
return m.naming.TableName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Naming() types.Naming {
|
func (m *Model) Naming() types.Naming {
|
||||||
return m.naming
|
return m.naming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) Value() reflect.Value {
|
||||||
|
return m.value
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Model) SetDB(db *gorm.DB) *gorm.DB {
|
func (m *Model) SetDB(db *gorm.DB) *gorm.DB {
|
||||||
m.db = db
|
m.db = db
|
||||||
return m.db
|
return m.db
|
||||||
|
@ -261,12 +266,15 @@ func (m *Model) Fields() []*schema.Field {
|
||||||
// 权限示例: "module.model.scenario"
|
// 权限示例: "module.model.scenario"
|
||||||
// 比如: organize:user:list, organize:user:create
|
// 比如: organize:user:list, organize:user:create
|
||||||
func (m *Model) Permission(scenario string) string {
|
func (m *Model) Permission(scenario string) string {
|
||||||
ss := make([]string, 4)
|
if pm, ok := m.modelValue.(PermissionModel); ok {
|
||||||
|
return pm.GetPermission(scenario)
|
||||||
|
}
|
||||||
|
ss := make([]string, 0, 4)
|
||||||
switch scenario {
|
switch scenario {
|
||||||
case types.ScenarioList:
|
case types.ScenarioList:
|
||||||
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "list")
|
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "list")
|
||||||
case types.ScenarioView:
|
case types.ScenarioView:
|
||||||
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "get")
|
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "detail")
|
||||||
case types.ScenarioCreate:
|
case types.ScenarioCreate:
|
||||||
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "create")
|
ss = append(ss, m.naming.ModuleName, m.naming.Singular, "create")
|
||||||
case types.ScenarioUpdate:
|
case types.ScenarioUpdate:
|
||||||
|
@ -283,7 +291,7 @@ func (m *Model) Permission(scenario string) string {
|
||||||
|
|
||||||
// Uri 获取请求的uri
|
// Uri 获取请求的uri
|
||||||
func (m *Model) Uri(scenario string) string {
|
func (m *Model) Uri(scenario string) string {
|
||||||
ss := make([]string, 4)
|
ss := make([]string, 0, 4)
|
||||||
if m.urlPrefix != "" {
|
if m.urlPrefix != "" {
|
||||||
ss = append(ss, m.urlPrefix)
|
ss = append(ss, m.urlPrefix)
|
||||||
}
|
}
|
||||||
|
@ -1081,6 +1089,7 @@ func newModel(v any, db *gorm.DB, naming types.Naming) *Model {
|
||||||
value: reflect.Indirect(reflect.ValueOf(v)),
|
value: reflect.Indirect(reflect.ValueOf(v)),
|
||||||
valueLookup: defaultValueLookup,
|
valueLookup: defaultValueLookup,
|
||||||
}
|
}
|
||||||
|
model.modelValue = reflect.New(model.value.Type()).Interface()
|
||||||
model.statement = &gorm.Statement{
|
model.statement = &gorm.Statement{
|
||||||
DB: model.getDB(),
|
DB: model.getDB(),
|
||||||
ConnPool: model.getDB().ConnPool,
|
ConnPool: model.getDB().ConnPool,
|
||||||
|
|
|
@ -13,6 +13,7 @@ type options struct {
|
||||||
router types.HttpRouter
|
router types.HttpRouter
|
||||||
writer types.HttpWriter
|
writer types.HttpWriter
|
||||||
permissionChecker types.PermissionChecker
|
permissionChecker types.PermissionChecker
|
||||||
|
valueLookup types.ValueLookupFunc
|
||||||
formatter *Formatter
|
formatter *Formatter
|
||||||
resourceDirectory string
|
resourceDirectory string
|
||||||
}
|
}
|
||||||
|
@ -30,6 +31,7 @@ func (o *options) Clone() *options {
|
||||||
permissionChecker: o.permissionChecker,
|
permissionChecker: o.permissionChecker,
|
||||||
formatter: o.formatter,
|
formatter: o.formatter,
|
||||||
resourceDirectory: o.resourceDirectory,
|
resourceDirectory: o.resourceDirectory,
|
||||||
|
valueLookup: o.valueLookup,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +49,12 @@ func WithUriPrefix(s string) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithValueLookup(f types.ValueLookupFunc) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.valueLookup = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithModuleName 模块名称
|
// WithModuleName 模块名称
|
||||||
func WithModuleName(s string) Option {
|
func WithModuleName(s string) Option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
|
|
113
rest.go
113
rest.go
|
@ -506,15 +506,19 @@ func AutoMigrate(ctx context.Context, model any, cbs ...Option) (modelValue *Mod
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//路由模块处理
|
//路由模块处理
|
||||||
|
singularizeTable := inflector.Singularize(table)
|
||||||
modelValue = newModel(model, opts.db, types.Naming{
|
modelValue = newModel(model, opts.db, types.Naming{
|
||||||
Pluralize: inflector.Pluralize(table),
|
Pluralize: inflector.Pluralize(singularizeTable),
|
||||||
Singular: inflector.Singularize(table),
|
Singular: singularizeTable,
|
||||||
ModuleName: opts.moduleName,
|
ModuleName: opts.moduleName,
|
||||||
TableName: table,
|
TableName: table,
|
||||||
})
|
})
|
||||||
if scenarioModel, ok := model.(types.ScenarioModel); ok {
|
if scenarioModel, ok := model.(types.ScenarioModel); ok {
|
||||||
modelValue.scenarios = scenarioModel.Scenario()
|
modelValue.scenarios = scenarioModel.Scenario()
|
||||||
}
|
}
|
||||||
|
if opts.valueLookup != nil {
|
||||||
|
modelValue.valueLookup = opts.valueLookup
|
||||||
|
}
|
||||||
modelValue.hookMgr = hookMgr
|
modelValue.hookMgr = hookMgr
|
||||||
modelValue.schemaLookup = VisibleSchemas
|
modelValue.schemaLookup = VisibleSchemas
|
||||||
modelValue.permissionChecker = opts.permissionChecker
|
modelValue.permissionChecker = opts.permissionChecker
|
||||||
|
@ -648,63 +652,128 @@ func VisibleSchemas(ctx context.Context, db *gorm.DB, domain, moduleName, tableN
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModelTypes 查询指定模型的类型
|
// ModelTypes 查询指定模型的类型
|
||||||
func ModelTypes(ctx context.Context, db *gorm.DB, model any, domainName, labelColumn, valueColumn string) (values []*types.TypeValue) {
|
func ModelTypes[T any](ctx context.Context, db *gorm.DB, model any, domainName, labelColumn, valueColumn string) (values []*types.TypeValue[T], err error) {
|
||||||
tx := db.WithContext(ctx)
|
tx := db.WithContext(ctx)
|
||||||
result := make([]map[string]any, 0, 10)
|
result := make([]map[string]any, 0, 10)
|
||||||
if domainName == "" {
|
if domainName == "" {
|
||||||
tx.Model(model).Select(labelColumn, valueColumn).Scan(&result)
|
err = tx.Model(model).Select(labelColumn, valueColumn).Scan(&result).Error
|
||||||
} else {
|
} else {
|
||||||
tx.Model(model).Select(labelColumn, valueColumn).Where("domain=?", domainName).Scan(&result)
|
err = tx.Model(model).Select(labelColumn, valueColumn).Where("domain=?", domainName).Scan(&result).Error
|
||||||
}
|
}
|
||||||
values = make([]*types.TypeValue, 0, len(result))
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
values = make([]*types.TypeValue[T], 0, len(result))
|
||||||
for _, pairs := range result {
|
for _, pairs := range result {
|
||||||
feed := &types.TypeValue{}
|
feed := &types.TypeValue[T]{}
|
||||||
for k, v := range pairs {
|
for k, v := range pairs {
|
||||||
if k == labelColumn {
|
if k == labelColumn {
|
||||||
feed.Label = v
|
if s, ok := v.(string); ok {
|
||||||
|
feed.Label = s
|
||||||
|
} else {
|
||||||
|
feed.Label = fmt.Sprint(s)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if k == valueColumn {
|
if k == valueColumn {
|
||||||
feed.Value = v
|
if p, ok := v.(T); ok {
|
||||||
|
feed.Value = p
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
values = append(values, feed)
|
values = append(values, feed)
|
||||||
}
|
}
|
||||||
return values
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelTiers 查询指定模型的层级数据
|
||||||
|
func ModelTiers[T comparable](ctx context.Context, db *gorm.DB, model any, domainName, parentColumn, labelColumn, valueColumn string) (values []*types.TierValue[T], err error) {
|
||||||
|
tx := db.WithContext(ctx)
|
||||||
|
result := make([]map[string]any, 0, 10)
|
||||||
|
if domainName == "" {
|
||||||
|
err = tx.Model(model).Select(parentColumn, labelColumn, valueColumn).Scan(&result).Error
|
||||||
|
} else {
|
||||||
|
err = tx.Model(model).Select(parentColumn, labelColumn, valueColumn).Where("domain=?", domainName).Scan(&result).Error
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
values = make([]*types.TierValue[T], 0, len(result))
|
||||||
|
for _, pairs := range result {
|
||||||
|
feed := &types.TierValue[T]{}
|
||||||
|
for k, v := range pairs {
|
||||||
|
if k == labelColumn {
|
||||||
|
if s, ok := v.(string); ok {
|
||||||
|
feed.Label = s
|
||||||
|
} else {
|
||||||
|
feed.Label = fmt.Sprint(s)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if k == valueColumn {
|
||||||
|
if p, ok := v.(T); ok {
|
||||||
|
feed.Value = p
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if k == parentColumn {
|
||||||
|
if p, ok := v.(T); ok {
|
||||||
|
feed.Parent = p
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values = append(values, feed)
|
||||||
|
}
|
||||||
|
var none T
|
||||||
|
return recursiveTier(none, values), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFieldValue 获取模型某个字段的值
|
// GetFieldValue 获取模型某个字段的值
|
||||||
func GetFieldValue(stmt *gorm.Statement, refValue reflect.Value, column string) interface{} {
|
func GetFieldValue(stmt *gorm.Statement, refValue reflect.Value, column string) any {
|
||||||
var (
|
var (
|
||||||
idx = -1
|
rawField *schema.Field
|
||||||
)
|
)
|
||||||
refVal := reflect.Indirect(refValue)
|
refVal := reflect.Indirect(refValue)
|
||||||
for i, field := range stmt.Schema.Fields {
|
for _, field := range stmt.Schema.Fields {
|
||||||
if field.DBName == column || field.Name == column {
|
if field.DBName == column || field.Name == column {
|
||||||
idx = i
|
rawField = field
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idx > -1 {
|
if rawField == nil {
|
||||||
return refVal.Field(idx).Interface()
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
var targetValue reflect.Value
|
||||||
|
targetValue = refVal
|
||||||
|
for _, i := range rawField.StructField.Index {
|
||||||
|
targetValue = targetValue.Field(i)
|
||||||
|
}
|
||||||
|
return targetValue.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFieldValue 设置模型某个字段的值
|
// SetFieldValue 设置模型某个字段的值
|
||||||
func SetFieldValue(stmt *gorm.Statement, refValue reflect.Value, column string, value any) {
|
func SetFieldValue(stmt *gorm.Statement, refValue reflect.Value, column string, value any) {
|
||||||
var (
|
var (
|
||||||
idx = -1
|
rawField *schema.Field
|
||||||
)
|
)
|
||||||
refVal := reflect.Indirect(refValue)
|
refVal := reflect.Indirect(refValue)
|
||||||
for i, field := range stmt.Schema.Fields {
|
for _, field := range stmt.Schema.Fields {
|
||||||
if field.DBName == column || field.Name == column {
|
if field.DBName == column || field.Name == column {
|
||||||
idx = i
|
rawField = field
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idx > -1 {
|
if rawField == nil {
|
||||||
refVal.Field(idx).Set(reflect.ValueOf(value))
|
return
|
||||||
}
|
}
|
||||||
|
var targetValue reflect.Value
|
||||||
|
targetValue = refVal
|
||||||
|
for _, i := range rawField.StructField.Index {
|
||||||
|
targetValue = targetValue.Field(i)
|
||||||
|
}
|
||||||
|
targetValue.Set(reflect.ValueOf(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SafeSetFileValue 安全设置模型某个字段的值
|
// SafeSetFileValue 安全设置模型某个字段的值
|
||||||
|
|
5
types.go
5
types.go
|
@ -44,6 +44,11 @@ type (
|
||||||
HttpTableName(req *http.Request) string
|
HttpTableName(req *http.Request) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 权限模型定义
|
||||||
|
PermissionModel interface {
|
||||||
|
GetPermission(scenario string) string
|
||||||
|
}
|
||||||
|
|
||||||
//创建后的回调,这个回调不在事物内
|
//创建后的回调,这个回调不在事物内
|
||||||
afterCreated interface {
|
afterCreated interface {
|
||||||
AfterCreated(ctx context.Context, tx *gorm.DB)
|
AfterCreated(ctx context.Context, tx *gorm.DB)
|
||||||
|
|
|
@ -119,16 +119,25 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeValue 键值对数据
|
// TypeValue 键值对数据
|
||||||
TypeValue struct {
|
TypeValue[T any] struct {
|
||||||
Label any `json:"label"`
|
Label string `json:"label"`
|
||||||
Value any `json:"value"`
|
Value T `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//TierValue 层级数据
|
||||||
|
TierValue[T comparable] struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value T `json:"value"`
|
||||||
|
Parent T `json:"-"`
|
||||||
|
Used bool `json:"-"`
|
||||||
|
Children []*TierValue[T] `json:"children"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NestedValue 层级数据
|
// NestedValue 层级数据
|
||||||
NestedValue struct {
|
NestedValue[T any] struct {
|
||||||
Label any `json:"label"`
|
Label string `json:"label"`
|
||||||
Value any `json:"value"`
|
Value T `json:"value"`
|
||||||
Children []*NestedValue `json:"children,omitempty"`
|
Children []*NestedValue[T] `json:"children,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValueLookupFunc 查找域的函数
|
//ValueLookupFunc 查找域的函数
|
||||||
|
@ -240,3 +249,17 @@ type (
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (t *TierValue[T]) HasChild(value T) bool {
|
||||||
|
for _, child := range t.Children {
|
||||||
|
if child.Value == value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(child.Children) > 0 {
|
||||||
|
if child.HasChild(value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
17
utils.go
17
utils.go
|
@ -4,6 +4,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.nobla.cn/golang/rest/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hasToken(hack string, need string) bool {
|
func hasToken(hack string, need string) bool {
|
||||||
|
@ -43,3 +45,18 @@ func isEmpty(val any) bool {
|
||||||
return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
|
return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func recursiveTier[T comparable](parent T, values []*types.TierValue[T]) []*types.TierValue[T] {
|
||||||
|
items := make([]*types.TierValue[T], 0, len(values)/2)
|
||||||
|
for idx, row := range values {
|
||||||
|
if row.Used {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if row.Parent == parent {
|
||||||
|
values[idx].Used = true
|
||||||
|
row.Children = recursiveTier(row.Value, values)
|
||||||
|
items = append(items, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue