api.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package rest
  2. import (
  3. "fmt"
  4. "git.nspix.com/golang/micro/gateway/http"
  5. "git.nspix.com/golang/rest/v3/cache"
  6. "gorm.io/gorm"
  7. )
  8. type (
  9. Api struct {
  10. crud *CRUD
  11. svr *http.Server
  12. exists []string
  13. middleware []http.Middleware
  14. }
  15. feedRequest struct {
  16. ModuleName string `json:"module_name"`
  17. TableName string `json:"table_name"`
  18. ValueField string `json:"value_field"`
  19. LabelField string `json:"label_field"`
  20. Condition string `json:"condition,omitempty"`
  21. Limit int `json:"limit,omitempty"`
  22. }
  23. feedResponse struct {
  24. Label interface{} `json:"label"`
  25. Value interface{} `json:"value"`
  26. }
  27. )
  28. func (api *Api) handleListSchema(httpCtx *http.Context) (err error) {
  29. var (
  30. schemas []*Schema
  31. )
  32. ns := httpCtx.FormValue(NamespaceVariable)
  33. if ns == "" {
  34. ns = DefaultNamespace
  35. }
  36. if schemas, err = api.crud.GetSchemas(httpCtx.Request().Context(), ns, httpCtx.ParamValue("module"), httpCtx.ParamValue("table")); err == nil {
  37. return httpCtx.Success(schemas)
  38. } else {
  39. return httpCtx.Error(HttpDatabaseQueryFailed, err.Error())
  40. }
  41. }
  42. //handleSaveSchema 保存schema
  43. func (api *Api) handleSaveSchema(httpCtx *http.Context) (err error) {
  44. var (
  45. rest *Restful
  46. )
  47. ns := httpCtx.FormValue(NamespaceVariable)
  48. if ns == "" {
  49. ns = DefaultNamespace
  50. }
  51. moduleName := httpCtx.ParamValue("module")
  52. tableName := httpCtx.ParamValue("table")
  53. for _, row := range api.crud.modules {
  54. if row.model.ModuleName() == moduleName && row.model.TableName() == tableName {
  55. rest = row
  56. break
  57. }
  58. }
  59. if rest == nil {
  60. return httpCtx.Error(HTTPUnknownFailed, fmt.Sprintf("module %s table %s schema not found", moduleName, tableName))
  61. }
  62. schemas := make([]*Schema, 0)
  63. if err = httpCtx.Bind(&schemas); err != nil {
  64. return httpCtx.Error(HttpInvalidPayload, err.Error())
  65. }
  66. if err = api.crud.db.Transaction(func(tx *gorm.DB) error {
  67. var (
  68. errTx error
  69. )
  70. for _, scm := range schemas {
  71. if errTx = tx.Save(scm).Error; errTx != nil {
  72. return errTx
  73. }
  74. }
  75. return nil
  76. }); err == nil {
  77. if api.crud.enableCache {
  78. cache.Delete(fmt.Sprintf("schema:%s:%s:%s", ns, moduleName, tableName))
  79. }
  80. return httpCtx.Success(map[string]interface{}{
  81. "count": len(schemas),
  82. "state": "success",
  83. })
  84. } else {
  85. return httpCtx.Error(HTTPUnknownFailed, err.Error())
  86. }
  87. }
  88. //handleListSchemas 查看表schema
  89. func (api *Api) handleListSchemas(httpCtx *http.Context) (err error) {
  90. var (
  91. moduleLabel string
  92. )
  93. ts := make([]*treeValue, 0)
  94. isHandled := false
  95. for _, e := range api.crud.modules {
  96. isHandled = false
  97. for _, tv := range ts {
  98. if tv.Value == e.model.ModuleName() {
  99. tv.Append(&treeValue{Value: e.model.TableName(), Label: e.model.TableName(), Type: TypeTable})
  100. isHandled = true
  101. break
  102. }
  103. }
  104. if isHandled {
  105. continue
  106. }
  107. moduleLabel = e.model.ModuleName()
  108. tv := &treeValue{Label: moduleLabel, Value: e.model.ModuleName(), Type: TypeModule}
  109. tv.Append(&treeValue{Value: e.model.TableName(), Label: e.model.TableName(), Type: TypeTable})
  110. ts = append(ts, tv)
  111. }
  112. return httpCtx.Success(ts)
  113. }
  114. //handleDeleteSchema 删除指定的表结构
  115. func (api *Api) handleDeleteSchema(httpCtx *http.Context) (err error) {
  116. id := httpCtx.ParamValue("id")
  117. model := &Schema{}
  118. if err = api.crud.db.Where("id=?", id).First(model).Error; err == nil {
  119. if err = api.crud.db.Where("id=?", id).Delete(&Schema{}).Error; err == nil {
  120. if api.crud.enableCache {
  121. cache.Delete(fmt.Sprintf("schema:%s:%s:%s", model.Namespace, model.ModuleName, model.TableName))
  122. }
  123. return httpCtx.Success(map[string]string{
  124. "id": id,
  125. "state": "success",
  126. })
  127. } else {
  128. return httpCtx.Error(HttpDatabaseDeleteFailed, err.Error())
  129. }
  130. } else {
  131. return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
  132. }
  133. }
  134. //handleFeed 订阅指定模块数据
  135. func (api *Api) handleFeed(httpCtx *http.Context) (err error) {
  136. req := &feedRequest{}
  137. if err = httpCtx.Bind(req); err != nil {
  138. return httpCtx.Error(HttpInvalidPayload, err.Error())
  139. }
  140. if !api.isExists(req.TableName + "@" + req.ModuleName) {
  141. return httpCtx.Error(HTTPUnknownFailed, fmt.Sprintf("model %s not register", req.TableName))
  142. }
  143. result := make([]feedResponse, 0, 10)
  144. query := api.crud.db.Table(req.TableName).Select(req.LabelField+" AS label", req.ValueField+" AS value")
  145. if req.Condition != "" {
  146. query = query.Where(req.Condition)
  147. }
  148. if req.Limit > 0 {
  149. query = query.Limit(req.Limit)
  150. }
  151. if err = query.Find(&result).Error; err == nil {
  152. return httpCtx.Success(result)
  153. } else {
  154. return httpCtx.Error(HttpDatabaseFindFailed, err.Error())
  155. }
  156. }
  157. func (api *Api) isExists(id string) bool {
  158. if api.exists == nil {
  159. return false
  160. }
  161. for _, s := range api.exists {
  162. if s == id {
  163. return true
  164. }
  165. }
  166. return false
  167. }
  168. func (api *Api) Attach(rest *Restful, ms ...http.Middleware) {
  169. if api.svr == nil {
  170. return
  171. }
  172. id := rest.model.TableName() + "@" + rest.model.ModuleName()
  173. if api.isExists(id) {
  174. return
  175. }
  176. if len(ms) == 0 {
  177. ms = api.middleware
  178. }
  179. if rest.hasScenario(ScenarioList) {
  180. api.svr.Handle("GET", rest.getScenarioUrl(ScenarioList), rest.getScenarioHandle(ScenarioList), ms...)
  181. }
  182. if rest.hasScenario(ScenarioCreate) {
  183. api.svr.Handle("POST", rest.getScenarioUrl(ScenarioCreate), rest.getScenarioHandle(ScenarioCreate), ms...)
  184. }
  185. if rest.hasScenario(ScenarioUpdate) {
  186. api.svr.Handle("PUT", rest.getScenarioUrl(ScenarioUpdate), rest.getScenarioHandle(ScenarioUpdate), ms...)
  187. }
  188. if rest.hasScenario(ScenarioDelete) {
  189. api.svr.Handle("DELETE", rest.getScenarioUrl(ScenarioDelete), rest.getScenarioHandle(ScenarioDelete), ms...)
  190. }
  191. if rest.hasScenario(ScenarioExport) {
  192. api.svr.Handle("GET", rest.getScenarioUrl(ScenarioExport), rest.getScenarioHandle(ScenarioExport), ms...)
  193. }
  194. if rest.hasScenario(ScenarioView) {
  195. api.svr.Handle("GET", rest.getScenarioUrl(ScenarioView), rest.getScenarioHandle(ScenarioView), ms...)
  196. }
  197. api.exists = append(api.exists, id)
  198. }
  199. func (api *Api) Router(svr *http.Server, ms ...http.Middleware) {
  200. api.svr = svr
  201. api.middleware = ms
  202. svr.Handle("GET", "/rest/schemas", api.handleListSchemas, ms...)
  203. svr.Handle("GET", "/rest/schema/:module/:table", api.handleListSchema, ms...)
  204. svr.Handle("PUT", "/rest/schema/:module/:table", api.handleSaveSchema, ms...)
  205. svr.Handle("DELETE", "/rest/schema/:id", api.handleDeleteSchema, ms...)
  206. svr.Handle("POST", "/rest/feed", api.handleFeed, ms...)
  207. api.exists = make([]string, 0, 10)
  208. for _, rest := range api.crud.modules {
  209. api.Attach(rest, ms...)
  210. }
  211. }