entity.go 25 KB

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