171 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package schema
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"database/sql"
 | |
| 	"database/sql/driver"
 | |
| 	"encoding/gob"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| var serializerMap = sync.Map{}
 | |
| 
 | |
| // RegisterSerializer register serializer
 | |
| func RegisterSerializer(name string, serializer SerializerInterface) {
 | |
| 	serializerMap.Store(strings.ToLower(name), serializer)
 | |
| }
 | |
| 
 | |
| // GetSerializer get serializer
 | |
| func GetSerializer(name string) (serializer SerializerInterface, ok bool) {
 | |
| 	v, ok := serializerMap.Load(strings.ToLower(name))
 | |
| 	if ok {
 | |
| 		serializer, ok = v.(SerializerInterface)
 | |
| 	}
 | |
| 	return serializer, ok
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	RegisterSerializer("json", JSONSerializer{})
 | |
| 	RegisterSerializer("unixtime", UnixSecondSerializer{})
 | |
| 	RegisterSerializer("gob", GobSerializer{})
 | |
| }
 | |
| 
 | |
| // Serializer field value serializer
 | |
| type serializer struct {
 | |
| 	Field           *Field
 | |
| 	Serializer      SerializerInterface
 | |
| 	SerializeValuer SerializerValuerInterface
 | |
| 	Destination     reflect.Value
 | |
| 	Context         context.Context
 | |
| 	value           interface{}
 | |
| 	fieldValue      interface{}
 | |
| }
 | |
| 
 | |
| // Scan implements sql.Scanner interface
 | |
| func (s *serializer) Scan(value interface{}) error {
 | |
| 	s.value = value
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Value implements driver.Valuer interface
 | |
| func (s serializer) Value() (driver.Value, error) {
 | |
| 	return s.SerializeValuer.Value(s.Context, s.Field, s.Destination, s.fieldValue)
 | |
| }
 | |
| 
 | |
| // SerializerInterface serializer interface
 | |
| type SerializerInterface interface {
 | |
| 	Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
 | |
| 	SerializerValuerInterface
 | |
| }
 | |
| 
 | |
| // SerializerValuerInterface serializer valuer interface
 | |
| type SerializerValuerInterface interface {
 | |
| 	Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
 | |
| }
 | |
| 
 | |
| // JSONSerializer json serializer
 | |
| type JSONSerializer struct{}
 | |
| 
 | |
| // Scan implements serializer interface
 | |
| func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
 | |
| 	fieldValue := reflect.New(field.FieldType)
 | |
| 
 | |
| 	if dbValue != nil {
 | |
| 		var bytes []byte
 | |
| 		switch v := dbValue.(type) {
 | |
| 		case []byte:
 | |
| 			bytes = v
 | |
| 		case string:
 | |
| 			bytes = []byte(v)
 | |
| 		default:
 | |
| 			return fmt.Errorf("failed to unmarshal JSONB value: %#v", dbValue)
 | |
| 		}
 | |
| 
 | |
| 		if len(bytes) > 0 {
 | |
| 			err = json.Unmarshal(bytes, fieldValue.Interface())
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Value implements serializer interface
 | |
| func (JSONSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
 | |
| 	result, err := json.Marshal(fieldValue)
 | |
| 	if string(result) == "null" {
 | |
| 		if field.TagSettings["NOT NULL"] != "" {
 | |
| 			return "", nil
 | |
| 		}
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return string(result), err
 | |
| }
 | |
| 
 | |
| // UnixSecondSerializer json serializer
 | |
| type UnixSecondSerializer struct{}
 | |
| 
 | |
| // Scan implements serializer interface
 | |
| func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
 | |
| 	t := sql.NullTime{}
 | |
| 	if err = t.Scan(dbValue); err == nil && t.Valid {
 | |
| 		err = field.Set(ctx, dst, t.Time.Unix())
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Value implements serializer interface
 | |
| func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) {
 | |
| 	rv := reflect.ValueOf(fieldValue)
 | |
| 	switch v := fieldValue.(type) {
 | |
| 	case int64, int, uint, uint64, int32, uint32, int16, uint16:
 | |
| 		result = time.Unix(reflect.Indirect(rv).Int(), 0).UTC()
 | |
| 	case *int64, *int, *uint, *uint64, *int32, *uint32, *int16, *uint16:
 | |
| 		if rv.IsZero() {
 | |
| 			return nil, nil
 | |
| 		}
 | |
| 		result = time.Unix(reflect.Indirect(rv).Int(), 0).UTC()
 | |
| 	default:
 | |
| 		err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v)
 | |
| 	}
 | |
| 	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)
 | |
| 		}
 | |
| 		if len(bytesValue) > 0 {
 | |
| 			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
 | |
| }
 |