entity.go 22 KB

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