schema.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package schema
  2. import (
  3. "errors"
  4. "fmt"
  5. "go/ast"
  6. "reflect"
  7. "sync"
  8. "github.com/jinzhu/gorm/logger"
  9. )
  10. // ErrUnsupportedDataType unsupported data type
  11. var ErrUnsupportedDataType = errors.New("unsupported data type")
  12. type Schema struct {
  13. Name string
  14. ModelType reflect.Type
  15. Table string
  16. PrioritizedPrimaryField *Field
  17. DBNames []string
  18. PrimaryFields []*Field
  19. Fields []*Field
  20. FieldsByName map[string]*Field
  21. FieldsByDBName map[string]*Field
  22. Relationships Relationships
  23. err error
  24. namer Namer
  25. cacheStore *sync.Map
  26. }
  27. func (schema Schema) String() string {
  28. if schema.ModelType.Name() == "" {
  29. return fmt.Sprintf("%v(%v)", schema.Name, schema.Table)
  30. }
  31. return fmt.Sprintf("%v.%v", schema.ModelType.PkgPath(), schema.ModelType.Name())
  32. }
  33. func (schema Schema) LookUpField(name string) *Field {
  34. if field, ok := schema.FieldsByDBName[name]; ok {
  35. return field
  36. }
  37. if field, ok := schema.FieldsByName[name]; ok {
  38. return field
  39. }
  40. return nil
  41. }
  42. // get data type from dialector
  43. func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
  44. modelType := reflect.ValueOf(dest).Type()
  45. for modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Ptr {
  46. modelType = modelType.Elem()
  47. }
  48. if modelType.Kind() != reflect.Struct {
  49. if modelType.PkgPath() == "" {
  50. return nil, fmt.Errorf("%w: %+v", ErrUnsupportedDataType, dest)
  51. }
  52. return nil, fmt.Errorf("%w: %v.%v", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
  53. }
  54. if v, ok := cacheStore.Load(modelType); ok {
  55. return v.(*Schema), nil
  56. }
  57. schema := &Schema{
  58. Name: modelType.Name(),
  59. ModelType: modelType,
  60. Table: namer.TableName(modelType.Name()),
  61. FieldsByName: map[string]*Field{},
  62. FieldsByDBName: map[string]*Field{},
  63. Relationships: Relationships{Relations: map[string]*Relationship{}},
  64. cacheStore: cacheStore,
  65. namer: namer,
  66. }
  67. defer func() {
  68. if schema.err != nil {
  69. logger.Default.Error(schema.err.Error())
  70. cacheStore.Delete(modelType)
  71. }
  72. }()
  73. for i := 0; i < modelType.NumField(); i++ {
  74. if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
  75. if field := schema.ParseField(fieldStruct); field.EmbeddedSchema != nil {
  76. schema.Fields = append(schema.Fields, field.EmbeddedSchema.Fields...)
  77. } else {
  78. schema.Fields = append(schema.Fields, field)
  79. }
  80. }
  81. }
  82. for _, field := range schema.Fields {
  83. if field.DBName == "" && field.DataType != "" {
  84. field.DBName = namer.ColumnName(schema.Table, field.Name)
  85. }
  86. if field.DBName != "" {
  87. // nonexistence or shortest path or first appear prioritized if has permission
  88. if v, ok := schema.FieldsByDBName[field.DBName]; !ok || (field.Creatable && len(field.BindNames) < len(v.BindNames)) {
  89. if _, ok := schema.FieldsByDBName[field.DBName]; !ok {
  90. schema.DBNames = append(schema.DBNames, field.DBName)
  91. }
  92. schema.FieldsByDBName[field.DBName] = field
  93. schema.FieldsByName[field.Name] = field
  94. if v != nil && v.PrimaryKey {
  95. if schema.PrioritizedPrimaryField == v {
  96. schema.PrioritizedPrimaryField = nil
  97. }
  98. for idx, f := range schema.PrimaryFields {
  99. if f == v {
  100. schema.PrimaryFields = append(schema.PrimaryFields[0:idx], schema.PrimaryFields[idx+1:]...)
  101. } else if schema.PrioritizedPrimaryField == nil {
  102. schema.PrioritizedPrimaryField = f
  103. }
  104. }
  105. }
  106. if field.PrimaryKey {
  107. if schema.PrioritizedPrimaryField == nil {
  108. schema.PrioritizedPrimaryField = field
  109. }
  110. schema.PrimaryFields = append(schema.PrimaryFields, field)
  111. }
  112. }
  113. }
  114. if _, ok := schema.FieldsByName[field.Name]; !ok {
  115. schema.FieldsByName[field.Name] = field
  116. }
  117. field.setupValuerAndSetter()
  118. }
  119. if f := schema.LookUpField("id"); f != nil {
  120. if f.PrimaryKey {
  121. schema.PrioritizedPrimaryField = f
  122. } else if len(schema.PrimaryFields) == 0 {
  123. f.PrimaryKey = true
  124. schema.PrioritizedPrimaryField = f
  125. schema.PrimaryFields = append(schema.PrimaryFields, f)
  126. }
  127. }
  128. cacheStore.Store(modelType, schema)
  129. // parse relations for unidentified fields
  130. for _, field := range schema.Fields {
  131. if field.DataType == "" && field.Creatable {
  132. if schema.parseRelation(field); schema.err != nil {
  133. return schema, schema.err
  134. }
  135. }
  136. }
  137. return schema, schema.err
  138. }