entity.go 25 KB

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