schema.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. FieldsWithDefaultDBValue map[string]*Field // fields with default value assigned by database
  23. Relationships Relationships
  24. err error
  25. namer Namer
  26. cacheStore *sync.Map
  27. }
  28. func (schema Schema) String() string {
  29. if schema.ModelType.Name() == "" {
  30. return fmt.Sprintf("%v(%v)", schema.Name, schema.Table)
  31. }
  32. return fmt.Sprintf("%v.%v", schema.ModelType.PkgPath(), schema.ModelType.Name())
  33. }
  34. func (schema Schema) LookUpField(name string) *Field {
  35. if field, ok := schema.FieldsByDBName[name]; ok {
  36. return field
  37. }
  38. if field, ok := schema.FieldsByName[name]; ok {
  39. return field
  40. }
  41. return nil
  42. }
  43. // get data type from dialector
  44. func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, reflect.Value, error) {
  45. reflectValue := reflect.ValueOf(dest)
  46. modelType := reflectValue.Type()
  47. for modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Ptr {
  48. modelType = modelType.Elem()
  49. }
  50. if modelType.Kind() != reflect.Struct {
  51. if modelType.PkgPath() == "" {
  52. return nil, reflectValue, fmt.Errorf("%w: %+v", ErrUnsupportedDataType, dest)
  53. }
  54. return nil, reflectValue, fmt.Errorf("%w: %v.%v", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
  55. }
  56. if v, ok := cacheStore.Load(modelType); ok {
  57. return v.(*Schema), reflectValue, nil
  58. }
  59. schema := &Schema{
  60. Name: modelType.Name(),
  61. ModelType: modelType,
  62. Table: namer.TableName(modelType.Name()),
  63. FieldsByName: map[string]*Field{},
  64. FieldsByDBName: map[string]*Field{},
  65. Relationships: Relationships{Relations: map[string]*Relationship{}},
  66. cacheStore: cacheStore,
  67. namer: namer,
  68. }
  69. defer func() {
  70. if schema.err != nil {
  71. logger.Default.Error(schema.err.Error())
  72. cacheStore.Delete(modelType)
  73. }
  74. }()
  75. for i := 0; i < modelType.NumField(); i++ {
  76. if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
  77. if field := schema.ParseField(fieldStruct); field.EmbeddedSchema != nil {
  78. schema.Fields = append(schema.Fields, field.EmbeddedSchema.Fields...)
  79. } else {
  80. schema.Fields = append(schema.Fields, field)
  81. }
  82. }
  83. }
  84. for _, field := range schema.Fields {
  85. if field.DBName == "" && field.DataType != "" {
  86. field.DBName = namer.ColumnName(schema.Table, field.Name)
  87. }
  88. if field.DBName != "" {
  89. // nonexistence or shortest path or first appear prioritized if has permission
  90. if v, ok := schema.FieldsByDBName[field.DBName]; !ok || (field.Creatable && len(field.BindNames) < len(v.BindNames)) {
  91. if _, ok := schema.FieldsByDBName[field.DBName]; !ok {
  92. schema.DBNames = append(schema.DBNames, field.DBName)
  93. }
  94. schema.FieldsByDBName[field.DBName] = field
  95. schema.FieldsByName[field.Name] = field
  96. if v != nil && v.PrimaryKey {
  97. if schema.PrioritizedPrimaryField == v {
  98. schema.PrioritizedPrimaryField = nil
  99. }
  100. for idx, f := range schema.PrimaryFields {
  101. if f == v {
  102. schema.PrimaryFields = append(schema.PrimaryFields[0:idx], schema.PrimaryFields[idx+1:]...)
  103. } else if schema.PrioritizedPrimaryField == nil {
  104. schema.PrioritizedPrimaryField = f
  105. }
  106. }
  107. }
  108. if field.PrimaryKey {
  109. if schema.PrioritizedPrimaryField == nil {
  110. schema.PrioritizedPrimaryField = field
  111. }
  112. schema.PrimaryFields = append(schema.PrimaryFields, field)
  113. }
  114. }
  115. }
  116. if _, ok := schema.FieldsByName[field.Name]; !ok {
  117. schema.FieldsByName[field.Name] = field
  118. }
  119. field.setupValuerAndSetter()
  120. }
  121. if f := schema.LookUpField("id"); f != nil {
  122. if f.PrimaryKey {
  123. schema.PrioritizedPrimaryField = f
  124. } else if len(schema.PrimaryFields) == 0 {
  125. f.PrimaryKey = true
  126. schema.PrioritizedPrimaryField = f
  127. schema.PrimaryFields = append(schema.PrimaryFields, f)
  128. }
  129. }
  130. schema.FieldsWithDefaultDBValue = map[string]*Field{}
  131. for db, field := range schema.FieldsByDBName {
  132. if field.HasDefaultValue && field.DefaultValueInterface == nil {
  133. schema.FieldsWithDefaultDBValue[db] = field
  134. }
  135. }
  136. if schema.PrioritizedPrimaryField != nil {
  137. switch schema.PrioritizedPrimaryField.DataType {
  138. case Int, Uint:
  139. schema.FieldsWithDefaultDBValue[schema.PrioritizedPrimaryField.DBName] = schema.PrioritizedPrimaryField
  140. }
  141. }
  142. cacheStore.Store(modelType, schema)
  143. // parse relations for unidentified fields
  144. for _, field := range schema.Fields {
  145. if field.DataType == "" && field.Creatable {
  146. if schema.parseRelation(field); schema.err != nil {
  147. return schema, reflectValue, schema.err
  148. }
  149. }
  150. }
  151. return schema, reflectValue, schema.err
  152. }