| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 | package iiimport (	"errors"	"fmt"	"slices"	"strings"	"git.simanc.com/software/golib/v4/features/mo")var (	errUnknownField     = errors.New("unknown field: ")	errUnknownFieldCall = func(name Name, key string) error {		return errors.Join(errUnknownField, fmt.Errorf("%s.%s", name, key))	})func IsUnknownField(err error) bool {	return errors.Is(err, errUnknownField)}// ItemInfo XML 配置, 每个 XML 应当包含 _id 字段type ItemInfo struct {	Name   Name        `xml:"Name,attr"`	Label  string      `xml:"Label,attr"`	Fields []FieldInfo `xml:"Fields>Field"`	fieldMap  map[string]int	uniqueMap map[string]int // 需要调用 SetUnique 设置唯一键}func (c *ItemInfo) ForkDb(name string) Name {	return NewName(c.Name.DbName(), name)}func (c *ItemInfo) IsUnique(field string) bool {	_, ok := c.uniqueMap[field]	return ok}// prepareInsert 创一个列表, 包含所有 Fields 的 name 和默认值func (c *ItemInfo) prepareInsert(doc mo.D) mo.D {	for _, field := range c.Fields {		idx := slices.IndexFunc(doc, func(ele mo.E) bool {			if ele.Key == field.Name {				return true			}			return false		})		if idx == -1 {			doc = append(doc, mo.E{Key: field.Name, Value: field.DefaultValue()})			continue		}		if field.Name == mo.OID {			if id, ok := doc[idx].Value.(mo.ObjectID); ok && !id.IsZero() {				continue // 如果指定了 _id 并且 _id 有效			}			doc = append(doc, mo.E{Key: field.Name, Value: field.DefaultValue()})		}	}	return doc}// PrepareInsert 准备插入的数据func (c *ItemInfo) PrepareInsert(doc mo.D, u User) (mo.D, error) {	for i, ele := range doc {		field, ok := c.Field(ele.Key)		if !ok {			// 不允许添加配置文件中不存在的字段			return nil, errUnknownFieldCall(c.Name, ele.Key)		}		v, err := field.ConvertWithValidate(ele.Value)		if err != nil {			return nil, err		}		doc[i] = mo.E{Key: field.Name, Value: v}	}	// 填充配置文件中已存在的字段	doc = c.prepareInsert(doc)	if u != nil {		doc = append(doc, mo.E{Key: Creator, Value: u.ID()})	}	doc = append(doc, mo.E{Key: CreationTime, Value: mo.NewDateTime()})	return doc, nil}func (c *ItemInfo) prepareUpdateObject(e *mo.E) (any, error) {	fieldName, subFieldName, ok := strings.Cut(e.Key, ".")	if !ok {		return nil, errUnknownFieldCall(c.Name, e.Key)	}	field, fo := c.Field(fieldName)	if !fo {		return nil, errUnknownFieldCall(c.Name, fieldName)	}	if field.Type != mo.TypeObject {		return nil, errTypeReturn(&field, e.Value)	}	subField, so := field.SubField(subFieldName)	if !so {		return nil, errUnknownFieldCall(c.Name, e.Key)	}	return subField.ConvertWithValidate(e.Value)}func (c *ItemInfo) prepareUpdateArray(e *mo.E) (any, error) {	name := strings.Split(e.Key, ".")	if len(name) < 2 {		return nil, errUnknownFieldCall(c.Name, e.Key)	}	fieldName := name[0]	field, ok := c.Field(fieldName)	if !ok {		return nil, errUnknownFieldCall(c.Name, fieldName)	}	if field.Type != mo.TypeArray {		return nil, errTypeReturn(&field, e.Value)	}	if field.Items == FieldItemsObject {		if len(name) != 3 {			return nil, errUnknownFieldCall(c.Name, e.Key)		}		subFieldName := name[2]		subField, o := field.SubField(subFieldName)		if !o {			return nil, errUnknownFieldCall(c.Name, fieldName+"."+subFieldName)		}		return subField.ConvertWithValidate(e.Value)	} else {		return field.ConvertWithValidate(e.Value)	}}func (c *ItemInfo) PrepareUpdater(updater mo.D, u User) error {	hasSetter := false	for i, ele := range updater {		switch ele.Key {		case mo.OptSet:			resolved, err := c.PrepareUpdate(ele.Value.(mo.D))			if err != nil {				return err			}			updater[i] = mo.E{Key: ele.Key, Value: c.appendUpdateField(resolved, u)}			hasSetter = true		case mo.OptSetOnInsert:			date := ele.Value.(mo.D)			date = append(date, mo.E{Key: CreationTime, Value: mo.NewDateTime()})			updater[i] = mo.E{Key: ele.Key, Value: date}			hasSetter = true		default:			for _, ev := range ele.Value.(mo.D) {				// 对于非 mo.OptSet 类型的更新, 仅判断字段是否存在, 不再为其检测和转换数据类型				if _, ok := c.Field(ev.Key); !ok {					return errUnknownFieldCall(c.Name, ev.Key)				}			}		}	}	if !hasSetter {		updater = append(mo.D{{			Key:   mo.OptSet,			Value: c.appendUpdateField(mo.D{}, u)}},			updater...,		)	}	return nil}// PrepareUpdate 准备更新的数据func (c *ItemInfo) PrepareUpdate(doc mo.D) (mo.D, error) {	var resolved mo.D	for _, e := range doc {		if e.Key == mo.OID {			return nil, fmt.Errorf("_id value can not be update")		}		field, ok := c.Field(e.Key)		if !ok {			switch strings.Count(e.Key, ".") {			case 1:				v, err := c.prepareUpdateObject(&e)				if err != nil {					return nil, err				}				resolved = append(resolved, mo.E{Key: e.Key, Value: v})			case 2:				v, err := c.prepareUpdateArray(&e)				if err != nil {					return nil, err				}				resolved = append(resolved, mo.E{Key: e.Key, Value: v})			default:				return nil, errUnknownFieldCall(c.Name, e.Key)			}		} else {			if field.ReadOnly {				continue			}			v, err := field.ConvertWithValidate(e.Value)			if err != nil {				return nil, err			}			resolved = append(resolved, mo.E{Key: e.Key, Value: v})		}	}	return resolved, nil}func (c *ItemInfo) appendUpdateField(resolved mo.D, u User) mo.D {	if u != nil {		return append(resolved, mo.E{Key: LastUpdater, Value: u.ID()})	}	return append(resolved, mo.E{Key: LastModified, Value: mo.NewDateTime()})}// QueryFilterCheck 检查 key 是否包在 itemName 中, 防止 SQL 注入func (c *ItemInfo) QueryFilterCheck(filter mo.D) error {	for _, ele := range filter {		if strings.ContainsRune(ele.Key, '.') { // 检查子 map 查找			mainKey, subKey, _ := strings.Cut(ele.Key, ".")			mainField, found := c.Field(mainKey)			if !found {				return errUnknownFieldCall(c.Name, mainKey)			}			_, found = mainField.SubField(subKey)			if !found {				return errUnknownFieldCall(c.Name, ele.Key)			}		} else {			if _, found := c.Field(ele.Key); !found {				return errUnknownFieldCall(c.Name, ele.Key)			}		}	}	return nil}// ResolveFilter 从 params 中根据 itemInfo 解析出已知的 filed 与未知的 filed// 对于已知的 filed 会将其值转换为对应类型的数据func (c *ItemInfo) ResolveFilter(params mo.D) (known, unknown mo.D, err error) {	for _, ele := range params {		field, found := c.Field(ele.Key)		if !found {			unknown = append(unknown, ele)			continue		}		val, err := field.Convert(ele.Value)		if err != nil {			return nil, nil, err		}		known = append(known, mo.E{Key: ele.Key, Value: val})	}	return}func (c *ItemInfo) Field(name string) (FieldInfo, bool) {	if field, ok := internalField[name]; ok {		if idx, o := c.fieldMap[name]; o {			return c.Fields[idx], true		}		return field, true	}	idx, ok := c.fieldMap[name]	if !ok {		return FieldInfo{}, false	}	return c.Fields[idx], true}func (c *ItemInfo) FieldType(t mo.Type) []FieldInfo {	fields := make([]FieldInfo, 0)	for _, field := range c.Fields {		if field.Type == t {			fields = append(fields, field)		}	}	return fields}func (c *ItemInfo) getUniques() (ks []string) {	for k := range c.uniqueMap {		ks = append(ks, k)	}	for _, field := range c.Fields {		for k := range field.uniqueMap {			ks = append(ks, k)		}	}	return ks}
 |