You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.2 KiB
157 lines
4.2 KiB
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) |
|
} |
|
|
|
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) |
|
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 { |
|
err = field.Set(ctx, dst, t.Time) |
|
} |
|
|
|
return |
|
} |
|
|
|
// Value implements serializer interface |
|
func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) { |
|
switch v := fieldValue.(type) { |
|
case int64, int, uint, uint64, int32, uint32, int16, uint16: |
|
result = time.Unix(reflect.ValueOf(v).Int(), 0) |
|
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) |
|
} |
|
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 |
|
}
|
|
|