parent
6cc2c01268
commit
725aa5b5ff
@ -75,9 +75,7 @@ func (schema *Schema) parseRelation(field *Field) *Relationship {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
cacheStore := schema.cacheStore
|
if relation.FieldSchema, err = getOrParse(fieldValue, schema.cacheStore, schema.namer); err != nil {
|
||||||
|
|
||||||
if relation.FieldSchema, err = getOrParse(fieldValue, cacheStore, schema.namer); err != nil {
|
|
||||||
schema.err = fmt.Errorf("failed to parse field: %s, error: %w", field.Name, err)
|
schema.err = fmt.Errorf("failed to parse field: %s, error: %w", field.Name, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -147,6 +145,9 @@ func hasPolymorphicRelation(tagSettings map[string]string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (schema *Schema) setRelation(relation *Relationship) {
|
func (schema *Schema) setRelation(relation *Relationship) {
|
||||||
|
schema.Relationships.Mux.Lock()
|
||||||
|
defer schema.Relationships.Mux.Unlock()
|
||||||
|
|
||||||
// set non-embedded relation
|
// set non-embedded relation
|
||||||
if rel := schema.Relationships.Relations[relation.Name]; rel != nil {
|
if rel := schema.Relationships.Relations[relation.Name]; rel != nil {
|
||||||
if len(rel.Field.BindNames) > 1 {
|
if len(rel.Field.BindNames) > 1 {
|
||||||
@ -590,6 +591,10 @@ func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl gu
|
|||||||
// build references
|
// build references
|
||||||
for idx, foreignField := range foreignFields {
|
for idx, foreignField := range foreignFields {
|
||||||
// use same data type for foreign keys
|
// use same data type for foreign keys
|
||||||
|
schema.Relationships.Mux.Lock()
|
||||||
|
if schema != foreignField.Schema {
|
||||||
|
foreignField.Schema.Relationships.Mux.Lock()
|
||||||
|
}
|
||||||
if copyableDataType(primaryFields[idx].DataType) {
|
if copyableDataType(primaryFields[idx].DataType) {
|
||||||
foreignField.DataType = primaryFields[idx].DataType
|
foreignField.DataType = primaryFields[idx].DataType
|
||||||
}
|
}
|
||||||
@ -597,6 +602,10 @@ func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl gu
|
|||||||
if foreignField.Size == 0 {
|
if foreignField.Size == 0 {
|
||||||
foreignField.Size = primaryFields[idx].Size
|
foreignField.Size = primaryFields[idx].Size
|
||||||
}
|
}
|
||||||
|
schema.Relationships.Mux.Unlock()
|
||||||
|
if schema != foreignField.Schema {
|
||||||
|
foreignField.Schema.Relationships.Mux.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
relation.References = append(relation.References, &Reference{
|
relation.References = append(relation.References, &Reference{
|
||||||
PrimaryKey: primaryFields[idx],
|
PrimaryKey: primaryFields[idx],
|
||||||
|
@ -3,9 +3,11 @@ package schema_test
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/schema"
|
"gorm.io/gorm/schema"
|
||||||
|
"gorm.io/gorm/utils/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkStructRelation(t *testing.T, data interface{}, relations ...Relation) {
|
func checkStructRelation(t *testing.T, data interface{}, relations ...Relation) {
|
||||||
@ -996,3 +998,46 @@ func TestParseConstraintNameWithSchemaQualifiedLongTableName(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InfoRelation struct {
|
||||||
|
ID int
|
||||||
|
Code string
|
||||||
|
Info1 []*Info1 `gorm:"foreignkey:Code;references:Code"`
|
||||||
|
Info2 []*Info2 `gorm:"foreignkey:Code;references:Code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Info1 struct {
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Code string
|
||||||
|
Relation []*InfoRelation `gorm:"foreignkey:Code;references:Code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Info2 struct {
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
Code string
|
||||||
|
Relation []*InfoRelation `gorm:"foreignkey:Code;references:Code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDataRace(t *testing.T) {
|
||||||
|
syncMap := &sync.Map{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
schema.Parse(&Info1{}, syncMap, schema.NamingStrategy{IdentifierMaxLength: 64})
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
schema.Parse(&Info2{}, syncMap, schema.NamingStrategy{IdentifierMaxLength: 64})
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var result User
|
||||||
|
schema.Parse(&result, syncMap, schema.NamingStrategy{IdentifierMaxLength: 64})
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
var result tests.Account
|
||||||
|
schema.Parse(&result, syncMap, schema.NamingStrategy{IdentifierMaxLength: 64})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
180
schema/schema.go
180
schema/schema.go
@ -60,14 +60,14 @@ type Schema struct {
|
|||||||
cacheStore *sync.Map
|
cacheStore *sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
func (schema Schema) String() string {
|
func (schema *Schema) String() string {
|
||||||
if schema.ModelType.Name() == "" {
|
if schema.ModelType.Name() == "" {
|
||||||
return fmt.Sprintf("%s(%s)", schema.Name, schema.Table)
|
return fmt.Sprintf("%s(%s)", schema.Name, schema.Table)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s.%s", schema.ModelType.PkgPath(), schema.ModelType.Name())
|
return fmt.Sprintf("%s.%s", schema.ModelType.PkgPath(), schema.ModelType.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (schema Schema) MakeSlice() reflect.Value {
|
func (schema *Schema) MakeSlice() reflect.Value {
|
||||||
slice := reflect.MakeSlice(reflect.SliceOf(reflect.PointerTo(schema.ModelType)), 0, 20)
|
slice := reflect.MakeSlice(reflect.SliceOf(reflect.PointerTo(schema.ModelType)), 0, 20)
|
||||||
results := reflect.New(slice.Type())
|
results := reflect.New(slice.Type())
|
||||||
results.Elem().Set(slice)
|
results.Elem().Set(slice)
|
||||||
@ -75,7 +75,7 @@ func (schema Schema) MakeSlice() reflect.Value {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func (schema Schema) LookUpField(name string) *Field {
|
func (schema *Schema) LookUpField(name string) *Field {
|
||||||
if field, ok := schema.FieldsByDBName[name]; ok {
|
if field, ok := schema.FieldsByDBName[name]; ok {
|
||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ func (schema Schema) LookUpField(name string) *Field {
|
|||||||
// }
|
// }
|
||||||
// ID string // is selected by LookUpFieldByBindName([]string{"ID"}, "ID")
|
// ID string // is selected by LookUpFieldByBindName([]string{"ID"}, "ID")
|
||||||
// }
|
// }
|
||||||
func (schema Schema) LookUpFieldByBindName(bindNames []string, name string) *Field {
|
func (schema *Schema) LookUpFieldByBindName(bindNames []string, name string) *Field {
|
||||||
if len(bindNames) == 0 {
|
if len(bindNames) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -114,6 +114,14 @@ type TablerWithNamer interface {
|
|||||||
TableName(Namer) string
|
TableName(Namer) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var callbackTypes = []callbackType{
|
||||||
|
callbackTypeBeforeCreate, callbackTypeAfterCreate,
|
||||||
|
callbackTypeBeforeUpdate, callbackTypeAfterUpdate,
|
||||||
|
callbackTypeBeforeSave, callbackTypeAfterSave,
|
||||||
|
callbackTypeBeforeDelete, callbackTypeAfterDelete,
|
||||||
|
callbackTypeAfterFind,
|
||||||
|
}
|
||||||
|
|
||||||
// Parse get data type from dialector
|
// Parse get data type from dialector
|
||||||
func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
|
func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
|
||||||
return ParseWithSpecialTableName(dest, cacheStore, namer, "")
|
return ParseWithSpecialTableName(dest, cacheStore, namer, "")
|
||||||
@ -129,8 +137,10 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
if value.Kind() == reflect.Ptr && value.IsNil() {
|
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||||
value = reflect.New(value.Type().Elem())
|
value = reflect.New(value.Type().Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
modelType := reflect.Indirect(value).Type()
|
modelType := reflect.Indirect(value).Type()
|
||||||
|
|
||||||
|
if modelType.Kind() != reflect.Struct {
|
||||||
if modelType.Kind() == reflect.Interface {
|
if modelType.Kind() == reflect.Interface {
|
||||||
modelType = reflect.Indirect(reflect.ValueOf(dest)).Elem().Type()
|
modelType = reflect.Indirect(reflect.ValueOf(dest)).Elem().Type()
|
||||||
}
|
}
|
||||||
@ -145,14 +155,13 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("%w: %s.%s", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
|
return nil, fmt.Errorf("%w: %s.%s", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the Schema for performance,
|
// Cache the Schema for performance,
|
||||||
// Use the modelType or modelType + schemaTable (if it present) as cache key.
|
// Use the modelType or modelType + schemaTable (if it present) as cache key.
|
||||||
var schemaCacheKey interface{}
|
var schemaCacheKey interface{} = modelType
|
||||||
if specialTableName != "" {
|
if specialTableName != "" {
|
||||||
schemaCacheKey = fmt.Sprintf("%p-%s", modelType, specialTableName)
|
schemaCacheKey = fmt.Sprintf("%p-%s", modelType, specialTableName)
|
||||||
} else {
|
|
||||||
schemaCacheKey = modelType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load exist schema cache, return if exists
|
// Load exist schema cache, return if exists
|
||||||
@ -163,28 +172,27 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
return s, s.err
|
return s, s.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tableName string
|
||||||
modelValue := reflect.New(modelType)
|
modelValue := reflect.New(modelType)
|
||||||
tableName := namer.TableName(modelType.Name())
|
|
||||||
if tabler, ok := modelValue.Interface().(Tabler); ok {
|
|
||||||
tableName = tabler.TableName()
|
|
||||||
}
|
|
||||||
if tabler, ok := modelValue.Interface().(TablerWithNamer); ok {
|
|
||||||
tableName = tabler.TableName(namer)
|
|
||||||
}
|
|
||||||
if en, ok := namer.(embeddedNamer); ok {
|
|
||||||
tableName = en.Table
|
|
||||||
}
|
|
||||||
if specialTableName != "" && specialTableName != tableName {
|
if specialTableName != "" && specialTableName != tableName {
|
||||||
tableName = specialTableName
|
tableName = specialTableName
|
||||||
|
} else if en, ok := namer.(embeddedNamer); ok {
|
||||||
|
tableName = en.Table
|
||||||
|
} else if tabler, ok := modelValue.Interface().(Tabler); ok {
|
||||||
|
tableName = tabler.TableName()
|
||||||
|
} else if tabler, ok := modelValue.Interface().(TablerWithNamer); ok {
|
||||||
|
tableName = tabler.TableName(namer)
|
||||||
|
} else {
|
||||||
|
tableName = namer.TableName(modelType.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
schema := &Schema{
|
schema := &Schema{
|
||||||
Name: modelType.Name(),
|
Name: modelType.Name(),
|
||||||
ModelType: modelType,
|
ModelType: modelType,
|
||||||
Table: tableName,
|
Table: tableName,
|
||||||
FieldsByName: map[string]*Field{},
|
FieldsByName: make(map[string]*Field, 10),
|
||||||
FieldsByBindName: map[string]*Field{},
|
FieldsByBindName: make(map[string]*Field, 10),
|
||||||
FieldsByDBName: map[string]*Field{},
|
FieldsByDBName: make(map[string]*Field, 10),
|
||||||
Relationships: Relationships{Relations: map[string]*Relationship{}},
|
Relationships: Relationships{Relations: map[string]*Relationship{}},
|
||||||
cacheStore: cacheStore,
|
cacheStore: cacheStore,
|
||||||
namer: namer,
|
namer: namer,
|
||||||
@ -284,10 +292,37 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
schema.PrimaryFieldDBNames = append(schema.PrimaryFieldDBNames, field.DBName)
|
schema.PrimaryFieldDBNames = append(schema.PrimaryFieldDBNames, field.DBName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, embedded := schema.cacheStore.Load(embeddedCacheKey)
|
||||||
|
relationshipFields := []*Field{}
|
||||||
for _, field := range schema.Fields {
|
for _, field := range schema.Fields {
|
||||||
if field.DataType != "" && field.HasDefaultValue && field.DefaultValueInterface == nil {
|
if field.DataType != "" && field.HasDefaultValue && field.DefaultValueInterface == nil {
|
||||||
schema.FieldsWithDefaultDBValue = append(schema.FieldsWithDefaultDBValue, field)
|
schema.FieldsWithDefaultDBValue = append(schema.FieldsWithDefaultDBValue, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !embedded {
|
||||||
|
if field.DataType == "" && field.GORMDataType == "" && (field.Creatable || field.Updatable || field.Readable) {
|
||||||
|
relationshipFields = append(relationshipFields, field)
|
||||||
|
schema.FieldsByName[field.Name] = field
|
||||||
|
schema.FieldsByBindName[field.BindName()] = field
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldValue := reflect.New(field.IndirectFieldType).Interface()
|
||||||
|
if fc, ok := fieldValue.(CreateClausesInterface); ok {
|
||||||
|
field.Schema.CreateClauses = append(field.Schema.CreateClauses, fc.CreateClauses(field)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fc, ok := fieldValue.(QueryClausesInterface); ok {
|
||||||
|
field.Schema.QueryClauses = append(field.Schema.QueryClauses, fc.QueryClauses(field)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fc, ok := fieldValue.(UpdateClausesInterface); ok {
|
||||||
|
field.Schema.UpdateClauses = append(field.Schema.UpdateClauses, fc.UpdateClauses(field)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fc, ok := fieldValue.(DeleteClausesInterface); ok {
|
||||||
|
field.Schema.DeleteClauses = append(field.Schema.DeleteClauses, fc.DeleteClauses(field)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if field := schema.PrioritizedPrimaryField; field != nil {
|
if field := schema.PrioritizedPrimaryField; field != nil {
|
||||||
@ -304,30 +339,6 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackTypes := []callbackType{
|
|
||||||
callbackTypeBeforeCreate, callbackTypeAfterCreate,
|
|
||||||
callbackTypeBeforeUpdate, callbackTypeAfterUpdate,
|
|
||||||
callbackTypeBeforeSave, callbackTypeAfterSave,
|
|
||||||
callbackTypeBeforeDelete, callbackTypeAfterDelete,
|
|
||||||
callbackTypeAfterFind,
|
|
||||||
}
|
|
||||||
for _, cbName := range callbackTypes {
|
|
||||||
if methodValue := callBackToMethodValue(modelValue, cbName); methodValue.IsValid() {
|
|
||||||
switch methodValue.Type().String() {
|
|
||||||
case "func(*gorm.DB) error":
|
|
||||||
expectedPkgPath := path.Dir(reflect.TypeOf(schema).Elem().PkgPath())
|
|
||||||
if inVarPkg := methodValue.Type().In(0).Elem().PkgPath(); inVarPkg == expectedPkgPath {
|
|
||||||
reflect.Indirect(reflect.ValueOf(schema)).FieldByName(string(cbName)).SetBool(true)
|
|
||||||
} else {
|
|
||||||
logger.Default.Warn(context.Background(), "In model %v, the hook function `%v(*gorm.DB) error` has an incorrect parameter type. The expected parameter type is `%v`, but the provided type is `%v`.", schema, cbName, expectedPkgPath, inVarPkg)
|
|
||||||
// PASS
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
logger.Default.Warn(context.Background(), "Model %v don't match %vInterface, should be `%v(*gorm.DB) error`. Please see https://gorm.io/docs/hooks.html", schema, cbName, cbName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the schema
|
// Cache the schema
|
||||||
if v, loaded := cacheStore.LoadOrStore(schemaCacheKey, schema); loaded {
|
if v, loaded := cacheStore.LoadOrStore(schemaCacheKey, schema); loaded {
|
||||||
s := v.(*Schema)
|
s := v.(*Schema)
|
||||||
@ -343,75 +354,37 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if _, embedded := schema.cacheStore.Load(embeddedCacheKey); !embedded {
|
for _, cbName := range callbackTypes {
|
||||||
for _, field := range schema.Fields {
|
if methodValue := modelValue.MethodByName(string(cbName)); methodValue.IsValid() {
|
||||||
if field.DataType == "" && field.GORMDataType == "" && (field.Creatable || field.Updatable || field.Readable) {
|
switch methodValue.Type().String() {
|
||||||
|
case "func(*gorm.DB) error":
|
||||||
|
expectedPkgPath := path.Dir(reflect.TypeOf(schema).Elem().PkgPath())
|
||||||
|
if inVarPkg := methodValue.Type().In(0).Elem().PkgPath(); inVarPkg == expectedPkgPath {
|
||||||
|
reflect.Indirect(reflect.ValueOf(schema)).FieldByName(string(cbName)).SetBool(true)
|
||||||
|
} else {
|
||||||
|
logger.Default.Warn(context.Background(), "In model %v, the hook function `%v(*gorm.DB) error` has an incorrect parameter type. The expected parameter type is `%v`, but the provided type is `%v`.", schema, cbName, expectedPkgPath, inVarPkg)
|
||||||
|
// PASS
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logger.Default.Warn(context.Background(), "Model %v don't match %vInterface, should be `%v(*gorm.DB) error`. Please see https://gorm.io/docs/hooks.html", schema, cbName, cbName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse relationships
|
||||||
|
for _, field := range relationshipFields {
|
||||||
if schema.parseRelation(field); schema.err != nil {
|
if schema.parseRelation(field); schema.err != nil {
|
||||||
return schema, schema.err
|
return schema, schema.err
|
||||||
} else {
|
|
||||||
schema.FieldsByName[field.Name] = field
|
|
||||||
schema.FieldsByBindName[field.BindName()] = field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValue := reflect.New(field.IndirectFieldType)
|
|
||||||
fieldInterface := fieldValue.Interface()
|
|
||||||
if fc, ok := fieldInterface.(CreateClausesInterface); ok {
|
|
||||||
field.Schema.CreateClauses = append(field.Schema.CreateClauses, fc.CreateClauses(field)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fc, ok := fieldInterface.(QueryClausesInterface); ok {
|
|
||||||
field.Schema.QueryClauses = append(field.Schema.QueryClauses, fc.QueryClauses(field)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fc, ok := fieldInterface.(UpdateClausesInterface); ok {
|
|
||||||
field.Schema.UpdateClauses = append(field.Schema.UpdateClauses, fc.UpdateClauses(field)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fc, ok := fieldInterface.(DeleteClausesInterface); ok {
|
|
||||||
field.Schema.DeleteClauses = append(field.Schema.DeleteClauses, fc.DeleteClauses(field)...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema, schema.err
|
return schema, schema.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// This unrolling is needed to show to the compiler the exact set of methods
|
|
||||||
// that can be used on the modelType.
|
|
||||||
// Prior to go1.22 any use of MethodByName would cause the linker to
|
|
||||||
// abandon dead code elimination for the entire binary.
|
|
||||||
// As of go1.22 the compiler supports one special case of a string constant
|
|
||||||
// being passed to MethodByName. For enterprise customers or those building
|
|
||||||
// large binaries, this gives a significant reduction in binary size.
|
|
||||||
// https://github.com/golang/go/issues/62257
|
|
||||||
func callBackToMethodValue(modelType reflect.Value, cbType callbackType) reflect.Value {
|
|
||||||
switch cbType {
|
|
||||||
case callbackTypeBeforeCreate:
|
|
||||||
return modelType.MethodByName(string(callbackTypeBeforeCreate))
|
|
||||||
case callbackTypeAfterCreate:
|
|
||||||
return modelType.MethodByName(string(callbackTypeAfterCreate))
|
|
||||||
case callbackTypeBeforeUpdate:
|
|
||||||
return modelType.MethodByName(string(callbackTypeBeforeUpdate))
|
|
||||||
case callbackTypeAfterUpdate:
|
|
||||||
return modelType.MethodByName(string(callbackTypeAfterUpdate))
|
|
||||||
case callbackTypeBeforeSave:
|
|
||||||
return modelType.MethodByName(string(callbackTypeBeforeSave))
|
|
||||||
case callbackTypeAfterSave:
|
|
||||||
return modelType.MethodByName(string(callbackTypeAfterSave))
|
|
||||||
case callbackTypeBeforeDelete:
|
|
||||||
return modelType.MethodByName(string(callbackTypeBeforeDelete))
|
|
||||||
case callbackTypeAfterDelete:
|
|
||||||
return modelType.MethodByName(string(callbackTypeAfterDelete))
|
|
||||||
case callbackTypeAfterFind:
|
|
||||||
return modelType.MethodByName(string(callbackTypeAfterFind))
|
|
||||||
default:
|
|
||||||
return reflect.ValueOf(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOrParse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
|
func getOrParse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
|
||||||
modelType := reflect.ValueOf(dest).Type()
|
modelType := reflect.ValueOf(dest).Type()
|
||||||
|
|
||||||
|
if modelType.Kind() != reflect.Struct {
|
||||||
for modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Array || modelType.Kind() == reflect.Ptr {
|
for modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Array || modelType.Kind() == reflect.Ptr {
|
||||||
modelType = modelType.Elem()
|
modelType = modelType.Elem()
|
||||||
}
|
}
|
||||||
@ -422,6 +395,7 @@ func getOrParse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, e
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("%w: %s.%s", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
|
return nil, fmt.Errorf("%w: %s.%s", ErrUnsupportedDataType, modelType.PkgPath(), modelType.Name())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := cacheStore.Load(modelType); ok {
|
if v, ok := cacheStore.Load(modelType); ok {
|
||||||
return v.(*Schema), nil
|
return v.(*Schema), nil
|
||||||
|
@ -27,13 +27,13 @@ require (
|
|||||||
github.com/jackc/pgx/v5 v5.7.5 // indirect
|
github.com/jackc/pgx/v5 v5.7.5 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
||||||
github.com/microsoft/go-mssqldb v1.9.2 // indirect
|
github.com/microsoft/go-mssqldb v1.9.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
golang.org/x/crypto v0.40.0 // indirect
|
golang.org/x/crypto v0.41.0 // indirect
|
||||||
golang.org/x/sync v0.16.0 // indirect
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
golang.org/x/text v0.27.0 // indirect
|
golang.org/x/text v0.28.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user