| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | package iiimport (	"encoding/xml"	"errors"	"fmt"	"log"	"os"	"path/filepath"	"strings"	"golib/v1/features/mlib/mo")type itemInfo struct {	Name     Name        `xml:"Name,attr"` // main.user	Label    string      `xml:"Label,attr"`	Fields   []fieldInfo `xml:"Fields>Field"`	fieldMap map[string]fieldInfo}func (c *itemInfo) Init() {	lstFields := make([]fieldInfo, len(c.Fields))	for idx, field := range c.Fields {		if err := field.init(); err != nil {			log.Panicf("LoadItemInfo.Init: %s -> %s", c.Name, err)		}		lstFields[idx] = field	}	c.Fields = lstFields	fieldMap := make(map[string]fieldInfo, len(c.Fields))	for _, field := range c.Fields {		fieldMap[field.Name] = field	}	c.fieldMap = fieldMap}func (c itemInfo) GetName() Name {	return c.Name}func (c itemInfo) GetLabel() string {	return c.Label}func (c itemInfo) GetField(name string) (Field, error) {	v, ok := c.fieldMap[name]	if !ok {		return nil, fmt.Errorf("unknown_field: %s", name)	}	return v, nil}func (c itemInfo) GetFields() []Field {	field := make([]Field, len(c.Fields))	for i := 0; i < len(c.Fields); i++ {		field[i] = Field(c.Fields[i])	}	return field}func (c itemInfo) GetFieldMap() map[string]Field {	im := make(map[string]Field, len(c.fieldMap))	for k, v := range c.fieldMap {		im[k] = v	}	return im}func (c itemInfo) GetFieldsName() []string {	name := make([]string, 0, len(c.Fields))	for _, f := range c.Fields {		if f.Ignore {			continue		}		name = append(name, f.Name)	}	return name}type fieldInfo struct {	Name    string      `xml:"Name,attr"`	Label   string      `xml:"Label"`	Type    mo.Type     `xml:"Type,attr"`  // Data type	Model   Model       `xml:"Model,attr"` // Format type	Default string      `xml:"Default"`	Ignore  bool        `xml:"Ignore,attr"` // 忽略此字段	Enums   []string    `xml:"Enums>Enum"`	Number  NumberValue `xml:"Number"`	Lookup  Lookup      `xml:"Lookup"`}type NumberValue struct {	Minimum int64 `xml:"Minimum,attr"`	Maximum int64 `xml:"Maximum,attr"`}type Lookup struct {	From      string `xml:"From,attr"`      // 需要关联的表: ums.user	Condition string `xml:"Condition,attr"` // 字段条件: _id	Need      string `xml:"Need,attr"`      // 获取结果中的字段: name	AS        string `xml:"As,attr"`        // 需要生成的字段: _id_name}func (c fieldInfo) GetName() string {	return c.Name}func (c fieldInfo) GetLabel() string {	return c.Label}func (c fieldInfo) GetType() mo.Type {	return c.Type}func (c fieldInfo) GetModel() Model {	return c.Model}func (c fieldInfo) IsIgnore() bool {	return c.Ignore}func (c fieldInfo) GetLookup() (Lookup, bool) {	if c.Lookup.From == "" {		return Lookup{}, false	}	// lookup := mo.D{{	// 	Key: mo.PLookup, Value: mo.D{	// 		{Key: "from", Value: c.Lookup.From},	// 		{Key: "localField", Value: c.Lookup.Need},	// 		{Key: "foreignField", Value: c.Lookup.Condition},	// 		{Key: "as", Value: c.Lookup.AS}},	// }}	return c.Lookup, true}func (c fieldInfo) GetEnums() ([]string, bool) {	return c.Enums, len(c.Enums) == 0}func (c fieldInfo) GetNumber() (min int64, max int64, ok bool) {	return c.Number.Minimum, c.Number.Maximum, c.Number.Minimum != 0 && c.Number.Maximum != 0}func (c fieldInfo) GetDefaultValue() string {	return c.Default}func (c *fieldInfo) init() error {	if c.Name == "" {		return errors.New("Field.Name does not exist")	}	if c.Label == "" {		return errors.New("Field.Label does not exist")	}	// 关联显示	if c.Lookup.From != "" {		// 如果未指定本地字段则使用 Name		if c.Lookup.Need == "" {			c.Lookup.Need = c.Name		}		// 如果未指定远程字段则使用 Name		if c.Lookup.Condition == "" {			c.Lookup.Condition = c.Name		}		if c.Lookup.AS == "" {			c.Lookup.AS = c.Name		}	}	return nil}var (	itemMap = &itemBody{infoMap: map[Name]itemInfo{}})type itemBody struct {	infoMap  map[Name]itemInfo	isLoaded bool}func (c *itemBody) Init(itemInfo map[Name]itemInfo) {	c.infoMap = itemInfo	c.isLoaded = true}func (c itemBody) GetItem(name Name) (Item, bool) {	if info, ok := c.infoMap[name]; ok {		return info, true	}	return itemInfo{}, false}func (c itemBody) IsLoaded() bool {	return c.isLoaded}func GetItemByName(name string) (Item, bool) {	return itemMap.GetItem(NewName(name))}type Name stringfunc (c Name) DbName() string {	if i := strings.Index(c.String(), "."); i != -1 {		return c.String()[:i]	}	return mo.DefaultDbName}func (c Name) CollName() string {	if i := strings.Index(c.String(), "."); i != -1 {		return c.String()[i+1:]	}	return c.String()}func (c Name) String() string {	return string(c)}func (c *Name) UnmarshalXMLAttr(attr xml.Attr) error {	if attr.Value == "" {		return fmt.Errorf("unknown name: %s", attr.Value)	}	*c = Name(attr.Value)	return nil}// NewName 获取包含数据库的集合名称, 例如: main.user// 当不包含 . 时则会补充 MongoDB 默认的数据库 testfunc NewName(name string) Name {	return Name(name)}// LoadItemInfo 初始化func LoadItemInfo(path string) {	if itemMap.IsLoaded() {		return	}	info := make(map[Name]itemInfo, 512)	err := filepath.Walk(path, func(filePath string, f os.FileInfo, err error) error {		if strings.HasSuffix(filePath, ".xml") {			oItemInfo, err := readItemInfoFromXml(filePath)			if err != nil {				return err			}			oItemInfo.Init()			info[oItemInfo.Name] = oItemInfo		}		return nil	})	if err != nil {		panic(err)	}	itemMap.Init(info)}func readItemInfoFromXml(path string) (itemInfo, error) {	content, err := os.ReadFile(path)	if err != nil {		return itemInfo{}, err	}	var oItemInfoCfg itemInfo	return oItemInfoCfg, xml.Unmarshal(content, &oItemInfoCfg)}
 |