crud.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package rest
  2. import (
  3. "context"
  4. loggerpkg "git.nspix.com/golang/rest/v3/logger"
  5. "gorm.io/gorm"
  6. "gorm.io/gorm/clause"
  7. "gorm.io/gorm/logger"
  8. "strings"
  9. )
  10. const (
  11. DefaultNamespace = "default"
  12. NamespaceVariable = "namespace"
  13. UserVariable = "@uid"
  14. DepartmentVariable = "@department"
  15. NamespaceField = "namespace"
  16. CreatedByField = "CreatedBy"
  17. CreatedDeptField = "CreatedDept"
  18. UpdatedByField = "UpdatedBy"
  19. UpdatedDeptField = "UpdatedDept"
  20. )
  21. const (
  22. TypeModule = "module"
  23. TypeTable = "table"
  24. )
  25. type (
  26. CRUD struct {
  27. api *Api
  28. db *gorm.DB
  29. modules []*Restful
  30. delegate *delegate
  31. }
  32. treeValue struct {
  33. Label string `json:"label"`
  34. Value string `json:"value"`
  35. Type string `json:"type"`
  36. Children []*treeValue `json:"children,omitempty"`
  37. }
  38. )
  39. func (t *treeValue) Append(v *treeValue) {
  40. if t.Children == nil {
  41. t.Children = make([]*treeValue, 0)
  42. }
  43. t.Children = append(t.Children, v)
  44. }
  45. //createStatement create new statement
  46. func (r *CRUD) createStatement(db *gorm.DB) *gorm.Statement {
  47. return &gorm.Statement{
  48. DB: db,
  49. ConnPool: db.Statement.ConnPool,
  50. Context: db.Statement.Context,
  51. Clauses: map[string]clause.Clause{},
  52. }
  53. }
  54. //WithDebug 开启调试
  55. func (r *CRUD) WithDebug() *CRUD {
  56. r.db.Logger = r.db.Logger.LogMode(logger.Info)
  57. return r
  58. }
  59. //RegisterDelegate 注册一个旁观者
  60. func (r *CRUD) RegisterDelegate(d Delegate) {
  61. r.delegate.Register(d)
  62. }
  63. //Attach 注册一个表
  64. func (r *CRUD) Attach(ctx context.Context, model Model, cbs ...Option) (err error) {
  65. var (
  66. opts *Options
  67. )
  68. opts = newOptions()
  69. for _, cb := range cbs {
  70. cb(opts)
  71. }
  72. if opts.DB == nil {
  73. opts.DB = r.db
  74. }
  75. if err = r.db.AutoMigrate(model); err != nil {
  76. return
  77. }
  78. if err = r.migrateSchema(ctx, DefaultNamespace, model); err != nil {
  79. return
  80. }
  81. opts.Delegate = r.delegate
  82. opts.LookupFunc = r.VisibleSchemas
  83. r.modules = append(r.modules, newRestful(model, opts))
  84. return
  85. }
  86. //migrateSchema 合并表的结构数据
  87. func (r *CRUD) migrateSchema(ctx context.Context, namespace string, model Model) (err error) {
  88. var (
  89. pos int
  90. columnLabel string
  91. columnName string
  92. columnIsExists bool
  93. stmt *gorm.Statement
  94. schemas []*Schema
  95. schemaModels []*Schema
  96. )
  97. schemas, err = r.GetSchemas(ctx, namespace, model.ModuleName(), model.TableName())
  98. stmt = r.createStatement(r.db)
  99. if err = stmt.Parse(model); err != nil {
  100. return
  101. }
  102. if len(schemas) > 0 {
  103. pos = len(schemas)
  104. }
  105. for index, field := range stmt.Schema.Fields {
  106. columnName = field.DBName
  107. if columnName == "-" {
  108. continue
  109. }
  110. if columnName == "" {
  111. columnName = field.Name
  112. }
  113. columnIsExists = false
  114. for _, sm := range schemas {
  115. if sm.Column == columnName {
  116. columnIsExists = true
  117. break
  118. }
  119. }
  120. if columnIsExists {
  121. continue
  122. }
  123. columnLabel = field.Tag.Get("comment")
  124. if columnLabel == "" {
  125. columnLabel = generateFieldName(field.DBName)
  126. }
  127. isPrimaryKey := uint8(0)
  128. if field.PrimaryKey {
  129. isPrimaryKey = 1
  130. }
  131. schemaModel := &Schema{
  132. Namespace: namespace,
  133. ModuleName: model.ModuleName(),
  134. TableName: model.TableName(),
  135. Enable: 1,
  136. Column: columnName,
  137. Label: columnLabel,
  138. Type: strings.ToLower(dataTypeOf(field)),
  139. Format: strings.ToLower(dataFormatOf(field)),
  140. Native: 1,
  141. IsPrimaryKey: isPrimaryKey,
  142. Scenarios: generateFieldScenario(index, field),
  143. Rule: generateFieldRule(field),
  144. Attribute: generateFieldAttribute(field),
  145. Position: pos,
  146. }
  147. schemaModels = append(schemaModels, schemaModel)
  148. pos++
  149. }
  150. if len(schemaModels) > 0 {
  151. err = r.db.Create(schemaModels).Error
  152. }
  153. return
  154. }
  155. //GetSchemas 获取表的结构数据
  156. func (r *CRUD) GetSchemas(ctx context.Context, namespace, moduleName, tableName string) (schemas []*Schema, err error) {
  157. schemas = make([]*Schema, 0)
  158. if len(namespace) == 0 {
  159. namespace = DefaultNamespace
  160. }
  161. sess := r.db.Session(&gorm.Session{NewDB: true, Context: ctx})
  162. err = sess.Where("`namespace`=? AND `module_name`=? AND `table_name`=?", namespace, moduleName, tableName).Order("position,id ASC").Find(&schemas).Error
  163. return
  164. }
  165. //VisibleSchemas 获取指定场景表的数据
  166. func (r *CRUD) VisibleSchemas(ctx context.Context, ns, moduleName, tableName, scene string) (result []*Schema) {
  167. var (
  168. err error
  169. schemas []*Schema
  170. )
  171. if schemas, err = r.GetSchemas(ctx, ns, moduleName, tableName); err == nil {
  172. result = make([]*Schema, 0, len(schemas))
  173. for _, s := range schemas {
  174. if s.Scenarios.Has(scene) || s.Attribute.PrimaryKey {
  175. result = append(result, s)
  176. }
  177. }
  178. }
  179. return
  180. }
  181. //New create new restful
  182. func New(dialer gorm.Dialector) (r *CRUD, err error) {
  183. r = &CRUD{
  184. delegate: &delegate{},
  185. }
  186. if r.db, err = gorm.Open(dialer); err != nil {
  187. return
  188. }
  189. r.api = &Api{crud: r}
  190. r.db.Logger = loggerpkg.New()
  191. err = r.db.AutoMigrate(&Schema{})
  192. return
  193. }