Initial commit
This commit is contained in:
417
handler.go
Normal file
417
handler.go
Normal file
@@ -0,0 +1,417 @@
|
||||
package mgoapi
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.basehosts.de/gopackage/mgocrud"
|
||||
"github.com/gin-gonic/gin"
|
||||
mgo "gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
func (api *API) collectionGetOneHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
session := api.DBSession.Copy()
|
||||
defer session.Close()
|
||||
db := session.DB(api.DBName)
|
||||
|
||||
var selector bson.M
|
||||
selectorStr := c.Query("select")
|
||||
if selectorStr != "" {
|
||||
err := bson.UnmarshalJSON([]byte(selectorStr), &selector)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": "select: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
validSelect, err := validateSelect(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
}, m, selector)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "select: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
newM, err := getDocument(c, db, m, validSelect)
|
||||
if err != nil {
|
||||
status := 500
|
||||
if err == mgo.ErrNotFound {
|
||||
status = 404
|
||||
}
|
||||
c.JSON(status, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if i, ok := m.(interface {
|
||||
ProcessResults(*Context, interface{}) error
|
||||
}); ok {
|
||||
// custom select manipulation
|
||||
err := i.ProcessResults(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
}, newM)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, newM)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) collectionGetHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
// we need to make a slice of the correct type, so that custom MarhalJSON functions of slice elements work
|
||||
// []ModelInterface type would not work => bson.M not compatible (results of mgo query)
|
||||
// see: https://stackoverflow.com/questions/25384640/why-golang-reflect-makeslice-returns-un-addressable-value
|
||||
slice := reflect.MakeSlice(
|
||||
reflect.SliceOf(
|
||||
modelTypeOf(m),
|
||||
),
|
||||
0, 0)
|
||||
|
||||
x := reflect.New(slice.Type())
|
||||
x.Elem().Set(slice)
|
||||
|
||||
results := x.Interface()
|
||||
|
||||
session := api.DBSession.Copy()
|
||||
defer session.Close()
|
||||
db := session.DB(api.DBName)
|
||||
|
||||
var filter bson.M
|
||||
filterStr := c.Query("filter")
|
||||
if filterStr != "" {
|
||||
err := bson.UnmarshalJSON([]byte(filterStr), &filter)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": "filter: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
validFilter, err := validateFilter(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
}, m, filter)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "filter: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var selector bson.M
|
||||
setIdent := false
|
||||
|
||||
if c.Query("ident") != "" {
|
||||
selector = m.GetIdentSelector()
|
||||
setIdent = true
|
||||
} else {
|
||||
selectorStr := c.Query("select")
|
||||
if selectorStr != "" {
|
||||
err := bson.UnmarshalJSON([]byte(selectorStr), &selector)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": "select: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
validSelect, err := validateSelect(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
}, m, selector)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": "select: " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
limit, _ := strconv.Atoi(c.Query("limit"))
|
||||
offset, _ := strconv.Atoi(c.Query("offset"))
|
||||
sort := c.QueryArray("sort")
|
||||
if len(sort) <= 0 {
|
||||
sort = c.QueryArray("sort[]")
|
||||
}
|
||||
clearedSort := []string{}
|
||||
for _, s := range sort {
|
||||
if s != "" {
|
||||
clearedSort = append(clearedSort, s)
|
||||
}
|
||||
}
|
||||
|
||||
queryCount := c.Query("count")
|
||||
if queryCount == "1" || strings.ToLower(queryCount) == "true" {
|
||||
count, err := mgocrud.ReadCollectionCount(db, m, validFilter)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
c.Header("X-Results-Count", strconv.Itoa(count))
|
||||
}
|
||||
|
||||
var pipelineModFunc mgocrud.PipelineModifierFunction
|
||||
if i, ok := m.(interface {
|
||||
PipelineModifier(*Context) (mgocrud.PipelineModifierFunction, error)
|
||||
}); ok {
|
||||
pipelineModFunc, err = i.PipelineModifier(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = mgocrud.ReadCollection(db, results, validFilter, validSelect, offset, limit, clearedSort, pipelineModFunc)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if i, ok := m.(interface {
|
||||
ProcessResults(*Context, interface{}) error
|
||||
}); ok {
|
||||
// custom select manipulation
|
||||
err := i.ProcessResults(&Context{
|
||||
API: api,
|
||||
Context: c,
|
||||
DB: db,
|
||||
}, results)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if setIdent {
|
||||
xE := x.Elem() // results slice (of pointer to slice)
|
||||
for i := 0; i < xE.Len(); i++ {
|
||||
resSliceEl := xE.Index(i).Addr().Interface().(mgocrud.ModelInterface)
|
||||
resSliceEl.SetIdent()
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, results)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) collectionPostHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
newM := newModelOf(m).(mgocrud.ModelInterface)
|
||||
if err := c.Bind(newM); err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
session := api.DBSession.Copy()
|
||||
defer session.Close()
|
||||
db := session.DB(api.DBName)
|
||||
|
||||
if err := mgocrud.ValidateObject(db, newM, nil); err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := mgocrud.CreateDocument(db, newM)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, newM)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) collectionPutHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
session := api.DBSession.Copy()
|
||||
defer session.Close()
|
||||
db := session.DB(api.DBName)
|
||||
|
||||
orgM, err := getDocument(c, db, m, nil)
|
||||
if err != nil {
|
||||
status := 500
|
||||
if err == mgo.ErrNotFound {
|
||||
status = 404
|
||||
}
|
||||
c.JSON(status, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
newM := newModelOf(m).(mgocrud.ModelInterface)
|
||||
|
||||
if err := c.Bind(newM); err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// dont allow id in PUT
|
||||
if newM.GetID() != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": "id not allowed in update",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
mapDecoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
ErrorUnused: true,
|
||||
ZeroFields: true,
|
||||
Result: orgM,
|
||||
TagName: "json",
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = mapDecoder.Decode(change)
|
||||
if err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
// apply newM on orgM and record changes for db update
|
||||
changes := bson.M{}
|
||||
newMStruct := reflect.Indirect(reflect.ValueOf(newM))
|
||||
orgMStruct := reflect.Indirect(reflect.ValueOf(orgM))
|
||||
for i := 0; i < newMStruct.NumField(); i++ {
|
||||
field := newMStruct.Field(i)
|
||||
fieldT := newMStruct.Type().Field(i)
|
||||
|
||||
if field.Kind() == reflect.Ptr && !field.IsNil() {
|
||||
// apply naming conventions of mgo for changeset
|
||||
tag := fieldT.Tag.Get("bson")
|
||||
if tag == "" && !strings.Contains(string(fieldT.Tag), ":") {
|
||||
tag = string(fieldT.Tag)
|
||||
}
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
tagFields := strings.Split(tag, ",")
|
||||
tag = tagFields[0]
|
||||
|
||||
fieldName := tag
|
||||
if fieldName == "" {
|
||||
fieldName = strings.ToLower(fieldT.Name)
|
||||
}
|
||||
|
||||
changes[fieldName] = field.Interface()
|
||||
orgMStruct.Field(i).Set(field)
|
||||
}
|
||||
}
|
||||
//spew.Dump(changes)
|
||||
//spew.Dump(orgM)
|
||||
|
||||
if err := mgocrud.ValidateObject(db, orgM, changes); err != nil {
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
//spew.Dump(orgM)
|
||||
err = mgocrud.UpdateDocument(db, orgM, changes)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//spew.Dump(orgM)
|
||||
// reread from db
|
||||
newM, err = getDocument(c, db, orgM, nil)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, newM)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) collectionDeleteHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
session := api.DBSession.Copy()
|
||||
defer session.Close()
|
||||
db := session.DB(api.DBName)
|
||||
|
||||
orgM, err := getDocument(c, db, m, bson.M{"_id": 1})
|
||||
if err != nil {
|
||||
status := 500
|
||||
if err == mgo.ErrNotFound {
|
||||
status = 404
|
||||
}
|
||||
c.JSON(status, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = mgocrud.DeleteDocument(db, orgM)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{"message": "ok"})
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) collectionGetMetaHandler(m mgocrud.ModelInterface) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.JSON(200, getModelMeta(m))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user