entity.go 25 KB

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