package restlet
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
log "github.com/Sirupsen/logrus"
|
|
"github.com/archsh/go.xql"
|
|
_ "github.com/archsh/go.xql/dialects/postgres"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type CURDKind interface {
|
|
Entity() xql.TableIdentified
|
|
}
|
|
|
|
type CURDTable interface {
|
|
Table() *xql.Table
|
|
}
|
|
|
|
type CURDPreRead interface {
|
|
PreRead(ctx RequestContext, session *xql.Session, url_params Parameters, queries Parameters) (*QueryController, error)
|
|
}
|
|
|
|
type CURDPreCreate interface {
|
|
PreCreate(ctx RequestContext, session *xql.Session, url_params Parameters, queries Parameters, entity interface{}) error
|
|
}
|
|
|
|
type CURDPreUpdate interface {
|
|
PreUpdate(ctx RequestContext, session *xql.Session, url_params Parameters, queries Parameters, columns []xql.UpdateColumn) (*QueryController, []xql.UpdateColumn, error)
|
|
}
|
|
|
|
type CURDPreDelete interface {
|
|
PreDelete(ctx RequestContext, session *xql.Session, url_params Parameters, queries Parameters) (*QueryController, error)
|
|
}
|
|
|
|
type CURDPostRead interface {
|
|
PostRead(ctx RequestContext, session *xql.Session, qc *QueryController, entity interface{}) (interface{}, error)
|
|
}
|
|
|
|
type CURDPostCreate interface {
|
|
PostCreate(ctx RequestContext, session *xql.Session, entity interface{}) (interface{}, error)
|
|
}
|
|
|
|
type CURDPostUpdate interface {
|
|
PostUpdate(ctx RequestContext, session *xql.Session, qc *QueryController, columns []xql.UpdateColumn) ([]xql.UpdateColumn, error)
|
|
}
|
|
|
|
type CURDPostDelete interface {
|
|
PostDelete(ctx RequestContext, session *xql.Session, qc *QueryController) error
|
|
}
|
|
|
|
type CURDOnRead interface {
|
|
OnRead(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error)
|
|
}
|
|
|
|
type CURDOnCreate interface {
|
|
OnCreate(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error)
|
|
}
|
|
|
|
type CURDOnUpdate interface {
|
|
OnUpdate(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error)
|
|
}
|
|
|
|
type CURDOnDelete interface {
|
|
OnDelete(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error)
|
|
}
|
|
|
|
type DefaultCURDHandler struct {
|
|
dbiName string
|
|
table *xql.Table
|
|
entity xql.TableIdentified
|
|
pks []string
|
|
notAllowed []string
|
|
query QueryMaker
|
|
preRead CURDPreRead
|
|
preCreate CURDPreCreate
|
|
preUpdate CURDPreUpdate
|
|
preDelete CURDPreDelete
|
|
postRead CURDPostRead
|
|
postCreate CURDPostCreate
|
|
postUpdate CURDPostUpdate
|
|
postDelete CURDPostDelete
|
|
onRead CURDOnRead
|
|
onCreate CURDOnCreate
|
|
onUpdate CURDOnUpdate
|
|
onDelete CURDOnDelete
|
|
}
|
|
|
|
func (h DefaultCURDHandler) Handle(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
for _, x := range h.notAllowed {
|
|
if strings.ToUpper(x) == ctx.Request().Method {
|
|
return Failure_Response(ERROR_METHOD_NOT_ALLOWED, "Method Not Allowed!")
|
|
}
|
|
}
|
|
switch ctx.Request().Method {
|
|
case "GET":
|
|
if h.onRead != nil {
|
|
return h.onRead.OnRead(ctx, url_params, queries, post_data)
|
|
}
|
|
return h.read(ctx, url_params, queries, post_data)
|
|
case "PATCH":
|
|
if h.onUpdate != nil {
|
|
return h.onUpdate.OnUpdate(ctx, url_params, queries, post_data)
|
|
}
|
|
return h.update(ctx, url_params, queries, post_data)
|
|
case "PUT":
|
|
if h.onUpdate != nil {
|
|
return h.onUpdate.OnUpdate(ctx, url_params, queries, post_data)
|
|
}
|
|
return h.update(ctx, url_params, queries, post_data)
|
|
case "POST":
|
|
if h.onCreate != nil {
|
|
return h.onCreate.OnCreate(ctx, url_params, queries, post_data)
|
|
}
|
|
return h.create(ctx, url_params, queries, post_data)
|
|
case "DELETE":
|
|
if h.onDelete != nil {
|
|
return h.onDelete.OnDelete(ctx, url_params, queries, post_data)
|
|
}
|
|
return h.delete(ctx, url_params, queries, post_data)
|
|
case "OPTIONS":
|
|
return h.options(ctx, url_params, queries, post_data)
|
|
default:
|
|
return Failure_Response(ERROR_METHOD_NOT_ALLOWED, "Method Not Allowed!")
|
|
}
|
|
}
|
|
|
|
func (h DefaultCURDHandler) options(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
result := &RestletResult{}
|
|
result.Model = reflect.TypeOf(h.entity).Name()
|
|
result.Data = h.entity
|
|
return result, nil
|
|
}
|
|
|
|
func (h DefaultCURDHandler) read(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
session := xql.MakeSession(ctx.SQL(h.dbiName), "postgres")
|
|
defer session.Close()
|
|
result := &RestletResult{}
|
|
entityType := reflect.TypeOf(h.entity)
|
|
if val := reflect.ValueOf(h.entity); val.Kind() == reflect.Ptr {
|
|
entityType = val.Elem().Type() //reflect.TypeOf()
|
|
}
|
|
log.Debugln("DefaultCURDHandler.read> ", h.table.TableName, entityType)
|
|
var queryControl *QueryController
|
|
if h.preRead != nil {
|
|
qc, e := h.preRead.PreRead(ctx, session, url_params, queries)
|
|
if nil != e {
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", e))
|
|
}
|
|
queryControl = qc
|
|
} else if qc, err := Build_QueryControl(queries, h.table, h.query); nil != err {
|
|
log.Errorln("DefaultCURDHandler.read:> failure:", err)
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", err))
|
|
} else {
|
|
queryControl = qc
|
|
}
|
|
var pk_mapping = _build_params_map(h.table, url_params, h.pks...)
|
|
if nil != pk_mapping && len(pk_mapping)==len(h.pks) {
|
|
obj := reflect.New(entityType)
|
|
row := session.Query(h.table, queryControl.Includes...).Filter(pk_mapping).One()
|
|
err := row.Scan(obj.Elem().Addr().Interface())
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.read:2> failure:", reflect.TypeOf(err), err)
|
|
return Failure_Response(ERROR_NOT_FOUND, "Record Not Found!")
|
|
}
|
|
result.Data = obj.Elem().Addr().Interface()
|
|
} else {
|
|
for k, v := range url_params {
|
|
f := xql.QueryFilter{Field: k, Operator: "="}
|
|
f.Value = _build_column_query_value(h.table, k, f.Operator, v)
|
|
queryControl.Filters = append(queryControl.Filters, f)
|
|
}
|
|
qs := session.Query(h.table, queryControl.Includes...).Filter(queryControl.Filters...)
|
|
total, err := qs.Count()
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.read:> failure:", err)
|
|
return Failure_Response(FATAL_DB_READ_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
|
|
result.Control = &ControlResult{}
|
|
result.Control.Total = total
|
|
result.Control.Offset = queryControl.Offset
|
|
result.Control.Limit = queryControl.Limit
|
|
qs = qs.Offset(queryControl.Offset).Limit(queryControl.Limit)
|
|
qs = qs.OrderBy(queryControl.OrderBy...)
|
|
rows, err := qs.All()
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.read:> failure:", err)
|
|
return Failure_Response(FATAL_DB_READ_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
defer rows.Close()
|
|
objects := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(entityType)), 0, 0)
|
|
for rows.Next() {
|
|
obj := reflect.New(entityType)
|
|
err = rows.Scan(obj.Elem().Addr().Interface())
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.read:> failure:", err)
|
|
return Failure_Response(FATAL_DB_READ_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
objects = reflect.Append(objects, obj)
|
|
result.Control.Count += 1
|
|
}
|
|
|
|
result.Model = reflect.TypeOf(h.entity).Name()
|
|
result.Data = objects.Interface()
|
|
}
|
|
|
|
if h.postRead != nil {
|
|
if ret, e := h.postRead.PostRead(ctx, session, queryControl, result.Data); nil != e {
|
|
log.Errorln("DefaultCURDHandler.read:> failure:", e)
|
|
return Failure_Response(FATAL_DB_READ_FAILED, fmt.Sprintf("%s", e))
|
|
} else {
|
|
result.Data = ret
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (h DefaultCURDHandler) create(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
entityType := reflect.TypeOf(h.entity)
|
|
if val := reflect.ValueOf(h.entity); val.Kind() == reflect.Ptr {
|
|
entityType = val.Elem().Type() //reflect.TypeOf()
|
|
}
|
|
log.Debugln("DefaultCURDHandler.create> ", h.table.TableName, entityType)
|
|
if nil == post_data || len(post_data) < 1 {
|
|
return Failure_Response(ERROR_INVALID_DATA, "Empty Data!")
|
|
}
|
|
session := xql.MakeSession(ctx.SQL(h.dbiName), "postgres")
|
|
defer session.Close()
|
|
|
|
entityObjs := reflect.MakeSlice(reflect.SliceOf(entityType), 1, 2)
|
|
p := reflect.New(reflect.SliceOf(entityType))
|
|
reflect.Indirect(p).Set(entityObjs)
|
|
if err := json.Unmarshal(post_data, entityObjs.Index(0).Addr().Interface()); nil == err {
|
|
log.Debugln("DefaultCURDHandler.create>>>: Single Object")
|
|
} else if err = json.Unmarshal(post_data, p.Interface()); nil == err {
|
|
log.Debugln("DefaultCURDHandler.create>>>: Slice Objects")
|
|
} else {
|
|
log.Warnln("DefaultCURDHandler.create> Invalid Data:", err)
|
|
return Failure_Response(ERROR_INVALID_DATA, "Invalid Data!")
|
|
}
|
|
var pk_mapping = _build_params_map(h.table, url_params, h.pks...)
|
|
for k, v := range url_params {
|
|
if nil == pk_mapping {
|
|
pk_mapping = make(map[string]interface{})
|
|
pk_mapping[k] = _build_column_query_value(h.table, k, "=", v)
|
|
continue
|
|
}
|
|
if _, ok := pk_mapping[k]; ! ok {
|
|
pk_mapping[k] = _build_column_query_value(h.table, k, "=", v)
|
|
}
|
|
}
|
|
result := &RestletResult{}
|
|
err := session.Begin()
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.create:> failure:", err)
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
//n := 0
|
|
for i := 0; i < entityObjs.Len(); i++ {
|
|
obj := entityObjs.Index(i)
|
|
if nil != pk_mapping {
|
|
_assign_entity_from_map(obj.Addr().Interface(), pk_mapping, false)
|
|
}
|
|
if h.preCreate != nil {
|
|
if e := h.preCreate.PreCreate(ctx, session, url_params, queries, obj.Addr().Interface()); nil != e {
|
|
log.Errorln("DefaultCURDHandler.create> preCreate failed:", e)
|
|
return Failure_Response(ERROR_INVALID_DATA, fmt.Sprintf("%s", e))
|
|
}
|
|
}
|
|
log.Debugln("DefaultCURDHandler.create:> Inserting :", obj.Addr().Interface())
|
|
_, err = session.Query(h.table).Insert(obj.Addr().Interface())
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.create:> failure:", err)
|
|
session.Rollback()
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
}
|
|
result.Data = entityObjs.Interface()
|
|
if h.postCreate != nil {
|
|
if ret, e := h.postCreate.PostCreate(ctx, session, result.Data); nil != e {
|
|
log.Errorln("DefaultCURDHandler.create:> postCreate failed:", e)
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", e))
|
|
} else {
|
|
result.Data = ret
|
|
}
|
|
}
|
|
err = session.Commit()
|
|
if nil != err {
|
|
log.Errorln("DefaultCURDHandler.create:> failure:", err)
|
|
session.Rollback()
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", err))
|
|
}
|
|
result.Code = SUCCESS_CREATED
|
|
return result, nil
|
|
}
|
|
|
|
func (h DefaultCURDHandler) update(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
entityType := reflect.TypeOf(h.entity)
|
|
if val := reflect.ValueOf(h.entity); val.Kind() == reflect.Ptr {
|
|
entityType = val.Elem().Type() //reflect.TypeOf()
|
|
}
|
|
log.Debugln("DefaultCURDHandler.update> ", h.table.TableName, entityType)
|
|
if nil == post_data || len(post_data) < 1 {
|
|
log.Warnln("DefaultCURDHandler.update:> Empty DATA.")
|
|
return Failure_Response(ERROR_INVALID_DATA, "Empty Data!")
|
|
}
|
|
entityObj := reflect.New(entityType)
|
|
var entityMap = make(map[string]interface{})
|
|
err := json.Unmarshal(post_data, entityObj.Elem().Addr().Interface())
|
|
e1 := json.Unmarshal(post_data, &entityMap)
|
|
if nil != err || nil != e1 {
|
|
log.Warnln("DefaultCURDHandler.update:> Invalid DATA:", err, e1)
|
|
return Failure_Response(ERROR_INVALID_DATA, "Invalid Data!")
|
|
}
|
|
for k, _ := range entityMap {
|
|
if _, ok := h.table.GetColumn(k); ok {
|
|
continue
|
|
} else {
|
|
log.Warnln("DefaultCURDHandler.update:> Invalid Field:", k)
|
|
return Failure_Response(ERROR_INVALID_DATA, "Invalid Field:"+k)
|
|
}
|
|
}
|
|
if len(entityMap) == 0 {
|
|
log.Warnln("DefaultCURDHandler.update:> Empty DATA:", err, e1)
|
|
return Failure_Response(ERROR_INVALID_DATA, "Empty Data!")
|
|
}
|
|
session := xql.MakeSession(ctx.SQL(h.dbiName), "postgres")
|
|
defer session.Close()
|
|
var updateCols []xql.UpdateColumn
|
|
for _, c := range h.table.GetColumns() {
|
|
if _, ok := entityMap[c.FieldName]; ok {
|
|
|
|
} else if _, ok := entityMap[c.Jtag]; ok {
|
|
|
|
} else if _, ok := entityMap[c.ElemName]; ok {
|
|
|
|
} else {
|
|
continue
|
|
}
|
|
if c.PrimaryKey {
|
|
return Failure_Response(ERROR_FORBIDDEN, "Not Allowed to Change Primary Key(s).")
|
|
}
|
|
uc := xql.UpdateColumn{Field: c.FieldName, Operator: "="}
|
|
val := entityObj.Elem().FieldByName(c.ElemName)
|
|
switch val.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
uc.Value = val.Int()
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
uc.Value = val.Uint()
|
|
case reflect.String:
|
|
uc.Value = val.String()
|
|
case reflect.Bool:
|
|
uc.Value = val.Bool()
|
|
case reflect.Float32, reflect.Float64:
|
|
uc.Value = val.Float()
|
|
default:
|
|
uc.Value = val.Interface()
|
|
}
|
|
updateCols = append(updateCols, uc)
|
|
}
|
|
var queryControl *QueryController
|
|
if h.preUpdate != nil {
|
|
if qc, cols, e := h.preUpdate.PreUpdate(ctx, session, url_params, queries, updateCols); nil != e {
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", e))
|
|
} else {
|
|
queryControl = qc
|
|
updateCols = cols
|
|
}
|
|
} else {
|
|
if qc, err := Build_QueryControl(queries, h.table, h.query); nil != err {
|
|
log.Errorln("DefaultCURDHandler.update:> failure:", err)
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", err))
|
|
} else {
|
|
queryControl = qc
|
|
}
|
|
}
|
|
if len(updateCols)<1{
|
|
return Failure_Response(ERROR_BAD_REQUEST, "empty update columns...")
|
|
}
|
|
|
|
log.Debugln("DefaultCURDHandler.update> QueryControl:", queryControl)
|
|
var pk_mapping = _build_params_map(h.table, url_params, h.pks...)
|
|
if nil != pk_mapping {
|
|
queryControl.Filters = append(queryControl.Filters, pk_mapping)
|
|
}
|
|
|
|
n, e := session.Query(h.table).Filter(queryControl.Filters...).Update(updateCols)
|
|
if nil != e {
|
|
log.Errorln("DefaultCURDHandler.update:> failure:", e)
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", e))
|
|
}
|
|
if h.postUpdate != nil {
|
|
updateCols, e = h.postUpdate.PostUpdate(ctx, session, queryControl, updateCols)
|
|
if nil != e {
|
|
log.Errorln("DefaultCURDHandler.update:> post update failure:", e)
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprintf("%s", e))
|
|
}
|
|
}
|
|
|
|
var updates = make(map[string]interface{})
|
|
for _, x := range updateCols {
|
|
updates[x.Field] = x.Value
|
|
}
|
|
result := &RestletResult{
|
|
Code: SUCCESS_OK,
|
|
Model: entityType.Name(),
|
|
Data: map[string]interface{}{
|
|
"count": n,
|
|
"updates": updates,
|
|
},
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (h DefaultCURDHandler) delete(ctx RequestContext, url_params Parameters, queries Parameters, post_data []byte) (*RestletResult, error) {
|
|
session := xql.MakeSession(ctx.SQL(h.dbiName), "postgres")
|
|
defer session.Close()
|
|
result := &RestletResult{}
|
|
entityType := reflect.TypeOf(h.entity)
|
|
if val := reflect.ValueOf(h.entity); val.Kind() == reflect.Ptr {
|
|
entityType = val.Elem().Type() //reflect.TypeOf()
|
|
}
|
|
result.Model = reflect.TypeOf(h.entity).Name()
|
|
log.Debugln("DefaultCURDHandler.delete> ", h.table.TableName, entityType)
|
|
var queryControl *QueryController
|
|
if h.preDelete != nil {
|
|
if qc, e := h.preDelete.PreDelete(ctx, session, url_params, queries); nil != e {
|
|
log.Errorln("DefaultCURDHandler.delete:> pre delete failure:", e)
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", e))
|
|
} else {
|
|
queryControl = qc
|
|
}
|
|
|
|
} else {
|
|
if qc, err := Build_QueryControl(queries, h.table, h.query); nil != err {
|
|
log.Errorln("DefaultCURDHandler.delete:> failure:", err)
|
|
return Failure_Response(ERROR_BAD_REQUEST, fmt.Sprintf("%s", err))
|
|
} else {
|
|
queryControl = qc
|
|
}
|
|
}
|
|
var pk_mapping = _build_params_map(h.table, url_params, h.pks...)
|
|
if nil != pk_mapping {
|
|
n, err := session.Query(h.table).Filter(pk_mapping).Delete()
|
|
if nil != err {
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprint(err))
|
|
}
|
|
result.Code = SUCCESS_DELETED
|
|
result.Data = map[string]interface{}{"Deleted": n}
|
|
return result, nil
|
|
}
|
|
for k, v := range url_params {
|
|
f := xql.QueryFilter{Field: k, Operator: "="}
|
|
f.Value = _build_column_query_value(h.table, k, f.Operator, v)
|
|
queryControl.Filters = append(queryControl.Filters, f)
|
|
}
|
|
|
|
if len(queryControl.Filters) < 1 {
|
|
return Failure_Response(ERROR_FORBIDDEN, "Not allowed to delete without conditions!")
|
|
}
|
|
n, err := session.Query(h.table).Filter(queryControl.Filters...).Delete()
|
|
if nil != err {
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprint(err))
|
|
}
|
|
if h.postDelete != nil {
|
|
if e := h.postDelete.PostDelete(ctx, session, queryControl); nil != e {
|
|
return Failure_Response(FATAL_DB_WRITE_FAILED, fmt.Sprint(e))
|
|
}
|
|
}
|
|
result.Code = SUCCESS_OK
|
|
result.Data = map[string]interface{}{"deleted": n}
|
|
return result, nil
|
|
}
|
|
|
|
func NewCURDHandler(dbiname string, kind interface{}, notAllowedMethods ...string) RestletHandler {
|
|
var h = DefaultCURDHandler{dbiName: dbiname, notAllowed: notAllowedMethods}
|
|
if h.dbiName == "" {
|
|
h.dbiName = "default"
|
|
}
|
|
if k, b := kind.(xql.TableIdentified); b {
|
|
h.entity = k
|
|
} else if k, b := kind.(CURDKind); b {
|
|
h.entity = k.Entity()
|
|
} else {
|
|
panic("kind param should at least implement CURDKind or xql.TableIdentified interface!")
|
|
}
|
|
if k, b := kind.(CURDTable); b {
|
|
h.table = k.Table()
|
|
} else {
|
|
h.table = xql.DeclareTable(h.entity)
|
|
}
|
|
for _, x := range h.table.GetPrimaryKeys() {
|
|
h.pks = append(h.pks, x.FieldName)
|
|
}
|
|
if k, b := kind.(QueryMaker); b {
|
|
h.query = k
|
|
}
|
|
if k, b := kind.(CURDPreRead); b {
|
|
h.preRead = k
|
|
}
|
|
if k, b := kind.(CURDPreCreate); b {
|
|
h.preCreate = k
|
|
}
|
|
if k, b := kind.(CURDPreUpdate); b {
|
|
h.preUpdate = k
|
|
}
|
|
if k, b := kind.(CURDPreDelete); b {
|
|
h.preDelete = k
|
|
}
|
|
if k, b := kind.(CURDPostRead); b {
|
|
h.postRead = k
|
|
}
|
|
if k, b := kind.(CURDPostCreate); b {
|
|
h.postCreate = k
|
|
}
|
|
if k, b := kind.(CURDPostUpdate); b {
|
|
h.postUpdate = k
|
|
}
|
|
if k, b := kind.(CURDPostDelete); b {
|
|
h.postDelete = k
|
|
}
|
|
if k, b := kind.(CURDOnRead); b {
|
|
h.onRead = k
|
|
}
|
|
|
|
if k, b := kind.(CURDOnCreate); b {
|
|
h.onCreate = k
|
|
}
|
|
|
|
if k, b := kind.(CURDOnUpdate); b {
|
|
h.onUpdate = k
|
|
}
|
|
|
|
if k, b := kind.(CURDOnDelete); b {
|
|
h.onDelete = k
|
|
}
|
|
|
|
return h
|
|
}
|
|
|
|
func _build_params_map(table *xql.Table, params Parameters, pks ...string) map[string]interface{} {
|
|
var pk_mapping map[string]interface{}
|
|
for i, pk := range pks {
|
|
if v, ok := params.GetString(pk); ok {
|
|
//log.Debugln("_build_params_map:> Pk", i, pk, v)
|
|
if nil == pk_mapping {
|
|
pk_mapping = make(map[string]interface{})
|
|
}
|
|
pk_mapping[table.GetPrimaryKeys()[i].FieldName] =
|
|
_build_column_query_value(table, table.GetPrimaryKeys()[i].FieldName, "=", v)
|
|
//delete(params, pk)
|
|
}
|
|
}
|
|
//if len(pks) > 0 {
|
|
// return pk_mapping
|
|
//}
|
|
//for k, v := range params {
|
|
// if nil == pk_mapping {
|
|
// pk_mapping = make(map[string]interface{})
|
|
// }
|
|
// pk_mapping[k] = _build_column_query_value(table, k, "=", v)
|
|
//}
|
|
return pk_mapping
|
|
}
|
|
|
|
func _assign_entity_from_map(entity interface{}, params map[string]interface{}, recursive bool) error {
|
|
//log.Debugln("_assign_entity_from_map:>>>", entity, params)
|
|
if nil != entity {
|
|
et := reflect.TypeOf(entity)
|
|
ev := reflect.ValueOf(entity)
|
|
for i := 0; i < et.Elem().NumField(); i++ {
|
|
f := et.Elem().Field(i)
|
|
x_tag := strings.Split(f.Tag.Get("xql"), ",")[0]
|
|
if x_tag == "-" {
|
|
continue
|
|
}
|
|
if f.Anonymous && !recursive {
|
|
_assign_entity_from_map(ev.Elem().Field(i).Addr().Interface(), params, true)
|
|
continue
|
|
}
|
|
json_tag := strings.Split(f.Tag.Get("json"), ",")[0]
|
|
var val interface{}
|
|
if v, ok := params[x_tag]; ok {
|
|
//log.Debugln("_assign_entity_from_map:>>>", 1, v)
|
|
val = v
|
|
} else if v, ok := params[json_tag]; ok {
|
|
//log.Debugln("_assign_entity_from_map:>>>", 2, v)
|
|
val = v
|
|
} else if v, ok := params[f.Name]; ok {
|
|
//log.Debugln("_assign_entity_from_map:>>>", 3, v)
|
|
val = v
|
|
} else if v, ok := params[xql.Camel2Underscore(f.Name)]; ok {
|
|
//log.Debugln("_assign_entity_from_map:>>>", 4, v)
|
|
val = v
|
|
} else {
|
|
continue
|
|
}
|
|
fv := ev.Elem().Field(i)
|
|
if fv.IsValid() && fv.CanSet() {
|
|
fv.Set(reflect.ValueOf(val))
|
|
}
|
|
}
|
|
} else {
|
|
panic("Empty pointer of entity!")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func translate_datetime(s string) time.Time {
|
|
if t, e := time.Parse(time.RFC3339Nano, s); nil == e {
|
|
return t
|
|
} else if t, e := time.Parse(time.RFC3339, s); nil == e {
|
|
return t
|
|
} else if t, e := time.Parse("2006-01-02T15:04:05", s); nil == e {
|
|
return t
|
|
} else if t, e := time.Parse("2006-01-02T15:04", s); nil == e {
|
|
return t
|
|
} else if t, e := time.Parse("2006-01-02", s); nil == e {
|
|
return t
|
|
} else if t, e := time.Parse("2006", s); nil == e {
|
|
return t
|
|
} else {
|
|
return time.Time{}
|
|
}
|
|
}
|
|
|
|
func translate_single_value(k reflect.Kind, val string) interface{} {
|
|
switch k {
|
|
case reflect.Bool:
|
|
switch strings.ToLower(val) {
|
|
case "yes", "true", "y", "t", "ok":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case reflect.Int:
|
|
n, _ := strconv.ParseInt(val, 10, 32)
|
|
return int(n)
|
|
case reflect.Int8:
|
|
n, _ := strconv.ParseInt(val, 10, 8)
|
|
return int8(n)
|
|
case reflect.Int16:
|
|
n, _ := strconv.ParseInt(val, 10, 16)
|
|
return int16(n)
|
|
case reflect.Int64:
|
|
n, _ := strconv.ParseInt(val, 10, 64)
|
|
return int64(n)
|
|
case reflect.Uint:
|
|
n, _ := strconv.ParseUint(val, 10, 32)
|
|
return uint(n)
|
|
case reflect.Uint8:
|
|
n, _ := strconv.ParseUint(val, 10, 8)
|
|
return uint8(n)
|
|
case reflect.Uint16:
|
|
n, _ := strconv.ParseUint(val, 10, 16)
|
|
return uint16(n)
|
|
case reflect.Uint64:
|
|
n, _ := strconv.ParseUint(val, 10, 64)
|
|
return uint64(n)
|
|
case reflect.String:
|
|
return val
|
|
case reflect.Float32:
|
|
f, _ := strconv.ParseFloat(val, 32)
|
|
return float32(f)
|
|
case reflect.Float64:
|
|
f, _ := strconv.ParseFloat(val, 64)
|
|
return float64(f)
|
|
case reflect.TypeOf(time.Time{}).Kind():
|
|
t := translate_datetime(val)
|
|
return t
|
|
case reflect.TypeOf(&time.Time{}).Kind():
|
|
t := translate_datetime(val)
|
|
return &t
|
|
default:
|
|
return val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func _build_column_query_value(table *xql.Table, field string, operator string, val string) interface{} {
|
|
if col, b := table.GetColumn(field); !b {
|
|
return val
|
|
} else {
|
|
if col.Type.Kind() == reflect.Slice {
|
|
et := col.Type.Elem()
|
|
vv := reflect.MakeSlice(col.Type, 0, 0)
|
|
for _, x := range strings.Split(val, ",") {
|
|
if x == "" {
|
|
continue
|
|
}
|
|
v := translate_single_value(et.Kind(), x)
|
|
//fmt.Println(">>>>", v,reflect.ValueOf(v))
|
|
vv = reflect.Append(vv, reflect.ValueOf(v))
|
|
//fmt.Println(">>>>",vv)
|
|
}
|
|
return vv.Interface()
|
|
} else if operator == "IN" {
|
|
vv := reflect.MakeSlice(reflect.SliceOf(col.Type), 0, 0)
|
|
for _, x := range strings.Split(val, ",") {
|
|
if x == "" {
|
|
continue
|
|
}
|
|
v := translate_single_value(col.Type.Kind(), x)
|
|
//fmt.Println(">>>>", v,reflect.ValueOf(v))
|
|
vv = reflect.Append(vv, reflect.ValueOf(v))
|
|
//fmt.Println(">>>>",vv)
|
|
}
|
|
return vv.Interface()
|
|
} else {
|
|
return translate_single_value(col.Type.Kind(), val)
|
|
}
|
|
}
|
|
return val
|
|
}
|