Add Serializer Interface
This commit is contained in:
parent
1b6cc25e19
commit
3c77eb0bb0
@ -15,12 +15,17 @@ import (
|
|||||||
"gorm.io/gorm/utils"
|
"gorm.io/gorm/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataType string
|
type (
|
||||||
|
// DataType GORM data type
|
||||||
type TimeType int64
|
DataType string
|
||||||
|
// TimeType GORM time type
|
||||||
|
TimeType int64
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeReflectType time's reflect type
|
||||||
var TimeReflectType = reflect.TypeOf(time.Time{})
|
var TimeReflectType = reflect.TypeOf(time.Time{})
|
||||||
|
|
||||||
|
// GORM time types
|
||||||
const (
|
const (
|
||||||
UnixTime TimeType = 1
|
UnixTime TimeType = 1
|
||||||
UnixSecond TimeType = 2
|
UnixSecond TimeType = 2
|
||||||
@ -28,6 +33,7 @@ const (
|
|||||||
UnixNanosecond TimeType = 4
|
UnixNanosecond TimeType = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GORM fields types
|
||||||
const (
|
const (
|
||||||
Bool DataType = "bool"
|
Bool DataType = "bool"
|
||||||
Int DataType = "int"
|
Int DataType = "int"
|
||||||
@ -38,6 +44,7 @@ const (
|
|||||||
Bytes DataType = "bytes"
|
Bytes DataType = "bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Field is the representation of model schema's field
|
||||||
type Field struct {
|
type Field struct {
|
||||||
Name string
|
Name string
|
||||||
DBName string
|
DBName string
|
||||||
@ -50,9 +57,9 @@ type Field struct {
|
|||||||
Creatable bool
|
Creatable bool
|
||||||
Updatable bool
|
Updatable bool
|
||||||
Readable bool
|
Readable bool
|
||||||
HasDefaultValue bool
|
|
||||||
AutoCreateTime TimeType
|
AutoCreateTime TimeType
|
||||||
AutoUpdateTime TimeType
|
AutoUpdateTime TimeType
|
||||||
|
HasDefaultValue bool
|
||||||
DefaultValue string
|
DefaultValue string
|
||||||
DefaultValueInterface interface{}
|
DefaultValueInterface interface{}
|
||||||
NotNull bool
|
NotNull bool
|
||||||
@ -61,6 +68,7 @@ type Field struct {
|
|||||||
Size int
|
Size int
|
||||||
Precision int
|
Precision int
|
||||||
Scale int
|
Scale int
|
||||||
|
IgnoreMigration bool
|
||||||
FieldType reflect.Type
|
FieldType reflect.Type
|
||||||
IndirectFieldType reflect.Type
|
IndirectFieldType reflect.Type
|
||||||
StructField reflect.StructField
|
StructField reflect.StructField
|
||||||
@ -72,24 +80,32 @@ type Field struct {
|
|||||||
ReflectValueOf func(context.Context, reflect.Value) reflect.Value
|
ReflectValueOf func(context.Context, reflect.Value) reflect.Value
|
||||||
ValueOf func(context.Context, reflect.Value) (value interface{}, zero bool)
|
ValueOf func(context.Context, reflect.Value) (value interface{}, zero bool)
|
||||||
Set func(context.Context, reflect.Value, interface{}) error
|
Set func(context.Context, reflect.Value, interface{}) error
|
||||||
IgnoreMigration bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseField parses reflect.StructField to Field
|
||||||
func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
||||||
var err error
|
var (
|
||||||
|
err error
|
||||||
|
tagSetting = ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";")
|
||||||
|
)
|
||||||
|
|
||||||
field := &Field{
|
field := &Field{
|
||||||
Name: fieldStruct.Name,
|
Name: fieldStruct.Name,
|
||||||
|
DBName: tagSetting["COLUMN"],
|
||||||
BindNames: []string{fieldStruct.Name},
|
BindNames: []string{fieldStruct.Name},
|
||||||
FieldType: fieldStruct.Type,
|
FieldType: fieldStruct.Type,
|
||||||
IndirectFieldType: fieldStruct.Type,
|
IndirectFieldType: fieldStruct.Type,
|
||||||
StructField: fieldStruct,
|
StructField: fieldStruct,
|
||||||
|
Tag: fieldStruct.Tag,
|
||||||
|
TagSettings: tagSetting,
|
||||||
|
Schema: schema,
|
||||||
Creatable: true,
|
Creatable: true,
|
||||||
Updatable: true,
|
Updatable: true,
|
||||||
Readable: true,
|
Readable: true,
|
||||||
Tag: fieldStruct.Tag,
|
PrimaryKey: utils.CheckTruth(tagSetting["PRIMARYKEY"], tagSetting["PRIMARY_KEY"]),
|
||||||
TagSettings: ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";"),
|
NotNull: utils.CheckTruth(tagSetting["NOT NULL"], tagSetting["NOTNULL"]),
|
||||||
Schema: schema,
|
Unique: utils.CheckTruth(tagSetting["UNIQUE"]),
|
||||||
|
Comment: tagSetting["COMMENT"],
|
||||||
AutoIncrementIncrement: 1,
|
AutoIncrementIncrement: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,16 +155,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbName, ok := field.TagSettings["COLUMN"]; ok {
|
|
||||||
field.DBName = dbName
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, ok := field.TagSettings["PRIMARYKEY"]; ok && utils.CheckTruth(val) {
|
|
||||||
field.PrimaryKey = true
|
|
||||||
} else if val, ok := field.TagSettings["PRIMARY_KEY"]; ok && utils.CheckTruth(val) {
|
|
||||||
field.PrimaryKey = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) {
|
if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) {
|
||||||
field.AutoIncrement = true
|
field.AutoIncrement = true
|
||||||
field.HasDefaultValue = true
|
field.HasDefaultValue = true
|
||||||
@ -177,20 +183,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||||||
field.Scale, _ = strconv.Atoi(s)
|
field.Scale, _ = strconv.Atoi(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := field.TagSettings["NOT NULL"]; ok && utils.CheckTruth(val) {
|
|
||||||
field.NotNull = true
|
|
||||||
} else if val, ok := field.TagSettings["NOTNULL"]; ok && utils.CheckTruth(val) {
|
|
||||||
field.NotNull = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, ok := field.TagSettings["UNIQUE"]; ok && utils.CheckTruth(val) {
|
|
||||||
field.Unique = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, ok := field.TagSettings["COMMENT"]; ok {
|
|
||||||
field.Comment = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// default value is function or null or blank (primary keys)
|
// default value is function or null or blank (primary keys)
|
||||||
field.DefaultValue = strings.TrimSpace(field.DefaultValue)
|
field.DefaultValue = strings.TrimSpace(field.DefaultValue)
|
||||||
skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
|
skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package schema_test
|
package schema_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@ -57,7 +58,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues {
|
for k, v := range newValues {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues2 {
|
for k, v := range newValues2 {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +133,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues {
|
for k, v := range newValues {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +152,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues2 {
|
for k, v := range newValues2 {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +203,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues {
|
for k, v := range newValues {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +220,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range newValues2 {
|
for k, v := range newValues2 {
|
||||||
if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
|
if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
|
||||||
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package schema
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
@ -12,8 +13,26 @@ type GormDataTypeInterface interface {
|
|||||||
GormDataType() string
|
GormDataType() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serializer serializer interface
|
// Serializer field value serializer
|
||||||
type Serializer interface {
|
type Serializer struct {
|
||||||
|
Field *Field
|
||||||
|
Interface SerializerInterface
|
||||||
|
Destination reflect.Value
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements sql.Scanner interface
|
||||||
|
func (s *Serializer) Scan(value interface{}) error {
|
||||||
|
return s.Interface.Scan(s.Context, s.Field, s.Destination, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements driver.Valuer interface
|
||||||
|
func (s Serializer) Value() (driver.Value, error) {
|
||||||
|
return s.Interface.Value(s.Context, s.Field, s.Destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializerInterface serializer interface
|
||||||
|
type SerializerInterface interface {
|
||||||
Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
|
Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
|
||||||
Value(ctx context.Context, field *Field, dst reflect.Value) (interface{}, error)
|
Value(ctx context.Context, field *Field, dst reflect.Value) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package schema_test
|
package schema_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -203,7 +204,7 @@ func checkSchemaRelation(t *testing.T, s *schema.Schema, relation Relation) {
|
|||||||
func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
|
func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
|
||||||
for k, v := range values {
|
for k, v := range values {
|
||||||
t.Run("CheckField/"+k, func(t *testing.T) {
|
t.Run("CheckField/"+k, func(t *testing.T) {
|
||||||
fv, _ := s.FieldsByDBName[k].ValueOf(value)
|
fv, _ := s.FieldsByDBName[k].ValueOf(context.Background(), value)
|
||||||
tests.AssertEqual(t, v, fv)
|
tests.AssertEqual(t, v, fv)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -36,17 +36,14 @@ func IsValidDBNameChar(c rune) bool {
|
|||||||
return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
|
return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckTruth(val interface{}) bool {
|
// CheckTruth check string true or not
|
||||||
if v, ok := val.(bool); ok {
|
func CheckTruth(vals ...string) bool {
|
||||||
return v
|
for _, val := range vals {
|
||||||
|
if !strings.EqualFold(val, "false") && val != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
if v, ok := val.(string); ok {
|
|
||||||
v = strings.ToLower(v)
|
|
||||||
return v != "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
return !reflect.ValueOf(val).IsZero()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToStringKey(values ...interface{}) string {
|
func ToStringKey(values ...interface{}) string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user