Add and update netquery code based on review discussions

This commit is contained in:
Patrick Pacher 2022-03-17 14:28:01 +01:00
parent 976c0a702e
commit c2d2064ec8
No known key found for this signature in database
GPG key ID: E8CD2DA160925A6D
9 changed files with 324 additions and 148 deletions

View file

@ -17,10 +17,10 @@ type (
}
)
// EncodeAsMap returns a map that contains the value of each struct field of
// ToParamMap returns a map that contains the sqlite compatible value of each struct field of
// r using the sqlite column name as a map key. It either uses the name of the
// exported struct field or the value of the "sqlite" tag.
func EncodeAsMap(ctx context.Context, r interface{}, keyPrefix string, cfg EncodeConfig) (map[string]interface{}, error) {
func ToParamMap(ctx context.Context, r interface{}, keyPrefix string, cfg EncodeConfig) (map[string]interface{}, error) {
// make sure we work on a struct type
val := reflect.Indirect(reflect.ValueOf(r))
if val.Kind() != reflect.Struct {
@ -38,12 +38,20 @@ func EncodeAsMap(ctx context.Context, r interface{}, keyPrefix string, cfg Encod
continue
}
colDev, err := getColumnDef(fieldType)
colDef, err := getColumnDef(fieldType)
if err != nil {
return nil, fmt.Errorf("failed to get column definition for %s: %w", fieldType.Name, err)
}
x, found, err := runEncodeHooks(colDev, fieldType.Type, field, cfg.EncodeHooks)
x, found, err := runEncodeHooks(
colDef,
fieldType.Type,
field,
append(
cfg.EncodeHooks,
encodeBasic(),
),
)
if err != nil {
return nil, fmt.Errorf("failed to run encode hooks: %w", err)
}
@ -61,6 +69,69 @@ func EncodeAsMap(ctx context.Context, r interface{}, keyPrefix string, cfg Encod
return res, nil
}
func EncodeValue(ctx context.Context, colDef *ColumnDef, val interface{}, cfg EncodeConfig) (interface{}, error) {
fieldValue := reflect.ValueOf(val)
fieldType := reflect.TypeOf(val)
x, found, err := runEncodeHooks(
colDef,
fieldType,
fieldValue,
append(
cfg.EncodeHooks,
encodeBasic(),
),
)
if err != nil {
return nil, fmt.Errorf("failed to run encode hooks: %w", err)
}
if !found {
if reflect.Indirect(fieldValue).IsValid() {
x = reflect.Indirect(fieldValue).Interface()
}
}
return x, nil
}
func encodeBasic() EncodeFunc {
return func(col *ColumnDef, valType reflect.Type, val reflect.Value) (interface{}, bool, error) {
kind := valType.Kind()
if kind == reflect.Ptr {
valType = valType.Elem()
kind = valType.Kind()
if val.IsNil() {
return nil, true, nil
}
val = val.Elem()
}
switch normalizeKind(kind) {
case reflect.String,
reflect.Float64,
reflect.Bool,
reflect.Int,
reflect.Uint:
// sqlite package handles conversion of those types
// already
return val.Interface(), true, nil
case reflect.Slice:
if valType.Elem().Kind() == reflect.Uint8 {
// this is []byte
return val.Interface(), true, nil
}
fallthrough
default:
return nil, false, fmt.Errorf("cannot convert value of kind %s for use in SQLite", kind)
}
}
}
func DatetimeEncoder(loc *time.Location) EncodeFunc {
return func(colDev *ColumnDef, valType reflect.Type, val reflect.Value) (interface{}, bool, error) {
// if fieldType holds a pointer we need to dereference the value
@ -103,6 +174,10 @@ func DatetimeEncoder(loc *time.Location) EncodeFunc {
}
func runEncodeHooks(colDev *ColumnDef, valType reflect.Type, val reflect.Value, hooks []EncodeFunc) (interface{}, bool, error) {
if valType == nil {
return nil, true, nil
}
for _, fn := range hooks {
res, end, err := fn(colDev, valType, val)
if err != nil {