entity.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. package rest
  2. import (
  3. "context"
  4. "encoding/csv"
  5. "encoding/json"
  6. "fmt"
  7. "path"
  8. "reflect"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "git.nspix.com/golang/micro/gateway/http"
  13. "git.nspix.com/golang/rest/v2/errors"
  14. "git.nspix.com/golang/rest/v2/internal/inflector"
  15. lru "github.com/hashicorp/golang-lru"
  16. "gorm.io/gorm"
  17. "gorm.io/gorm/clause"
  18. )
  19. const (
  20. HttpAccessDenied = 8004
  21. HttpInvalidPayload = 8002
  22. HttpRequestCallbackFailed = 8003
  23. HttpValidateFailed = 8008
  24. HttpDatabaseQueryFailed = 8010
  25. HttpDatabaseFindFailed = 8011
  26. HttpDatabaseCreateFailed = 8012
  27. HttpDatabaseUpdateFailed = 8013
  28. HttpDatabaseDeleteFailed = 8014
  29. HttpDatabaseExportFailed = 8015
  30. )
  31. type DiffAttr struct {
  32. Column string `json:"column"`
  33. Label string `json:"label"`
  34. OldValue interface{} `json:"old_value"`
  35. NewValue interface{} `json:"new_value"`
  36. }
  37. type Entity struct {
  38. opts *Options
  39. model Model
  40. primaryKey string
  41. reflectValue reflect.Value
  42. reflectType reflect.Type
  43. statement *gorm.Statement
  44. isImplementKvMapping bool
  45. mappingLabelField string
  46. mappingValueField string
  47. singularName string
  48. pluralizeName string
  49. scenarios []string
  50. hooks []Hook
  51. lruCache *lru.Cache
  52. createdAt time.Time
  53. }
  54. func (e *Entity) ID() string {
  55. return e.model.TableName() + "@" + e.model.ModuleName()
  56. }
  57. func (e *Entity) hasScenario(s string) bool {
  58. for _, scenario := range e.scenarios {
  59. if s == scenario {
  60. return true
  61. }
  62. }
  63. return false
  64. }
  65. // callMethod 调用回调函数
  66. func (e *Entity) callMethod(model interface{}, name string, args ...interface{}) (err error) {
  67. refVal := reflect.ValueOf(model)
  68. if refVal.Kind() != reflect.Ptr {
  69. return
  70. }
  71. method := refVal.MethodByName(name)
  72. //
  73. if !method.CanAddr() {
  74. return
  75. }
  76. var (
  77. ok bool
  78. in []reflect.Value
  79. out []reflect.Value
  80. )
  81. if method.Type().NumIn() == len(args) {
  82. in = make([]reflect.Value, len(args))
  83. for i, arg := range args {
  84. in[i] = reflect.ValueOf(arg)
  85. }
  86. out = method.Call(in)
  87. for _, v := range out {
  88. if err, ok = v.Interface().(error); ok {
  89. return
  90. }
  91. }
  92. }
  93. return
  94. }
  95. // getPrimaryKeyValue get reflect model primary value
  96. func (e *Entity) getPrimaryKeyValue(model interface{}) interface{} {
  97. if e.statement == nil {
  98. return nil
  99. }
  100. if len(e.statement.Schema.PrimaryFields) > 0 {
  101. primaryField := e.statement.Schema.PrimaryFields[0]
  102. refVal := reflect.Indirect(reflect.ValueOf(model))
  103. val := refVal.FieldByName(primaryField.Name)
  104. return val.Interface()
  105. }
  106. return 0
  107. }
  108. //getFieldValue get field value from reflect value
  109. func (e *Entity) getFieldValue(model reflect.Value, column string) interface{} {
  110. var (
  111. name string
  112. )
  113. refVal := reflect.Indirect(model)
  114. for _, field := range e.statement.Schema.Fields {
  115. if field.DBName == column {
  116. name = field.Name
  117. break
  118. } else if field.Name == column {
  119. name = column
  120. break
  121. }
  122. }
  123. if name == "" {
  124. return nil
  125. }
  126. fieldVal := refVal.FieldByName(name)
  127. return fieldVal.Interface()
  128. }
  129. // setFieldValue set reflect field value
  130. func (e *Entity) setFieldValue(model reflect.Value, column string, value interface{}) {
  131. var (
  132. name string
  133. )
  134. refVal := reflect.Indirect(model)
  135. for _, field := range e.statement.Schema.Fields {
  136. if field.DBName == column {
  137. name = field.Name
  138. break
  139. } else if field.Name == column {
  140. name = column
  141. break
  142. }
  143. }
  144. if name == "" {
  145. return
  146. }
  147. fieldVal := refVal.FieldByName(name)
  148. if fieldVal.CanSet() {
  149. fieldVal.Set(reflect.ValueOf(value))
  150. }
  151. }
  152. // getScenarioMethod 获取某个场景下HTTP请求方法
  153. func (e *Entity) getScenarioMethod(scenario string) string {
  154. var method string
  155. switch scenario {
  156. case ScenarioList:
  157. method = "GET"
  158. case ScenarioView:
  159. method = "GET"
  160. case ScenarioCreate:
  161. method = "POST"
  162. case ScenarioUpdate:
  163. method = "PUT"
  164. case ScenarioDelete:
  165. method = "DELETE"
  166. case ScenarioExport:
  167. method = "GET"
  168. }
  169. return method
  170. }
  171. // getScenarioUrl 获取某个场景下HTTP请求的URL
  172. func (e *Entity) getScenarioUrl(scenario string) string {
  173. var uri string
  174. switch scenario {
  175. case ScenarioList:
  176. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.pluralizeName
  177. case ScenarioView:
  178. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
  179. case ScenarioCreate:
  180. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName
  181. case ScenarioUpdate:
  182. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
  183. case ScenarioDelete:
  184. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "/:id"
  185. case ScenarioExport:
  186. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "-export"
  187. case ScenarioMapping:
  188. uri = e.opts.Prefix + "/" + e.model.ModuleName() + "/" + e.singularName + "-mapping"
  189. }
  190. return path.Clean(uri)
  191. }
  192. // getScenarioHandle 获取某个场景下HTTP请求的处理回调
  193. func (e *Entity) getScenarioHandle(scenario string) http.HandleFunc {
  194. var handleFunc http.HandleFunc
  195. switch scenario {
  196. case ScenarioList:
  197. handleFunc = e.actionIndex
  198. case ScenarioView:
  199. handleFunc = e.actionView
  200. case ScenarioCreate:
  201. handleFunc = e.actionCreate
  202. case ScenarioUpdate:
  203. handleFunc = e.actionUpdate
  204. case ScenarioDelete:
  205. handleFunc = e.actionDelete
  206. case ScenarioExport:
  207. handleFunc = e.actionExport
  208. case ScenarioMapping:
  209. handleFunc = e.actionMapping
  210. }
  211. return handleFunc
  212. }
  213. // prepareConditions 解析查询条件
  214. func (e *Entity) prepareConditions(ctx *http.Context, query *Query, schemas []*Schema) {
  215. var (
  216. err error
  217. formValue string
  218. model interface{}
  219. activeModel FilterColumnInterface
  220. )
  221. model = reflect.New(e.reflectType).Interface()
  222. activeModel, _ = model.(FilterColumnInterface)
  223. //处理默认的搜索
  224. for _, schema := range schemas {
  225. if activeModel != nil {
  226. if err = activeModel.OnSearchColumn(ctx, query, schema); err != nil {
  227. continue
  228. }
  229. }
  230. if schema.Native == 0 {
  231. continue
  232. }
  233. formValue = ctx.FormValue(schema.Column)
  234. switch schema.Format {
  235. case "string", "text", "textarea":
  236. if schema.getProperties().Match == MatchExactly {
  237. query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
  238. } else {
  239. query.AndFilterWhere(NewQueryConditionWithOperator("LIKE", schema.Column, formValue))
  240. }
  241. case "date", "time", "datetime":
  242. var sep string
  243. seps := []byte{',', '/'}
  244. for _, s := range seps {
  245. if strings.IndexByte(formValue, s) > -1 {
  246. sep = string(s)
  247. }
  248. }
  249. if ss := strings.Split(formValue, sep); len(ss) == 2 {
  250. query.AndFilterWhere(
  251. NewQueryConditionWithOperator(">=", schema.Column, strings.TrimSpace(ss[0])),
  252. NewQueryConditionWithOperator("<=", schema.Column, strings.TrimSpace(ss[1])),
  253. )
  254. } else {
  255. query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
  256. }
  257. case "duration", "number", "integer", "decimal":
  258. query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
  259. default:
  260. if schema.Type == "string" {
  261. if schema.getProperties().Match == MatchExactly {
  262. query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
  263. } else {
  264. query.AndFilterWhere(NewQueryConditionWithOperator("LIKE", schema.Column, formValue))
  265. }
  266. } else {
  267. query.AndFilterWhere(NewQueryCondition(schema.Column, formValue))
  268. }
  269. }
  270. }
  271. //处理排序
  272. sortPar := ctx.FormValue("sort")
  273. if sortPar != "" {
  274. sorts := strings.Split(sortPar, ",")
  275. for _, s := range sorts {
  276. if s[0] == '-' {
  277. query.OrderBy(s[1:], "DESC")
  278. } else {
  279. if s[0] == '+' {
  280. query.OrderBy(s[1:], "ASC")
  281. } else {
  282. query.OrderBy(s, "ASC")
  283. }
  284. }
  285. }
  286. }
  287. }
  288. // isKvMapping 是否实现键值对结构
  289. func (e *Entity) isKvMapping() bool {
  290. return e.isImplementKvMapping
  291. }
  292. // getMappingValue 获取映射值
  293. func (e *Entity) getMappingValue(namespace string) []mappingValue {
  294. if !e.isKvMapping() {
  295. return nil
  296. }
  297. if v, ok := e.lruCache.Get(namespace + ":mappingValue"); ok {
  298. return v.([]mappingValue)
  299. }
  300. values := make([]mappingValue, 0)
  301. 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 {
  302. e.lruCache.Add(namespace+":mappingValue", values)
  303. }
  304. return values
  305. }
  306. // invalidMappingValue 删除映射缓存数据
  307. func (e *Entity) invalidMappingValue(namespace string) {
  308. e.lruCache.Remove(namespace + ":mappingValue")
  309. }
  310. func (e *Entity) invalidCache(namespace string) {
  311. e.invalidMappingValue(namespace)
  312. return
  313. }
  314. //actionIndex
  315. func (e *Entity) actionIndex(ctx *http.Context) (err error) {
  316. var (
  317. page int
  318. pageIndex int
  319. pageSize int
  320. namespace string
  321. query *Query
  322. )
  323. if !e.hasScenario(ScenarioList) {
  324. return ctx.Error(HttpAccessDenied, "access denied")
  325. }
  326. namespace = ctx.ParamValue("@namespace")
  327. page, _ = strconv.Atoi(ctx.FormValue("page"))
  328. pageSize, _ = strconv.Atoi(ctx.FormValue("pagesize"))
  329. if pageSize <= 0 {
  330. pageSize = 15
  331. }
  332. pageIndex = page
  333. if pageIndex > 0 {
  334. pageIndex--
  335. }
  336. sliceValue := reflect.MakeSlice(reflect.SliceOf(e.reflectType), 0, 0)
  337. models := reflect.New(sliceValue.Type())
  338. models.Elem().Set(sliceValue)
  339. query = NewQuery(e.opts.DB)
  340. searchSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioSearch)
  341. indexSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioList)
  342. e.prepareConditions(ctx, query, searchSchemas)
  343. if e.opts.EnableNamespace {
  344. query.AndFilterWhere(NewQueryCondition("namespace", namespace))
  345. }
  346. query.Offset(pageIndex * pageSize).Limit(pageSize)
  347. if err = query.All(models.Interface()); err != nil {
  348. return ctx.Error(HttpDatabaseQueryFailed, err.Error())
  349. }
  350. requestCtx := ctx.Request().Context()
  351. if requestCtx == nil {
  352. requestCtx = context.Background()
  353. }
  354. requestCtx = context.WithValue(requestCtx, "namespace", namespace)
  355. return ctx.Success(map[string]interface{}{
  356. "page": page,
  357. "pageSize": pageSize,
  358. "totalCount": query.Limit(0).Offset(0).Count(e.model),
  359. "data": e.opts.Formatter.formatModels(requestCtx, models.Interface(), indexSchemas, e.statement),
  360. })
  361. }
  362. func (e *Entity) actionView(ctx *http.Context) (err error) {
  363. var (
  364. model interface{}
  365. namespace string
  366. )
  367. if !e.hasScenario(ScenarioView) {
  368. return ctx.Error(HttpAccessDenied, "access denied")
  369. }
  370. namespace = ctx.ParamValue("@namespace")
  371. scenario := ctx.FormValue("scenario")
  372. idStr := ctx.ParamValue("id")
  373. model = reflect.New(e.reflectType).Interface()
  374. conditions := map[string]interface{}{
  375. e.primaryKey: idStr,
  376. }
  377. if e.opts.EnableNamespace {
  378. conditions["namespace"] = namespace
  379. }
  380. if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
  381. return ctx.Error(HttpDatabaseFindFailed, err.Error())
  382. }
  383. if ctx.FormValue("format") != "" {
  384. //获取指定场景下面的字段进行渲染显示
  385. var schemas []*Schema
  386. if scenario == "" {
  387. schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioView)
  388. } else {
  389. schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), scenario)
  390. }
  391. requestCtx := ctx.Request().Context()
  392. if requestCtx == nil {
  393. requestCtx = context.Background()
  394. }
  395. requestCtx = context.WithValue(requestCtx, "namespace", namespace)
  396. return ctx.Success(e.opts.Formatter.formatModel(requestCtx, model, schemas, e.statement))
  397. }
  398. return ctx.Success(model)
  399. }
  400. func (e *Entity) actionExport(ctx *http.Context) (err error) {
  401. var (
  402. query *Query
  403. namespace string
  404. )
  405. if !e.hasScenario(ScenarioExport) {
  406. return ctx.Error(HttpAccessDenied, "access denied")
  407. }
  408. namespace = ctx.ParamValue("@namespace")
  409. sliceValue := reflect.MakeSlice(reflect.SliceOf(e.reflectType), 0, 0)
  410. models := reflect.New(sliceValue.Type())
  411. models.Elem().Set(sliceValue)
  412. query = NewQuery(e.opts.DB)
  413. searchSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioSearch)
  414. exportSchemas := visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioList)
  415. e.prepareConditions(ctx, query, searchSchemas)
  416. if e.opts.EnableNamespace {
  417. query.AndFilterWhere(NewQueryCondition("namespace", namespace))
  418. }
  419. if err = query.All(models.Interface()); err != nil {
  420. return ctx.Error(HttpDatabaseExportFailed, err.Error())
  421. }
  422. ctx.Response().Header().Set("Content-Type", "text/csv")
  423. ctx.Response().Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
  424. ctx.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", e.singularName))
  425. requestCtx := ctx.Request().Context()
  426. if requestCtx == nil {
  427. requestCtx = context.Background()
  428. }
  429. requestCtx = context.WithValue(requestCtx, "namespace", namespace)
  430. value := e.opts.Formatter.formatModels(requestCtx, models.Interface(), exportSchemas, e.statement)
  431. writer := csv.NewWriter(ctx.Response())
  432. ss := make([]string, len(exportSchemas))
  433. for i, field := range exportSchemas {
  434. ss[i] = field.Label
  435. }
  436. _ = writer.Write(ss)
  437. if values, ok := value.([]interface{}); ok {
  438. for _, val := range values {
  439. row, ok2 := val.(map[string]interface{})
  440. if !ok2 {
  441. continue
  442. }
  443. for i, field := range exportSchemas {
  444. if v, ok := row[field.Column]; ok {
  445. ss[i] = fmt.Sprint(v)
  446. } else {
  447. ss[i] = ""
  448. }
  449. }
  450. _ = writer.Write(ss)
  451. }
  452. }
  453. writer.Flush()
  454. return
  455. }
  456. func (e *Entity) actionCreate(ctx *http.Context) (err error) {
  457. var (
  458. errTx error
  459. namespace string
  460. model interface{}
  461. schemas []*Schema
  462. refModel reflect.Value
  463. diffAttrs = make([]*DiffAttr, 0)
  464. )
  465. if !e.hasScenario(ScenarioCreate) {
  466. return ctx.Error(HttpAccessDenied, "access denied")
  467. }
  468. namespace = ctx.ParamValue("@namespace")
  469. refModel = reflect.New(e.reflectType)
  470. model = refModel.Interface()
  471. if err = ctx.Bind(model); err != nil {
  472. return ctx.Error(HttpInvalidPayload, err.Error())
  473. }
  474. schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioCreate)
  475. //设置某个字段的值
  476. e.setFieldValue(refModel, "namespace", namespace)
  477. //global set field value
  478. e.setFieldValue(refModel, "CreatedBy", ctx.ParamValue("@uid"))
  479. e.setFieldValue(refModel, "CreatedDept", ctx.ParamValue("@department"))
  480. e.setFieldValue(refModel, "UpdatedBy", ctx.ParamValue("@uid"))
  481. e.setFieldValue(refModel, "UpdatedDept", ctx.ParamValue("@department"))
  482. if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
  483. //执行创建前回调函数
  484. if errTx = e.callMethod(model, "OnBeforeCreateRequest", []interface{}{ctx, tx, model}); errTx != nil {
  485. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  486. }
  487. //执行保存前回调函数
  488. if errTx = e.callMethod(model, "OnBeforeSaveRequest", []interface{}{ctx, tx, model}); errTx != nil {
  489. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  490. }
  491. //创建数据
  492. if errTx = tx.Create(model).Error; errTx != nil {
  493. return errTx
  494. }
  495. //对比差异数据
  496. for _, scm := range schemas {
  497. diffAttrs = append(diffAttrs, &DiffAttr{
  498. Column: scm.Column,
  499. Label: scm.Label,
  500. OldValue: nil,
  501. NewValue: e.getFieldValue(refModel, scm.Column),
  502. })
  503. }
  504. //执行创建后回调函数
  505. if errTx = e.callMethod(model, "OnAfterCreateRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
  506. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  507. }
  508. //执行保存后回调函数
  509. if errTx = e.callMethod(model, "OnAfterSaveRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
  510. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  511. }
  512. return errTx
  513. }); err == nil {
  514. e.invalidCache(namespace)
  515. pkVal := e.getPrimaryKeyValue(model)
  516. if len(e.hooks) > 0 {
  517. for _, hook := range e.hooks {
  518. hook.HookAfterCreate(ctx, e.opts.DB, pkVal, model, diffAttrs)
  519. }
  520. }
  521. return ctx.Success(map[string]interface{}{
  522. "id": pkVal,
  523. "table": e.model.TableName(),
  524. "state": "created",
  525. })
  526. }
  527. //form validation
  528. if validateError, ok := err.(*errors.StructError); ok {
  529. ctx.Response().Header().Set("Content-Type", "application/json")
  530. return json.NewEncoder(ctx.Response()).Encode(map[string]interface{}{
  531. "errno": HttpValidateFailed,
  532. "result": validateError,
  533. })
  534. }
  535. return ctx.Error(HttpDatabaseCreateFailed, err.Error())
  536. }
  537. func (e *Entity) actionUpdate(ctx *http.Context) (err error) {
  538. var (
  539. errTx error
  540. namespace string
  541. model interface{}
  542. schemas []*Schema
  543. refModel reflect.Value
  544. oldValues = make(map[string]interface{})
  545. diffs = make(map[string]interface{})
  546. diffAttrs = make([]*DiffAttr, 0)
  547. )
  548. if !e.hasScenario(ScenarioUpdate) {
  549. return ctx.Error(HttpAccessDenied, "access denied")
  550. }
  551. namespace = ctx.ParamValue("@namespace")
  552. idStr := ctx.ParamValue("id")
  553. refModel = reflect.New(e.reflectType)
  554. model = refModel.Interface()
  555. //默认设置更新用户
  556. e.setFieldValue(refModel, "UpdatedBy", ctx.ParamValue("@uid"))
  557. e.setFieldValue(refModel, "UpdatedDept", ctx.ParamValue("@department"))
  558. conditions := map[string]interface{}{
  559. e.primaryKey: idStr,
  560. }
  561. if e.opts.EnableNamespace {
  562. conditions["namespace"] = namespace
  563. }
  564. if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
  565. return ctx.Error(HttpDatabaseFindFailed, err.Error())
  566. }
  567. schemas = visibleSchemas(namespace, e.model.ModuleName(), e.model.TableName(), ScenarioUpdate)
  568. for _, scm := range schemas {
  569. oldValues[scm.Column] = e.getFieldValue(refModel, scm.Column)
  570. }
  571. if err = ctx.Bind(model); err != nil {
  572. return ctx.Error(HttpInvalidPayload, err.Error())
  573. }
  574. if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
  575. //更新前回调函数
  576. if errTx = e.callMethod(model, "OnBeforeUpdateRequest", []interface{}{ctx, tx, model}); errTx != nil {
  577. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  578. }
  579. //执行保存前回调函数
  580. if errTx = e.callMethod(model, "OnBeforeSaveRequest", []interface{}{ctx, tx, model}); errTx != nil {
  581. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  582. }
  583. //对比差异数据
  584. for _, scm := range schemas {
  585. v := e.getFieldValue(refModel, scm.Column)
  586. if oldValues[scm.Column] != v {
  587. diffs[scm.Column] = v
  588. diffAttrs = append(diffAttrs, &DiffAttr{
  589. Column: scm.Column,
  590. Label: scm.Label,
  591. OldValue: oldValues[scm.Column],
  592. NewValue: v,
  593. })
  594. }
  595. }
  596. //进行局部数据更新
  597. if len(diffs) > 0 {
  598. if errTx = tx.Model(model).Updates(diffs).Error; errTx != nil {
  599. return errTx
  600. }
  601. }
  602. //更新后回调函数
  603. if errTx = e.callMethod(model, "OnAfterUpdateRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
  604. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  605. }
  606. //执行保存后回调函数
  607. if errTx = e.callMethod(model, "OnAfterSaveRequest", []interface{}{ctx, tx, model, diffAttrs}); errTx != nil {
  608. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  609. }
  610. return errTx
  611. }); err == nil {
  612. e.invalidCache(namespace)
  613. pkVal := e.getPrimaryKeyValue(model)
  614. if len(e.hooks) > 0 {
  615. for _, hook := range e.hooks {
  616. hook.HookAfterUpdate(ctx, e.opts.DB, pkVal, model, diffAttrs)
  617. }
  618. }
  619. return ctx.Success(map[string]interface{}{
  620. "id": pkVal,
  621. "table": e.model.TableName(),
  622. "state": "updated",
  623. })
  624. }
  625. //form validation
  626. if validateError, ok := err.(*errors.StructError); ok {
  627. ctx.Response().Header().Set("Content-Type", "application/json")
  628. return json.NewEncoder(ctx.Response()).Encode(map[string]interface{}{
  629. "errno": HttpValidateFailed,
  630. "result": validateError,
  631. })
  632. }
  633. return ctx.Error(HttpDatabaseUpdateFailed, err.Error())
  634. }
  635. func (e *Entity) actionDelete(ctx *http.Context) (err error) {
  636. var (
  637. errTx error
  638. model interface{}
  639. namespace string
  640. )
  641. if !e.hasScenario(ScenarioDelete) {
  642. return ctx.Error(HttpAccessDenied, "access denied")
  643. }
  644. idStr := ctx.ParamValue("id")
  645. namespace = ctx.ParamValue("@namespace")
  646. model = reflect.New(e.reflectType).Interface()
  647. conditions := map[string]interface{}{
  648. e.primaryKey: idStr,
  649. }
  650. if e.opts.EnableNamespace {
  651. conditions["namespace"] = namespace
  652. }
  653. if err = e.opts.DB.Where(conditions).First(model).Error; err != nil {
  654. return ctx.Error(HttpDatabaseFindFailed, err.Error())
  655. }
  656. if err = e.opts.DB.Transaction(func(tx *gorm.DB) error {
  657. //删除前回调函数
  658. if errTx = e.callMethod(model, "OnBeforeDeleteRequest", []interface{}{ctx, tx, model}); errTx != nil {
  659. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  660. }
  661. //删除数据
  662. if errTx = tx.Delete(model).Error; errTx != nil {
  663. return errTx
  664. }
  665. //删除后回调函数
  666. if errTx = e.callMethod(model, "OnAfterDeleteRequest", []interface{}{ctx, tx, model}); errTx != nil {
  667. return ctx.Error(HttpRequestCallbackFailed, err.Error())
  668. }
  669. return errTx
  670. }); err == nil {
  671. e.invalidCache(namespace)
  672. return ctx.Success(map[string]interface{}{
  673. "id": e.getPrimaryKeyValue(model),
  674. "table": e.model.TableName(),
  675. "state": "deleted",
  676. })
  677. } else {
  678. return ctx.Error(HttpDatabaseDeleteFailed, err.Error())
  679. }
  680. }
  681. func (e *Entity) actionMapping(ctx *http.Context) (err error) {
  682. namespace := ctx.ParamValue("@namespace")
  683. return ctx.Success(e.getMappingValue(namespace))
  684. }
  685. func newEntity(model Model, opts *Options) *Entity {
  686. entity := &Entity{
  687. model: model,
  688. opts: opts,
  689. createdAt: time.Now(),
  690. reflectValue: reflect.Indirect(reflect.ValueOf(model)),
  691. }
  692. entity.lruCache, _ = lru.New(50)
  693. entity.reflectType = entity.reflectValue.Type()
  694. entity.singularName = inflector.Singularize(model.TableName())
  695. entity.pluralizeName = inflector.Pluralize(model.TableName())
  696. val := reflect.New(entity.reflectType).Interface()
  697. if kvMapping, ok := val.(KvMapping); ok {
  698. entity.isImplementKvMapping = true
  699. entity.mappingLabelField = kvMapping.LabelField()
  700. entity.mappingValueField = kvMapping.ValueField()
  701. }
  702. if opts.DB != nil {
  703. entity.statement = &gorm.Statement{
  704. DB: opts.DB,
  705. ConnPool: opts.DB.ConnPool,
  706. Clauses: map[string]clause.Clause{},
  707. }
  708. if err := entity.statement.Parse(model); err != nil {
  709. panic(err)
  710. }
  711. if entity.statement.Schema != nil {
  712. if entity.statement.Schema.PrimaryFieldDBNames != nil && len(entity.statement.Schema.PrimaryFieldDBNames) > 0 {
  713. entity.primaryKey = entity.statement.Schema.PrimaryFieldDBNames[0]
  714. }
  715. //把字段名称转成成数据库字段
  716. for _, field := range entity.statement.Schema.Fields {
  717. if field.Name == entity.mappingValueField {
  718. entity.mappingValueField = field.DBName
  719. }
  720. if field.Name == entity.mappingLabelField {
  721. entity.mappingLabelField = field.DBName
  722. }
  723. }
  724. }
  725. }
  726. return entity
  727. }