feat: support gob serialize (#5108)
This commit is contained in:
		
							parent
							
								
									45ef1da7e4
								
							
						
					
					
						commit
						3741f258d0
					
				| @ -1,11 +1,12 @@ | |||||||
| package schema | package schema | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"database/sql" | 	"database/sql" | ||||||
| 	"database/sql/driver" | 	"database/sql/driver" | ||||||
|  | 	"encoding/gob" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| @ -32,6 +33,7 @@ func GetSerializer(name string) (serializer SerializerInterface, ok bool) { | |||||||
| func init() { | func init() { | ||||||
| 	RegisterSerializer("json", JSONSerializer{}) | 	RegisterSerializer("json", JSONSerializer{}) | ||||||
| 	RegisterSerializer("unixtime", UnixSecondSerializer{}) | 	RegisterSerializer("unixtime", UnixSecondSerializer{}) | ||||||
|  | 	RegisterSerializer("gob", GobSerializer{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Serializer field value serializer
 | // Serializer field value serializer
 | ||||||
| @ -83,7 +85,7 @@ func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, | |||||||
| 		case string: | 		case string: | ||||||
| 			bytes = []byte(v) | 			bytes = []byte(v) | ||||||
| 		default: | 		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()) | 		err = json.Unmarshal(bytes, fieldValue.Interface()) | ||||||
| @ -123,3 +125,33 @@ func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect | |||||||
| 	} | 	} | ||||||
| 	return | 	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 | ||||||
|  | } | ||||||
|  | |||||||
| @ -19,11 +19,20 @@ type SerializerStruct struct { | |||||||
| 	Name            []byte                 `gorm:"json"` | 	Name            []byte                 `gorm:"json"` | ||||||
| 	Roles           Roles                  `gorm:"serializer:json"` | 	Roles           Roles                  `gorm:"serializer:json"` | ||||||
| 	Contracts       map[string]interface{} `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
 | 	CreatedTime     int64                  `gorm:"serializer:unixtime;type:time"` // store time in db, use int as field type
 | ||||||
| 	EncryptedString EncryptedString | 	EncryptedString EncryptedString | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Roles []string | type Roles []string | ||||||
|  | 
 | ||||||
|  | type Job struct { | ||||||
|  | 	Title    string | ||||||
|  | 	Number   int | ||||||
|  | 	Location string | ||||||
|  | 	IsIntern bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type EncryptedString string | type EncryptedString string | ||||||
| 
 | 
 | ||||||
| func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) { | 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}, | 		Contracts:       map[string]interface{}{"name": "jinzhu", "age": 10}, | ||||||
| 		EncryptedString: EncryptedString("pass"), | 		EncryptedString: EncryptedString("pass"), | ||||||
| 		CreatedTime:     createdAt.Unix(), | 		CreatedTime:     createdAt.Unix(), | ||||||
|  | 		JobInfo: Job{ | ||||||
|  | 			Title:    "programmer", | ||||||
|  | 			Number:   9920, | ||||||
|  | 			Location: "Kenmawr", | ||||||
|  | 			IsIntern: false, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := DB.Create(&data).Error; err != nil { | 	if err := DB.Create(&data).Error; err != nil { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 jing1
						jing1