mirror of
https://github.com/samuelncui/yatm.git
synced 2025-12-23 14:25:23 +00:00
74 lines
1.4 KiB
Go
74 lines
1.4 KiB
Go
package entity
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"fmt"
|
|
reflect "reflect"
|
|
sync "sync"
|
|
|
|
"github.com/modern-go/reflect2"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
var (
|
|
typeMap sync.Map
|
|
)
|
|
|
|
// Scan implement database/sql.Scanner
|
|
func Scan(dst proto.Message, src interface{}) error {
|
|
cacheKey := reflect2.RTypeOf(dst)
|
|
typ, has := loadType(cacheKey)
|
|
if !has {
|
|
ptrType := reflect.TypeOf(dst)
|
|
if ptrType.Kind() != reflect.Ptr {
|
|
return fmt.Errorf("scan dst is not an ptr, has= %T", dst)
|
|
}
|
|
|
|
typ = reflect2.Type2(ptrType.Elem())
|
|
storeType(cacheKey, typ)
|
|
}
|
|
typ.Set(dst, typ.New())
|
|
|
|
var buf []byte
|
|
switch v := src.(type) {
|
|
case string:
|
|
buf = []byte(v)
|
|
case []byte:
|
|
buf = v
|
|
case nil:
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("process define extra scanner, unexpected type for i18n, %T", v)
|
|
}
|
|
|
|
if len(buf) == 0 {
|
|
return nil
|
|
}
|
|
|
|
if err := proto.Unmarshal(buf, dst); err != nil {
|
|
return fmt.Errorf("process define extra scanner, json unmarshal fail, %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Value implement database/sql/driver.Valuer
|
|
func Value(src proto.Message) (driver.Value, error) {
|
|
buf, err := proto.Marshal(src)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("process define extra valuer, json marshal fail, %w", err)
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func loadType(key uintptr) (reflect2.Type, bool) {
|
|
i, has := typeMap.Load(key)
|
|
if !has {
|
|
return nil, false
|
|
}
|
|
return i.(reflect2.Type), true
|
|
}
|
|
|
|
func storeType(key uintptr, typ reflect2.Type) {
|
|
typeMap.Store(key, typ)
|
|
}
|