mgoapi/helper.go

173 lines
3.7 KiB
Go

package mgoapi
import (
"errors"
"reflect"
"regexp"
"strings"
"gitbase.de/gopackage/mgocrud"
"github.com/gin-gonic/gin"
mgo "gopkg.in/mgo.v2"
"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)
for _, e := range embed {
meta = append(meta, e)
}
} 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 *mgo.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
}