package sql import ( "errors" "github.com/iancoleman/strcase" "reflect" "strings" ) const ( defaultKeyColumnName = "id" sqlMappingTagPartSeparator = ";" sqlMappingTagPartKeyValueSeparator = ":" ) const ( sqlMappingTagKey = "sqlmapping" sqlMappingIgnore = "-" sqlMappingColumn = "column" sqlMappingKey = "key" sqlMappingNotUpdate = "notUpdate" sqlMappingUpdateClear = "updateClear" ) type Mapping struct { ColumnMap map[string]MappingColumn } func ParseSqlMapping(e any) (*Mapping, error) { if e == nil { return nil, errors.New("没有传递实体") } entityType := reflect.TypeOf(e) if entityType.Kind() == reflect.Ptr { entityType = entityType.Elem() } if entityType.Kind() != reflect.Struct { return nil, errors.New("传递的不是实体结构") } entityValue := reflect.ValueOf(e) if entityValue.Kind() == reflect.Ptr { entityValue = entityValue.Elem() } sqlMapping := new(Mapping) sqlMapping.ColumnMap = make(map[string]MappingColumn) fieldNum := entityType.NumField() for i := 0; i < fieldNum; i++ { field := entityType.Field(i) fieldValue := entityValue.Field(i) column, err := parseSqlMappingColumn(field, fieldValue) if err != nil { return nil, err } if column == nil { continue } sqlMapping.ColumnMap[field.Name] = *column } return sqlMapping, nil } type MappingColumn struct { Name string IsKey bool CanUpdate bool CanUpdateClear bool // 原字段的反射结构 OriginFieldType reflect.Type OriginFieldValue reflect.Value // 值类型的反射结构 ValueFieldType reflect.Type ValueFieldValue reflect.Value } func parseSqlMappingColumn(field reflect.StructField, fieldValue reflect.Value) (*MappingColumn, error) { valueFieldType := field.Type valueFieldValue := fieldValue if valueFieldType.Kind() == reflect.Ptr { valueFieldType = valueFieldType.Elem() if valueFieldValue.IsZero() { valueFieldValue = reflect.Zero(valueFieldType) } else { valueFieldValue = fieldValue.Elem() } } sqlColumn := &MappingColumn{ Name: strcase.ToSnake(field.Name), IsKey: false, CanUpdate: true, CanUpdateClear: false, OriginFieldType: field.Type, OriginFieldValue: fieldValue, ValueFieldType: valueFieldType, ValueFieldValue: valueFieldValue, } if sqlColumn.Name == defaultKeyColumnName { sqlColumn.IsKey = true } sqlMappingTag, ok := field.Tag.Lookup(sqlMappingTagKey) if !ok { return sqlColumn, nil } if sqlMappingTag == sqlMappingIgnore { return nil, nil } sqlMappingParts := strings.Split(sqlMappingTag, sqlMappingTagPartSeparator) if sqlMappingParts != nil || len(sqlMappingParts) != 0 { for _, sqlMappingPart := range sqlMappingParts { sqlPartKeyValue := strings.Split(strings.TrimSpace(sqlMappingPart), sqlMappingTagPartKeyValueSeparator) switch sqlPartKeyValue[0] { case sqlMappingColumn: sqlColumn.Name = strings.TrimSpace(sqlPartKeyValue[1]) case sqlMappingKey: sqlColumn.IsKey = true sqlColumn.CanUpdate = false case sqlMappingNotUpdate: sqlColumn.CanUpdate = false case sqlMappingUpdateClear: sqlColumn.CanUpdateClear = true default: continue } } } return sqlColumn, nil }