package mgoapi import ( "errors" "reflect" "regexp" "strings" "gitbase.de/gopackage/mgocrud/v2" "github.com/gin-gonic/gin" "gopkg.in/mgo.v2/bson" ) func errorObject(err error) bson.M { o := bson.M{"error": err.Error()} if e, ok := err.(*mgocrud.ErrorWithStack); ok { o["stack"] = e.Stack() } return o } func modelTypeOf(m interface{}) reflect.Type { return reflect.TypeOf( reflect.ValueOf(m).Elem().Interface(), ) } func newModelOf(m interface{}) interface{} { return reflect.New( modelTypeOf(m), ).Interface() } func string2ObjectID(id string) (objectID *bson.ObjectId, err error) { defer func() { if r := recover(); r != nil { switch x := r.(type) { case string: err = errors.New(x) case error: err = x default: err = errors.New("unknown panic in: string2ObjectID") } } }() oID := bson.ObjectIdHex(id) return &oID, err } func getStructMeta(s reflect.Type, dontRecurse map[string]bool) []map[string]interface{} { if s.Kind() == reflect.Ptr { s = s.Elem() } numField := s.NumField() meta := make([]map[string]interface{}, 0, numField+3) for i := 0; i < numField; i++ { f := s.Field(i) jsonTag := strings.Split(f.Tag.Get("json"), ",") if jsonTag[0] != "-" { _type := f.Type kind := f.Type.Kind() if kind == reflect.Ptr { _type = _type.Elem() } if f.Anonymous { // embed directly embed := getStructMeta(_type, dontRecurse) meta = append(meta, embed...) } else { fMeta := make(map[string]interface{}) fName := f.Name if jsonTag[0] != "" { fName = jsonTag[0] } fMeta["name"] = fName fType := _type.Name() if fType == "" { fType = _type.String() } //fType = strings.Replace(fType, "*", "", -1) fType = regexp.MustCompile(`\*[a-zA-Z0-9]*\.?`).ReplaceAllString(fType, "") fMeta["type"] = fType kind = _type.Kind() fMeta["kind"] = kind.String() if vT := f.Tag.Get("validator"); vT != "" { fMeta["validator"] = strings.Split(vT, ",") } /* if vT := f.Tag.Get("class"); vT != "" { fMeta["class"] = strings.Split(vT, ",") } if lT := f.Tag.Get("label"); lT != "" { fMeta["label"] = lT } */ if vM := f.Tag.Get("meta"); vM != "" { m := strings.Split(vM, ";") for _, mP := range m { p := strings.Split(mP, "=") if len(p) > 1 { pp := strings.Split(p[1], ",") if len(pp) == 1 { fMeta[p[0]] = pp[0] } else { fMeta[p[0]] = pp } } } } if kind == reflect.Struct && !dontRecurse[fType] { dontRecurse[fType] = true fMeta[kind.String()+"Of"] = getStructMeta(_type, dontRecurse) } else if kind == reflect.Slice && !dontRecurse[fType] { sliceEl := _type.Elem() if sliceEl.Kind() == reflect.Ptr { sliceEl = sliceEl.Elem() } if sliceEl.Kind() == reflect.Struct { dontRecurse[fType] = true fMeta[kind.String()+"Of"] = getStructMeta(sliceEl, dontRecurse) } else { fMeta[kind.String()+"Of"] = sliceEl.String() } } meta = append(meta, fMeta) } } } return meta } func getModelMeta(m mgocrud.ModelInterface) []map[string]interface{} { dontRecurse := map[string]bool{ "Time": true, "ObjectId": true, } modelType := reflect.ValueOf(m).Elem().Type() return getStructMeta(modelType, dontRecurse) } func getDocument(c *gin.Context, db *mgocrud.Database, m mgocrud.ModelInterface, selector bson.M) (mgocrud.ModelInterface, error) { objectID, err := string2ObjectID(c.Param("id")) if err != nil { return nil, err } newM := newModelOf(m).(mgocrud.ModelInterface) newM.SetID(objectID) err = mgocrud.ReadDocument(db, newM, selector) if err != nil { return nil, err } return newM, nil }