diff --git a/schema/serializer.go b/schema/serializer.go index 68597538..09da6d9e 100644 --- a/schema/serializer.go +++ b/schema/serializer.go @@ -1,11 +1,12 @@ package schema import ( + "bytes" "context" "database/sql" "database/sql/driver" + "encoding/gob" "encoding/json" - "errors" "fmt" "reflect" "strings" @@ -32,6 +33,7 @@ func GetSerializer(name string) (serializer SerializerInterface, ok bool) { func init() { RegisterSerializer("json", JSONSerializer{}) RegisterSerializer("unixtime", UnixSecondSerializer{}) + RegisterSerializer("gob", GobSerializer{}) } // Serializer field value serializer @@ -83,7 +85,7 @@ func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, case string: bytes = []byte(v) default: - return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", dbValue)) + return fmt.Errorf("failed to unmarshal JSONB value: %#v", dbValue) } err = json.Unmarshal(bytes, fieldValue.Interface()) @@ -123,3 +125,33 @@ func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect } return } + +// GobSerializer gob serializer +type GobSerializer struct { +} + +// Scan implements serializer interface +func (GobSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) { + fieldValue := reflect.New(field.FieldType) + + if dbValue != nil { + var bytesValue []byte + switch v := dbValue.(type) { + case []byte: + bytesValue = v + default: + return fmt.Errorf("failed to unmarshal gob value: %#v", dbValue) + } + decoder := gob.NewDecoder(bytes.NewBuffer(bytesValue)) + err = decoder.Decode(fieldValue.Interface()) + } + field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem()) + return +} + +// Value implements serializer interface +func (GobSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) { + buf := new(bytes.Buffer) + err := gob.NewEncoder(buf).Encode(fieldValue) + return buf.Bytes(), err +} diff --git a/tests/serializer_test.go b/tests/serializer_test.go index 3ed733d9..a8a4e28f 100644 --- a/tests/serializer_test.go +++ b/tests/serializer_test.go @@ -19,11 +19,20 @@ type SerializerStruct struct { Name []byte `gorm:"json"` Roles Roles `gorm:"serializer:json"` Contracts map[string]interface{} `gorm:"serializer:json"` + JobInfo Job `gorm:"type:bytes;serializer:gob"` CreatedTime int64 `gorm:"serializer:unixtime;type:time"` // store time in db, use int as field type EncryptedString EncryptedString } type Roles []string + +type Job struct { + Title string + Number int + Location string + IsIntern bool +} + type EncryptedString string func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) { @@ -56,6 +65,12 @@ func TestSerializer(t *testing.T) { Contracts: map[string]interface{}{"name": "jinzhu", "age": 10}, EncryptedString: EncryptedString("pass"), CreatedTime: createdAt.Unix(), + JobInfo: Job{ + Title: "programmer", + Number: 9920, + Location: "Kenmawr", + IsIntern: false, + }, } if err := DB.Create(&data).Error; err != nil {