From 2807299d4660d50967ba6e3b78a41ca0384695eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Sun, 28 May 2023 22:55:06 +0200 Subject: [PATCH] v0.0.127 --- confext/confParser.go | 15 +++++++ confext/confParser_test.go | 4 ++ sq/converter.go | 91 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 sq/converter.go diff --git a/confext/confParser.go b/confext/confParser.go index 86250e4..1978f7b 100644 --- a/confext/confParser.go +++ b/confext/confParser.go @@ -8,6 +8,7 @@ import ( "os" "reflect" "strconv" + "strings" "time" ) @@ -172,6 +173,20 @@ func parseEnvToValue(envval string, fullEnvKey string, rvtype reflect.Type) (ref return envcvl, nil + } else if rvtype.ConvertibleTo(reflect.TypeOf(false)) { + + if strings.TrimSpace(strings.ToLower(envval)) == "true" { + return reflect.ValueOf(true).Convert(rvtype), nil + } else if strings.TrimSpace(strings.ToLower(envval)) == "false" { + return reflect.ValueOf(true).Convert(rvtype), nil + } else if strings.TrimSpace(strings.ToLower(envval)) == "1" { + return reflect.ValueOf(false).Convert(rvtype), nil + } else if strings.TrimSpace(strings.ToLower(envval)) == "0" { + return reflect.ValueOf(false).Convert(rvtype), nil + } else { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to <%s, ,bool> (value := '%s')", rvtype.Name(), fullEnvKey, envval)) + } + } else if rvtype.ConvertibleTo(reflect.TypeOf("")) { envcvl := reflect.ValueOf(envval).Convert(rvtype) diff --git a/confext/confParser_test.go b/confext/confParser_test.go index c2fdbd8..6540692 100644 --- a/confext/confParser_test.go +++ b/confext/confParser_test.go @@ -68,6 +68,7 @@ func TestApplyEnvOverridesSimple(t *testing.T) { V7 aliasstring `env:"TEST_V7"` V8 time.Duration `env:"TEST_V8"` V9 time.Time `env:"TEST_V9"` + VA bool `env:"TEST_VA"` } data := testdata{ @@ -82,6 +83,7 @@ func TestApplyEnvOverridesSimple(t *testing.T) { V7: "7", V8: 9, V9: time.Unix(1671102873, 0), + VA: false, } t.Setenv("TEST_V1", "846") @@ -93,6 +95,7 @@ func TestApplyEnvOverridesSimple(t *testing.T) { t.Setenv("TEST_V7", "AAAAAA") t.Setenv("TEST_V8", "1min4s") t.Setenv("TEST_V9", "2009-11-10T23:00:00Z") + t.Setenv("TEST_VA", "true") err := ApplyEnvOverrides("", &data, ".") if err != nil { @@ -109,6 +112,7 @@ func TestApplyEnvOverridesSimple(t *testing.T) { tst.AssertEqual(t, data.V7, "AAAAAA") tst.AssertEqual(t, data.V8, time.Second*64) tst.AssertEqual(t, data.V9, time.Unix(1257894000, 0).UTC()) + tst.AssertEqual(t, data.VA, true) } func TestApplyEnvOverridesRecursive(t *testing.T) { diff --git a/sq/converter.go b/sq/converter.go new file mode 100644 index 0000000..a3d2352 --- /dev/null +++ b/sq/converter.go @@ -0,0 +1,91 @@ +package sq + +import ( + "errors" + "fmt" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "time" +) + +//TODO UNFINISHED +// this is not finished +// idea was that we can register converter in the database struct +// they get inherited from the transactions +// and when marshallingunmarshaling (sq.Query | sq.QueryAll) +// or marshaling (sq.InsertSingle) +// the types get converter automatically... + +type DBTypeConverter interface { + ModelTypeString() string + DBTypeString() string + ModelToDB(v any) (any, error) + DBToModel(v any) (any, error) +} + +var ConverterBoolToBit = NewDBTypeConverter[bool, int](func(v bool) (int, error) { + return langext.Conditional(v, 1, 0), nil +}, func(v int) (bool, error) { + if v == 0 { + return false, nil + } + if v == 1 { + return true, nil + } + return false, errors.New(fmt.Sprintf("invalid valud for boolean: '%d'", v)) +}) + +var ConverterTimeToUnixMillis = NewDBTypeConverter[time.Time, int64](func(v time.Time) (int64, error) { + return v.UnixMilli(), nil +}, func(v int64) (time.Time, error) { + return time.UnixMilli(v), nil +}) + +var ConverterOptTimeToUnixMillis = NewDBTypeConverter[*time.Time, *int64](func(v *time.Time) (*int64, error) { + if v == nil { + return nil, nil + } + return langext.Ptr(v.UnixMilli()), nil +}, func(v *int64) (*time.Time, error) { + if v == nil { + return nil, nil + } + return langext.Ptr(time.UnixMilli(*v)), nil +}) + +type dbTypeConverterImpl[TModelData any, TDBData any] struct { + dbTypeString string + modelTypeString string + todb func(v TModelData) (TDBData, error) + tomodel func(v TDBData) (TModelData, error) +} + +func (t *dbTypeConverterImpl[TModelData, TDBData]) ModelTypeString() string { + return t.modelTypeString +} + +func (t *dbTypeConverterImpl[TModelData, TDBData]) DBTypeString() string { + return t.dbTypeString +} + +func (t *dbTypeConverterImpl[TModelData, TDBData]) ModelToDB(v any) (any, error) { + if vv, ok := v.(TModelData); ok { + return t.todb(vv) + } + return nil, errors.New(fmt.Sprintf("Unexpected value in DBTypeConverter, expected '%s', found '%T'", t.modelTypeString, v)) +} + +func (t *dbTypeConverterImpl[TModelData, TDBData]) DBToModel(v any) (any, error) { + if vv, ok := v.(TDBData); ok { + return t.tomodel(vv) + } + return nil, errors.New(fmt.Sprintf("Unexpected value in DBTypeConverter, expected '%s', found '%T'", t.dbTypeString, v)) +} + +func NewDBTypeConverter[TModelData any, TDBData any](todb func(v TModelData) (TDBData, error), tomodel func(v TDBData) (TModelData, error)) DBTypeConverter { + return &dbTypeConverterImpl[TModelData, TDBData]{ + dbTypeString: fmt.Sprintf("%T", *new(TDBData)), + modelTypeString: fmt.Sprintf("%T", *new(TModelData)), + todb: todb, + tomodel: tomodel, + } +}