123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759 |
- package rest
- import (
- "context"
- "encoding/csv"
- "encoding/json"
- "fmt"
- "path"
- "reflect"
- "strconv"
- "strings"
- "time"
- "git.nspix.com/golang/micro/gateway/http"
- "git.nspix.com/golang/rest/v2/errors"
- "git.nspix.com/golang/rest/v2/internal/inflector"
- lru "github.com/hashicorp/golang-lru"
- "gorm.io/gorm"
- "gorm.io/gorm/clause"
- )
- const (
- HttpAccessDenied = 8004 //拒绝访问
- HttpInvalidPayload = 8002 //请求内容无效
- HttpRequestCallbackFailed = 8003 //执行回调失败
- HttpValidateFailed = 8008 //数据校验失败
- HttpDatabaseQueryFailed = 8010 //查询失败
- HttpDatabaseFindFailed = 8011 //查找失败
- HttpDatabaseCreateFailed = 8012 //创建失败
- HttpDatabaseUpdateFailed = 8013 //更新失败
- HttpDatabaseDeleteFailed = 8014 //删除失败
- HttpDatabaseExportFailed = 8015 //数据导出失败
- HTTPUnknownFailed = 9001 //未知错误
- )
- type DiffAttr struct {
- Column string `json:"column"`
- Label string `json:"label"`
- OldValue interface{} `json:"old_value"`
- NewValue interface{} `json:"new_value"`
- }
- type Entity struct {
- opts *Options
- model Model
- primaryKey string
- reflectValue reflect.Value
- reflectType reflect.Type
- statement *gorm.Statement
- isImplementKvMapping bool
- mappingLabelField string
- mappingValueField string
- singularName string
- pluralizeName string
- scenarios []string
- hooks []Hook
- lruCache *lru.Cache
- createdAt time.Time
- }
- func (e *Entity) ID() string {
- return e.model.TableName() + "@" + e.model.ModuleName()
- }
- func (e *Entity) hasScenario(s string) bool {
- for _, scenario := range e.scenarios {
- if s == scenario {
- return true
- }
- }
- return false
- }
- // callMethod 调用回调函数
- func (e *Entity) callMethod(model interface{}, name string, args ...interface{}) (err error) {
- refVal := reflect.ValueOf(model)
- if refVal.Kind() != reflect.Ptr {
- return
- }
- method := refVal.MethodByName(name)
- //
- if !method.CanAddr() {
- return
- }
- var (
- ok bool
- in []reflect.Value
- out []reflect.Value
- )
- if method.Type().NumIn() == len(args) {
- in = make([]reflect.Value, len(args))
- for i, arg := range args {
- in[i] = reflect.ValueOf(arg)
- }
- out = method.Call(in)
- for _, v := range out {
- if err, ok = v.Interface().(error); ok {
- return
- }
- }
- }
- return
- }
- // getPrimaryKeyValue get reflect model primary value
- func (e *Entity) getPrimaryKeyValue(model interface{}) interface{} {
- if e.statement == nil {
- return nil
- }
- if len(e.statement.Schema.PrimaryFields) > 0 {
- primaryField := e.statement.Schema.PrimaryFields[0]
- refVal := reflect.Indirect(reflect.ValueOf(model))
- val := refVal.FieldByName(primaryField.Name)
- return val.Interface()
- }
- return 0
- }
- //getFieldValue get field value from reflect value
- func (e *Entity) getFieldValue(model reflect.Value, column string) interface{} {
- var (
- name string
- )
- refVal := reflect.Indirect(model)
- for _, field := range e.statement.Schema.Fields {
- if field.DBName == column {
- name = field.Name
- break
- } else if field.Name == column {
- name = column
- break
- }
- }
- if name == "" {
- return nil
- }
- fieldVal := refVal.FieldByName(name)
- return fieldVal.Interface()
- }
- // setFieldValue set reflect field value
- func (e *Entity) setFieldValue(model reflect.Value, column string, value interface{}) {
- var (
- name string
- )
- refVal := reflect.Indirect(model)
- for _, field := range e.statement.Schema.Fields {
- if field.DBName == column {
- name = field.Name
- break
- } else if field.Name == column {
- name = column
- break
- }
- }
- if name == "" {
- return
- }
- fieldVal := refVal.FieldByName(name)
- if fieldVal.CanSet() {
- fieldVal.Set(reflect.ValueOf(value))
- }
- }
- // getScenarioMethod 获取某个场景下HTTP请求方法
- func (e *Entity) getScenarioMethod(scenario string) string {
- var method string
- switch scenario {
- case ScenarioList:
- method = "GET"
- case ScenarioView:
- method = "GET"
- case ScenarioCreate:
- method = "POST"
- case ScenarioUpdate:
- method = "PUT"
- case ScenarioDelete:
- method = "DELETE"
- case ScenarioExport:
- method = "GET"
- }
- return method
- }
- // getScenarioUrl 获取某个场景下HTTP请求的URL
- func (e *Entity) getScenarioUrl(scenario string) string {
- var uri string
- switch scenario {
- case ScenarioList:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.pluralizeName
- case ScenarioView:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
- case ScenarioCreate:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName
- case ScenarioUpdate:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
- case ScenarioDelete:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
- case ScenarioExport:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "-export"
- case ScenarioMapping:
- uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "-mapping"
- }
- return path.Clean(uri)
- }
- // getScenarioHandle 获取某个场景下HTTP请求的处理回调
- func (e *Entity) getScenarioHandle(scenario string) http.HandleFunc {
- var handleFunc http.HandleFunc
- switch scenario {
- case ScenarioList:
- handleFunc = e.actionIndex
- case ScenarioView:
- handleFunc = e.actionView
- case ScenarioCreate:
- handleFunc = e.actionCreate
- case ScenarioUpdate:
- handleFunc = e.actionUpdate
- case ScenarioDelete:
- handleFunc = e.actionDelete
- case ScenarioExport:
- handleFunc = e.actionExport
- case ScenarioMapping:
- handleFunc = e.actionMapping
- }
- return handleFunc
- }
- // prepareConditions 解析查询条件
- func (e *Entity) prepareConditions(ctx *http.Context, query *Query, schemas []*Schema) {
- var (
- err error
- formValue string
- model interface{}
- activeModel FilterColumnInterface
- )
- model = reflect.New(e.reflectType).Interface()
- activeModel, _ = model.(FilterColumnInterface)
- //处理默认的搜索
- for _, schema := range schemas {
- if activeModel != nil {
- if err = activeModel.OnSearchColumn(ctx, query, schema); err != nil {
- continue
- }
- }
- if schema.Native == 0 {
- continue
- }
- formValue = ctx.FormValue(schema.Column)
- switch schema.Format {
- case "string", "text", "textarea":
- if schema.getProperties().Match == MatchExactly {
- query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
- } else {
- query.AndFilterWhere(NewQueryConditionWithOperator("LIKE", schema.Column, formValue))
- }
- case "date", "time", "datetime":
- var sep string
- seps := []byte{',', '/'}
- for _, s := range seps {
- if strings.IndexByte(formValue, s) > -1 {
- sep = string(s)
- }
- }
- if ss := strings.Split(formValue, sep); len(ss) == 2 {
- query.AndFilterWhere(
- NewQueryConditionWithOperator(">=", schema.Column, strings.TrimSpace(ss[0])),
- NewQueryConditionWithOperator("<=", schema.Column, strings.TrimSpace(ss[1])),
- )
- } else {
- query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
- }
- case "duration", "number", "integer", "decimal":
- query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
- default:
- if schema.Type == "string" {
- if schema.getProperties().Match == MatchExactly {
- query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
- } else {
- query.AndFilterWhere(NewQueryConditionWithOperator("LIKE", schema.Column, formValue))
- }
- } else {
- query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
- }
- }
- }
- //处理排序
- sortPar := ctx.FormValue("sort")
- if sortPar != "" {
- sorts := strings.Split(sortPar, ",")
- for _, s := range sorts {
- if s[0] == '-' {
- query.OrderBy(s[1:], "DESC")
- } else {
- if s[0] == '+' {
- query.OrderBy(s[1:], "ASC")
- } else {
- query.OrderBy(s, "ASC")
- }
- }
- }
- }
- }
- // isKvMapping 是否实现键值对结构
- func (e *Entity) isKvMapping() bool {
- return e.isImplementKvMapping
- }
- // getMappingValue 获取映射值
- func (e *Entity) getMappingValue(namespace string) []mappingValue {
- if !e.isKvMapping() {
- return nil
- }
- if v, ok := e.lruCache.Get(namespace + ":mappingValue"); ok {
- return v.([]mappingValue)
- }
- values := make([]mappingValue, 0)
- if err := e.opts.DB.Select(e.mappingLabelField+" AS label", e.mappingValueField+" AS value").Where("namespace=?", namespace).Table(e.model.TableName()).Scan(&values).Error; err == nil {
- e.lruCache.Add(namespace+":mappingValue", values)
- }
- return values
- }
- // invalidMappingValue 删除映射缓存数据
- func (e *Entity) invalidMappingValue(namespace string) {
- e.lruCache.Remove(namespace + ":mappingValue")
- }
- func (e *Entity) invalidCache(namespace string) {
- e.invalidMappingValue(namespace)
- return
- }
- //actionIndex
- func (e *Entity) actionIndex(ctx *http.Context) (err error) {
- var (
- page int
- pageIndex int
- pageSize int
- namespace string
- query *Query
- )
- if !e.hasScenario(ScenarioList) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- namespace = ctx.ParamValue("@namespace")
- page, _ = strconv.Atoi(ctx.FormValue("page"))
- pageSize, _ = strconv.Atoi(ctx.FormValue("pagesize"))
- if pageSize <= 0 {
- pageSize = 15
- }
- pageIndex = page
- if pageIndex > 0 {
- pageIndex--
- }
- sliceValue := reflect.MakeSlice(reflect.SliceOf(e.reflectType), 0, 0)
- models := reflect.New(sliceValue.Type())
- models.Elem().Set(sliceValue)
- query = NewQuery(e.opts.DB)
- searchSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioSearch)
- indexSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioList)
- e.prepareConditions(ctx, query, searchSchemas)
- if e.opts.EnableNamespace {
- query.AndFilterWhere(NewQueryCondition("namespace", namespace))
- }
- query.Offset(pageIndex * pageSize).Limit(pageSize)
- if err = query.All(models.Interface()); err != nil {
- return ctx.Error(HttpDatabaseQueryFailed, err.Error())
- }
- requestCtx := ctx.Request().Context()
- if requestCtx == nil {
- requestCtx = context.Background()
- }
- requestCtx = context.WithValue(requestCtx, "namespace", namespace)
- return ctx.Success(map[string]interface{}{
- "page": page,
- "pageSize": pageSize,
- "totalCount": query.Limit(0).Offset(0).Count(e.model),
- "data": e.opts.Formatter.formatModels(requestCtx, models.Interface(), indexSchemas, e.statement),
- })
- }
- func (e *Entity) actionView(ctx *http.Context) (err error) {
- var (
- model interface{}
- namespace string
- )
- if !e.hasScenario(ScenarioView) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- namespace = ctx.ParamValue("@namespace")
- scenario := ctx.FormValue("scenario")
- idStr := ctx.ParamValue("id")
- model = reflect.New(e.reflectType).Interface()
- conditions := map[string]interface{}{
- e.primaryKey: idStr,
- }
- if e.opts.EnableNamespace {
- conditions["namespace"] = namespace
- }
- if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
- return ctx.Error(HttpDatabaseFindFailed, err.Error())
- }
- if ctx.FormValue("format") != "" {
- //获取指定场景下面的字段进行渲染显示
- var schemas []*Schema
- if scenario == "" {
- schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioView)
- } else {
- schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), scenario)
- }
- requestCtx := ctx.Request().Context()
- if requestCtx == nil {
- requestCtx = context.Background()
- }
- requestCtx = context.WithValue(requestCtx, "namespace", namespace)
- return ctx.Success(e.opts.Formatter.formatModel(requestCtx, model, schemas, e.statement))
- }
- return ctx.Success(model)
- }
- func (e *Entity) actionExport(ctx *http.Context) (err error) {
- var (
- query *Query
- namespace string
- )
- if !e.hasScenario(ScenarioExport) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- namespace = ctx.ParamValue("@namespace")
- sliceValue := reflect.MakeSlice(reflect.SliceOf(e.reflectType), 0, 0)
- models := reflect.New(sliceValue.Type())
- models.Elem().Set(sliceValue)
- query = NewQuery(e.opts.DB)
- searchSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioSearch)
- exportSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioList)
- e.prepareConditions(ctx, query, searchSchemas)
- if e.opts.EnableNamespace {
- query.AndFilterWhere(NewQueryCondition("namespace", namespace))
- }
- if err = query.All(models.Interface()); err != nil {
- return ctx.Error(HttpDatabaseExportFailed, err.Error())
- }
- ctx.Response().Header().Set("Content-Type", "text/csv")
- ctx.Response().Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
- ctx.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", e.singularName))
- requestCtx := ctx.Request().Context()
- if requestCtx == nil {
- requestCtx = context.Background()
- }
- requestCtx = context.WithValue(requestCtx, "namespace", namespace)
- value := e.opts.Formatter.formatModels(requestCtx, models.Interface(), exportSchemas, e.statement)
- writer := csv.NewWriter(ctx.Response())
- ss := make([]string, len(exportSchemas))
- for i, field := range exportSchemas {
- ss[i] = field.Label
- }
- _ = writer.Write(ss)
- if values, ok := value.([]interface{}); ok {
- for _, val := range values {
- row, ok2 := val.(map[string]interface{})
- if !ok2 {
- continue
- }
- for i, field := range exportSchemas {
- if v, ok := row[field.Column]; ok {
- ss[i] = fmt.Sprint(v)
- } else {
- ss[i] = ""
- }
- }
- _ = writer.Write(ss)
- }
- }
- writer.Flush()
- return
- }
- func (e *Entity) actionCreate(ctx *http.Context) (err error) {
- var (
- errTx error
- namespace string
- model interface{}
- schemas []*Schema
- refModel reflect.Value
- diffAttrs = make([]*DiffAttr, 0)
- )
- if !e.hasScenario(ScenarioCreate) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- namespace = ctx.ParamValue("@namespace")
- refModel = reflect.New(e.reflectType)
- model = refModel.Interface()
- if err = ctx.Bind(model); err != nil {
- return ctx.Error(HttpInvalidPayload, err.Error())
- }
- schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioCreate)
- //设置某个字段的值
- e.setFieldValue(refModel, "namespace", namespace)
- //global set field value
- e.setFieldValue(refModel, "CreatedBy", ctx.ParamValue("@uid"))
- e.setFieldValue(refModel, "CreatedDept", ctx.ParamValue("@department"))
- e.setFieldValue(refModel, "UpdatedBy", ctx.ParamValue("@uid"))
- e.setFieldValue(refModel, "UpdatedDept", ctx.ParamValue("@department"))
- if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
- //执行创建前回调函数
- if errTx = e.callMethod(model, "OnBeforeCreateRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //执行保存前回调函数
- if errTx = e.callMethod(model, "OnBeforeSaveRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //创建数据
- if errTx = tx.Create(model).Error; errTx != nil {
- return errTx
- }
- //对比差异数据
- for _, scm := range schemas {
- diffAttrs = append(diffAttrs, &DiffAttr{
- Column: scm.Column,
- Label: scm.Label,
- OldValue: nil,
- NewValue: e.getFieldValue(refModel, scm.Column),
- })
- }
- //执行创建后回调函数
- if errTx = e.callMethod(model, "OnAfterCreateRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //执行保存后回调函数
- if errTx = e.callMethod(model, "OnAfterSaveRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- return errTx
- }); err == nil {
- e.invalidCache(namespace)
- pkVal := e.getPrimaryKeyValue(model)
- if len(e.hooks) > 0 {
- for _, hook := range e.hooks {
- hook.HookAfterCreate(ctx, e.opts.DB, pkVal, model, diffAttrs)
- }
- }
- return ctx.Success(map[string]interface{}{
- "id": pkVal,
- "table": e.model.TableName(),
- "state": "created",
- })
- }
- //form validation
- if validateError, ok := err.(*errors.StructError); ok {
- ctx.Response().Header().Set("Content-Type", "application/json")
- return json.NewEncoder(ctx.Response()).Encode(map[string]interface{}{
- "errno": HttpValidateFailed,
- "result": validateError,
- })
- }
- return ctx.Error(HttpDatabaseCreateFailed, err.Error())
- }
- func (e *Entity) actionUpdate(ctx *http.Context) (err error) {
- var (
- errTx error
- namespace string
- model interface{}
- schemas []*Schema
- refModel reflect.Value
- oldValues = make(map[string]interface{})
- diffs = make(map[string]interface{})
- diffAttrs = make([]*DiffAttr, 0)
- )
- if !e.hasScenario(ScenarioUpdate) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- namespace = ctx.ParamValue("@namespace")
- idStr := ctx.ParamValue("id")
- refModel = reflect.New(e.reflectType)
- model = refModel.Interface()
- //默认设置更新用户
- e.setFieldValue(refModel, "UpdatedBy", ctx.ParamValue("@uid"))
- e.setFieldValue(refModel, "UpdatedDept", ctx.ParamValue("@department"))
- conditions := map[string]interface{}{
- e.primaryKey: idStr,
- }
- if e.opts.EnableNamespace {
- conditions["namespace"] = namespace
- }
- if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
- return ctx.Error(HttpDatabaseFindFailed, err.Error())
- }
- schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioUpdate)
- for _, scm := range schemas {
- oldValues[scm.Column] = e.getFieldValue(refModel, scm.Column)
- }
- if err = ctx.Bind(model); err != nil {
- return ctx.Error(HttpInvalidPayload, err.Error())
- }
- if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
- //更新前回调函数
- if errTx = e.callMethod(model, "OnBeforeUpdateRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //执行保存前回调函数
- if errTx = e.callMethod(model, "OnBeforeSaveRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //对比差异数据
- for _, scm := range schemas {
- v := e.getFieldValue(refModel, scm.Column)
- if oldValues[scm.Column] != v {
- diffs[scm.Column] = v
- diffAttrs = append(diffAttrs, &DiffAttr{
- Column: scm.Column,
- Label: scm.Label,
- OldValue: oldValues[scm.Column],
- NewValue: v,
- })
- }
- }
- //进行局部数据更新
- if len(diffs) > 0 {
- if errTx = tx.Model(model).Updates(diffs).Error; errTx != nil {
- return errTx
- }
- }
- //更新后回调函数
- if errTx = e.callMethod(model, "OnAfterUpdateRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //执行保存后回调函数
- if errTx = e.callMethod(model, "OnAfterSaveRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- return errTx
- }); err == nil {
- e.invalidCache(namespace)
- pkVal := e.getPrimaryKeyValue(model)
- if len(e.hooks) > 0 {
- for _, hook := range e.hooks {
- hook.HookAfterUpdate(ctx, e.opts.DB, pkVal, model, diffAttrs)
- }
- }
- return ctx.Success(map[string]interface{}{
- "id": pkVal,
- "table": e.model.TableName(),
- "state": "updated",
- })
- }
- //form validation
- if validateError, ok := err.(*errors.StructError); ok {
- ctx.Response().Header().Set("Content-Type", "application/json")
- return json.NewEncoder(ctx.Response()).Encode(map[string]interface{}{
- "errno": HttpValidateFailed,
- "result": validateError,
- })
- }
- return ctx.Error(HttpDatabaseUpdateFailed, err.Error())
- }
- func (e *Entity) actionDelete(ctx *http.Context) (err error) {
- var (
- errTx error
- model interface{}
- namespace string
- )
- if !e.hasScenario(ScenarioDelete) {
- return ctx.Error(HttpAccessDenied, "access denied")
- }
- idStr := ctx.ParamValue("id")
- namespace = ctx.ParamValue("@namespace")
- model = reflect.New(e.reflectType).Interface()
- conditions := map[string]interface{}{
- e.primaryKey: idStr,
- }
- if e.opts.EnableNamespace {
- conditions["namespace"] = namespace
- }
- if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
- return ctx.Error(HttpDatabaseFindFailed, err.Error())
- }
- if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
- //删除前回调函数
- if errTx = e.callMethod(model, "OnBeforeDeleteRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- //删除数据
- if errTx = tx.Delete(model).Error; errTx != nil {
- return errTx
- }
- //删除后回调函数
- if errTx = e.callMethod(model, "OnAfterDeleteRequest", []interface{}{ctx, tx, model}); errTx != nil {
- return ctx.Error(HttpRequestCallbackFailed, err.Error())
- }
- return errTx
- }); err == nil {
- e.invalidCache(namespace)
- return ctx.Success(map[string]interface{}{
- "id": e.getPrimaryKeyValue(model),
- "table": e.model.TableName(),
- "state": "deleted",
- })
- } else {
- return ctx.Error(HttpDatabaseDeleteFailed, err.Error())
- }
- }
- func (e *Entity) actionMapping(ctx *http.Context) (err error) {
- namespace := ctx.ParamValue("@namespace")
- return ctx.Success(e.getMappingValue(namespace))
- }
- func newEntity(model Model, opts *Options) *Entity {
- entity := &Entity{
- model: model,
- opts: opts,
- createdAt: time.Now(),
- reflectValue: reflect.Indirect(reflect.ValueOf(model)),
- }
- entity.lruCache, _ = lru.New(50)
- entity.reflectType = entity.reflectValue.Type()
- entity.singularName = inflector.Singularize(model.TableName())
- entity.pluralizeName = inflector.Pluralize(model.TableName())
- val := reflect.New(entity.reflectType).Interface()
- if kvMapping, ok := val.(KvMapping); ok {
- entity.isImplementKvMapping = true
- entity.mappingLabelField = kvMapping.LabelField()
- entity.mappingValueField = kvMapping.ValueField()
- }
- if opts.DB != nil {
- entity.statement = &gorm.Statement{
- DB: opts.DB,
- ConnPool: opts.DB.ConnPool,
- Clauses: map[string]clause.Clause{},
- }
- if err := entity.statement.Parse(model); err != nil {
- panic(err)
- }
- if entity.statement.Schema != nil {
- if entity.statement.Schema.PrimaryFieldDBNames != nil && len(entity.statement.Schema.PrimaryFieldDBNames) > 0 {
- entity.primaryKey = entity.statement.Schema.PrimaryFieldDBNames[0]
- }
- //把字段名称转成成数据库字段
- for _, field := range entity.statement.Schema.Fields {
- if field.Name == entity.mappingValueField {
- entity.mappingValueField = field.DBName
- }
- if field.Name == entity.mappingLabelField {
- entity.mappingLabelField = field.DBName
- }
- }
- }
- }
- return entity
- }
|