From 3a09b29c62c36685aeda52dd1a1328f836455e44 Mon Sep 17 00:00:00 2001 From: kaidaguerre Date: Wed, 8 Nov 2023 07:10:03 -0600 Subject: [PATCH] Add `AnySliceToTypedSlice` and `ToTypedSlice`. Closes #78 --- hcl_helpers/convert.go | 88 -------- hcl_helpers/convert_test.go | 37 ---- hcl_helpers/hcl_blocks.go | 61 ------ hcl_helpers/traversal.go | 64 ------ {type_conversion => helpers}/slice.go | 4 +- type_conversion/cty_conversion.go | 216 -------------------- type_conversion/postgres_conversion.go | 189 ----------------- type_conversion/postgres_conversion_test.go | 60 ------ types/convert_types.go | 146 ++++++------- 9 files changed, 75 insertions(+), 790 deletions(-) delete mode 100644 hcl_helpers/convert.go delete mode 100644 hcl_helpers/convert_test.go delete mode 100644 hcl_helpers/hcl_blocks.go delete mode 100644 hcl_helpers/traversal.go rename {type_conversion => helpers}/slice.go (92%) delete mode 100644 type_conversion/cty_conversion.go delete mode 100644 type_conversion/postgres_conversion.go delete mode 100644 type_conversion/postgres_conversion_test.go diff --git a/hcl_helpers/convert.go b/hcl_helpers/convert.go deleted file mode 100644 index f2f7d3f..0000000 --- a/hcl_helpers/convert.go +++ /dev/null @@ -1,88 +0,0 @@ -package hcl_helpers - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" - "github.com/hashicorp/hcl/v2/hclwrite" - "github.com/hashicorp/hcl/v2/json" - "github.com/turbot/go-kit/helpers" -) - -func JSONToHcl(jsonString string) (string, hcl.Diagnostics) { - converted, diags := json.Parse([]byte(jsonString), "") - if diags.HasErrors() { - return "", diags - } - - res, diags := HclBodyToHclString(converted.Body, nil) - - if diags.HasErrors() { - return "", diags - } - return res, nil -} - -// HclBodyToHclString builds a hcl string with all attributes in the connection config which are NOT specified in the coneciton block schema -// this is passed to the plugin who will validate and parse it -func HclBodyToHclString(body hcl.Body, excludeContent *hcl.BodyContent) (string, hcl.Diagnostics) { - var diags hcl.Diagnostics - f := hclwrite.NewEmptyFile() - rootBody := f.Body() - - // this is a bit messy - // we want to extract the attributes which are NOT in the connection block schema - // the body passed in here is the 'rest' result returned from a partial decode, meaning all attributes and blocks - // in the schema are marked as 'hidden' - - // body.JustAttributes() returns all attributes which are not hidden (i.e. all attributes NOT in the schema) - // - // however when calling JustAttributes for a hcl body, it will fail if there are any blocks - // therefore this code will fail for hcl connection config which has any child blocks (e.g connection options) - // - // it does work however for a json body as this implementation treats blocks as attributes, - // so the options block is treated as a hidden attribute and excluded - // we therefore need to treaty hcl and json body separately - - // store map of attribute expressions - attrExpressionMap := make(map[string]hcl.Expression) - - if hclBody, ok := body.(*hclsyntax.Body); ok { - // if we can cast to a hcl body, read all the attributes and manually exclude those which are in the schema - for name, attr := range hclBody.Attributes { - // if excludeContent was passed, exclude attributes we have already handled - if excludeContent != nil { - if _, ok := excludeContent.Attributes[name]; ok { - continue - } - } - - attrExpressionMap[name] = attr.Expr - - } - } else { - // so the body was not hcl - we assume it is json - // try to call JustAttributes - attrs, diags := body.JustAttributes() - if diags.HasErrors() { - return "", diags - } - // the attributes returned will only be the ones not in the schema, i.e. we do not need to filter them ourselves - for name, attr := range attrs { - attrExpressionMap[name] = attr.Expr - } - } - - // build ordered list attributes - var sortedKeys = helpers.SortedMapKeys(attrExpressionMap) - for _, name := range sortedKeys { - expr := attrExpressionMap[name] - val, moreDiags := expr.Value(nil) - if moreDiags.HasErrors() { - diags = append(diags, moreDiags...) - } else { - rootBody.SetAttributeValue(name, val) - } - } - - return string(f.Bytes()), diags -} diff --git a/hcl_helpers/convert_test.go b/hcl_helpers/convert_test.go deleted file mode 100644 index 8ae3870..0000000 --- a/hcl_helpers/convert_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package hcl_helpers - -import ( - "testing" -) - -type jsonToHclTestCase struct { - input string - expected string -} - -var jsonToHclTests = map[string]jsonToHclTestCase{ - "simple": { - input: `{ "profile": "foo"}`, - expected: "profile = \"foo\"\n", - }, -} - -func TestResolveAsString(t *testing.T) { - for name, test := range jsonToHclTests { - - res, err := JSONToHcl(test.input) - if err != nil { - if test.expected != "ERROR" { - t.Errorf("Test: '%s'' FAILED : \nunexpected error %v", name, err) - } - continue - } - if test.expected == "ERROR" { - t.Errorf("Test: '%s'' FAILED - expected error", name) - continue - } - if test.expected != res { - t.Errorf("Test: '%s'' FAILED : \nexpected:\n %v, \ngot:\n %v\n", name, test.expected, res) - } - } -} diff --git a/hcl_helpers/hcl_blocks.go b/hcl_helpers/hcl_blocks.go deleted file mode 100644 index 499db16..0000000 --- a/hcl_helpers/hcl_blocks.go +++ /dev/null @@ -1,61 +0,0 @@ -package hcl_helpers - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/hclsyntax" -) - -func GetFirstBlockOfType(blocks hcl.Blocks, blockType string) *hcl.Block { - for _, block := range blocks { - if block.Type == blockType { - return block - } - } - return nil -} - -func FindChildBlocks(parentBlock *hcl.Block, blockType string) hcl.Blocks { - var res hcl.Blocks - childBlocks := parentBlock.Body.(*hclsyntax.Body).Blocks - for _, b := range childBlocks { - if b.Type == blockType { - res = append(res, b.AsHCLBlock()) - } - } - return res -} -func FindFirstChildBlock(parentBlock *hcl.Block, blockType string) *hcl.Block { - childBlocks := FindChildBlocks(parentBlock, blockType) - if len(childBlocks) == 0 { - return nil - } - return childBlocks[0] -} - -// BlocksToMap convert an array of blocks to a map keyed by block laabel -// NOTE: this panics if any blocks do not have a label -func BlocksToMap(blocks hcl.Blocks) map[string]*hcl.Block { - res := make(map[string]*hcl.Block, len(blocks)) - for _, b := range blocks { - if len(b.Labels) == 0 { - panic("all blocks passed to BlocksToMap must have a label") - } - res[b.Labels[0]] = b - } - return res -} - -func BlockRange(block *hcl.Block) hcl.Range { - if hclBody, ok := block.Body.(*hclsyntax.Body); ok { - return hclBody.SrcRange - } - return block.DefRange -} -func BlockRangePointer(block *hcl.Block) *hcl.Range { - r := BlockRange(block) - return &r -} -func HclSyntaxBlockRangePointer(block *hclsyntax.Block) *hcl.Range { - r := block.Range() - return &r -} diff --git a/hcl_helpers/traversal.go b/hcl_helpers/traversal.go deleted file mode 100644 index d775876..0000000 --- a/hcl_helpers/traversal.go +++ /dev/null @@ -1,64 +0,0 @@ -package hcl_helpers - -import ( - "github.com/hashicorp/hcl/v2" - "github.com/turbot/go-kit/type_conversion" - "strings" -) - -// TraversalAsString converts a traversal to a path string -// (if an absolute traversal is passed - convert to relative) -func TraversalAsString(traversal hcl.Traversal) string { - var parts = make([]string, len(traversal)) - offset := 0 - - if !traversal.IsRelative() { - s := traversal.SimpleSplit() - parts[0] = s.Abs.RootName() - offset++ - traversal = s.Rel - } - for i, r := range traversal { - switch t := r.(type) { - case hcl.TraverseAttr: - parts[i+offset] = t.Name - case hcl.TraverseIndex: - idx, err := type_conversion.CtyToString(t.Key) - if err != nil { - // we do not expect this to fail - continue - } - parts[i+offset] = idx - } - } - return strings.Join(parts, ".") -} - -func TraversalsEqual(t1, t2 hcl.Traversal) bool { - return TraversalAsString(t1) == TraversalAsString(t2) -} - -// ResourceNameFromTraversal converts a traversal to the name of the referenced resource -// We must take into account possible mod-name as first traversal element -func ResourceNameFromTraversal(resourceType string, traversal hcl.Traversal) (string, bool) { - traversalString := TraversalAsString(traversal) - split := strings.Split(traversalString, ".") - - // the resource reference will be of the form - // var. - // or - // .. - // or - // ... - - if split[0] == "var" { - return strings.Join(split, "."), true - } - if len(split) >= 2 && split[0] == resourceType { - return strings.Join(split[:2], "."), true - } - if len(split) >= 3 && split[1] == resourceType { - return strings.Join(split[:3], "."), true - } - return "", false -} diff --git a/type_conversion/slice.go b/helpers/slice.go similarity index 92% rename from type_conversion/slice.go rename to helpers/slice.go index e9ac2a8..12caffd 100644 --- a/type_conversion/slice.go +++ b/helpers/slice.go @@ -1,4 +1,4 @@ -package type_conversion +package helpers import ( "reflect" @@ -8,7 +8,7 @@ import ( // AnySliceToTypedSlice determines whether input is []any and if so converts to an array of the underlying type func AnySliceToTypedSlice(input any) any { result := input - switch result.(type) { + switch result.(type) { //nolint:gocritic // TODO fix this gocritic lint suggestion case []any: val := reflect.ValueOf(result) if val.Kind() == reflect.Slice { diff --git a/type_conversion/cty_conversion.go b/type_conversion/cty_conversion.go deleted file mode 100644 index 97dbac2..0000000 --- a/type_conversion/cty_conversion.go +++ /dev/null @@ -1,216 +0,0 @@ -package type_conversion - -import ( - "fmt" - "strings" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/gocty" - "github.com/zclconf/go-cty/cty/json" -) - -// CtyToJSON converts a cty value to it;s JSON representation -func CtyToJSON(val cty.Value) (string, error) { - - if !val.IsWhollyKnown() { - return "", fmt.Errorf("cannot serialize unknown values") - } - - if val.IsNull() { - return "{}", nil - } - - buf, err := json.Marshal(val, val.Type()) - if err != nil { - return "", err - } - - return string(buf), nil - -} - -// CtyToString convert a cty value into a string representation of the value -func CtyToString(v cty.Value) (valStr string, err error) { - if v.IsNull() || !v.IsWhollyKnown() { - return "", nil - } - ty := v.Type() - switch { - case ty.IsTupleType(), ty.IsListType(): - { - var array []string - if array, err = ctyTupleToArrayOfPgStrings(v); err == nil { - valStr = fmt.Sprintf("[%s]", strings.Join(array, ",")) - } - return - } - } - - switch ty { - case cty.Bool: - var target bool - if err = gocty.FromCtyValue(v, &target); err == nil { - valStr = fmt.Sprintf("%v", target) - } - case cty.Number: - var target int - if err = gocty.FromCtyValue(v, &target); err == nil { - valStr = fmt.Sprintf("%d", target) - } else { - var targetf float64 - if err = gocty.FromCtyValue(v, &targetf); err == nil { - valStr = fmt.Sprintf("%d", target) - } - } - case cty.String: - var target string - if err := gocty.FromCtyValue(v, &target); err == nil { - valStr = target - } - default: - var json string - // wrap as postgres string - if json, err = CtyToJSON(v); err == nil { - valStr = json - } - - } - - return valStr, err -} - -func CtyToGo(v cty.Value) (val interface{}, err error) { - if v.IsNull() { - return nil, nil - } - ty := v.Type() - switch { - case ty.IsTupleType(), ty.IsListType(): - { - var array []string - if array, err = ctyTupleToArrayOfStrings(v); err == nil { - val = array - } - return - } - } - - switch ty { - case cty.Bool: - var target bool - if err = gocty.FromCtyValue(v, &target); err == nil { - val = target - } - - case cty.Number: - var target int - if err = gocty.FromCtyValue(v, &target); err == nil { - val = target - } else { - var targetf float64 - if err = gocty.FromCtyValue(v, &targetf); err == nil { - val = targetf - } - } - case cty.String: - var target string - if err := gocty.FromCtyValue(v, &target); err == nil { - val = target - } - - default: - var json string - // wrap as postgres string - if json, err = CtyToJSON(v); err == nil { - val = json - } - } - - return -} - -// CtyTypeToHclType converts a cty type to a hcl type -// accept multiple types and use the first non null and non dynamic one -func CtyTypeToHclType(types ...cty.Type) string { - // find which if any of the types are non nil and not dynamic - t := getKnownType(types) - if t == cty.NilType { - return "" - } - - friendlyName := t.FriendlyName() - - // func to convert from ctyt aggregate syntax to hcl - convertAggregate := func(prefix string) (string, bool) { - if strings.HasPrefix(friendlyName, prefix) { - return fmt.Sprintf("%s(%s)", strings.TrimSuffix(prefix, " of "), strings.TrimPrefix(friendlyName, prefix)), true - } - return "", false - } - - if convertedName, isList := convertAggregate("list of "); isList { - return convertedName - } - if convertedName, isMap := convertAggregate("map of "); isMap { - return convertedName - } - if convertedName, isSet := convertAggregate("set of "); isSet { - return convertedName - } - if friendlyName == "tuple" { - elementTypes := t.TupleElementTypes() - if len(elementTypes) == 0 { - // we cannot determine the eleemnt type - return "list" - } - // if there are element types, use the first one (assume homogeneous) - underlyingType := elementTypes[0] - return fmt.Sprintf("list(%s)", CtyTypeToHclType(underlyingType)) - } - if friendlyName == "dynamic" { - return "" - } - return friendlyName -} - -// from a list oif cty typoes, return the first which is non nil and not dynamic -func getKnownType(types []cty.Type) cty.Type { - for _, t := range types { - if t != cty.NilType && !t.HasDynamicTypes() { - return t - } - } - return cty.NilType -} - -func ctyTupleToArrayOfPgStrings(val cty.Value) ([]string, error) { - var res []string - it := val.ElementIterator() - for it.Next() { - _, v := it.Element() - // decode the value into a postgres compatible - valStr, err := CtyToPostgresString(v) - if err != nil { - return nil, err - } - - res = append(res, valStr) - } - return res, nil -} - -func ctyTupleToArrayOfStrings(val cty.Value) ([]string, error) { - res := []string{} - it := val.ElementIterator() - for it.Next() { - _, v := it.Element() - - var valStr string - if err := gocty.FromCtyValue(v, &valStr); err != nil { - return nil, err - } - - res = append(res, valStr) - } - return res, nil -} diff --git a/type_conversion/postgres_conversion.go b/type_conversion/postgres_conversion.go deleted file mode 100644 index 01bd348..0000000 --- a/type_conversion/postgres_conversion.go +++ /dev/null @@ -1,189 +0,0 @@ -package type_conversion - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "log" - "reflect" - "strconv" - "strings" - "time" - - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/gocty" -) - -// GoToPostgresString convert a go value into a postgres representation of the value -func GoToPostgresString(v any) (string, error) { - // pass false to indicate we want a slice to be returned as a PostgresSlice - return goToPostgresString(v, false) -} - -func goToPostgresString(v any, sliceAsJson bool) (string, error) { - var str string - - switch arg := v.(type) { - case nil: - str = "null" - case int: - str = strconv.FormatInt(int64(arg), 10) - case int64: - str = strconv.FormatInt(arg, 10) - case float64: - str = strconv.FormatFloat(arg, 'f', -1, 64) - case bool: - str = strconv.FormatBool(arg) - case []byte: - str = QuotePostgresBytes(arg) - case string: - str = QuotePostgresString(arg) - case time.Time: - str = arg.Truncate(time.Microsecond).Format("'2006-01-02 15:04:05.999999999Z07:00:00'") - default: - if !sliceAsJson { - // is this an array - val := reflect.ValueOf(v) - - if val.Kind() == reflect.Slice { - return goSliceToPostgresString(val) - - } - } - - jsonBytes, err := json.Marshal(v) - if err != nil { - return "", err - } - - return fmt.Sprintf("'%s'::jsonb", string(jsonBytes)), nil - } - return str, nil -} - -func goSliceToPostgresString(val reflect.Value) (string, error) { - len := val.Len() - if len == 0 { - return "array[]", nil - } - - var elemStrings = make([]string, len) - - var postgresArrayType string - for i := 0; i < len; i++ { - elem := val.Index(i).Interface() - - t := pgArraySuffixFromElem(elem) - - if postgresArrayType == "" { - postgresArrayType = t - } else { - // all elements must be same type - if t != postgresArrayType { - return "", fmt.Errorf("goSliceToPostgresString failed: all elements of slice must bve the same type") - } - } - - // pass true to indicate we want a slice to be returned as JSON - str, err := goToPostgresString(elem, true) - if err != nil { - return "", err - } - elemStrings[i] = str - } - res := fmt.Sprintf("array[%s]::%s", strings.Join(elemStrings, ","), postgresArrayType) - return res, nil -} - -func pgArraySuffixFromElem(elem any) string { - k := reflect.ValueOf(elem).Kind() - log.Println(k) - switch elem.(type) { - case string: - return "text[]" - case bool: - return "bool[]" - case int, int8, int16, int32, int64, float32, float64: - return "numeric[]" - case time.Time: - return "time[]" - default: - return "jsonb[]" - } -} - -// CtyToPostgresString convert a cty value into a postgres representation of the value -func CtyToPostgresString(v cty.Value) (valStr string, err error) { - ty := v.Type() - - if ty.IsTupleType() || ty.IsListType() { - return ctyListToPostgresString(v, ty) - } - - switch ty { - case cty.Bool: - var target bool - if err = gocty.FromCtyValue(v, &target); err == nil { - valStr = fmt.Sprintf("%v", target) - } - case cty.Number: - var target int - if err = gocty.FromCtyValue(v, &target); err == nil { - valStr = fmt.Sprintf("%d", target) - return - } else { - var targetf float64 - if err = gocty.FromCtyValue(v, &targetf); err == nil { - valStr = fmt.Sprintf("%f", targetf) - } - } - case cty.String: - var target string - if err := gocty.FromCtyValue(v, &target); err == nil { - valStr = QuotePostgresString(target) - } - default: - var json string - // wrap as postgres string - if json, err = CtyToJSON(v); err == nil { - valStr = fmt.Sprintf("'%s'::jsonb", json) - } - } - - return valStr, err -} - -// QuotePostgresString taken from github.com/jackc/pgx/v5@v4.17.2/internal/sanitize/sanitize.go -func QuotePostgresString(str string) string { - return "'" + strings.ReplaceAll(str, "'", "''") + "'" -} - -// QuotePostgresBytes taken from github.com/jackc/pgx/v5@v4.17.2/internal/sanitize/sanitize.go -func QuotePostgresBytes(buf []byte) string { - return `'\x` + hex.EncodeToString(buf) + "'" -} - -func ctyListToPostgresString(v cty.Value, ty cty.Type) (string, error) { - var valStr string - array, err := ctyTupleToArrayOfPgStrings(v) - if err != nil { - return "", err - } - - suffix := "" - if len(array) == 0 { - t := ty.ElementType() - // cast the empty array to the appropriate type - switch t.FriendlyName() { - case "string": - suffix = "::text[]" - case "bool": - suffix = "::bool[]" - case "number": - suffix = "::numeric[]" - } - } - valStr = fmt.Sprintf("array[%s]%s", strings.Join(array, ","), suffix) - - return valStr, nil -} diff --git a/type_conversion/postgres_conversion_test.go b/type_conversion/postgres_conversion_test.go deleted file mode 100644 index 54305ad..0000000 --- a/type_conversion/postgres_conversion_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package type_conversion - -import ( - "testing" -) - -type goToPostgresTest struct { - input any - expected any -} - -var goToPostgresTestCases = map[string]goToPostgresTest{ - "int": { - input: 1, expected: "1", - }, - "float": { - input: 1.1, expected: "1.1", - }, - "string": { - input: "foo", expected: "'foo'", - }, - "string slice": { - input: []string{"foo", "bar"}, expected: `array['foo','bar']::text[]`, - }, - "string interface slice": { - input: []any{"foo", "bar"}, expected: `array['foo','bar']::text[]`, - }, - "int slice": { - input: []int{1, 2}, expected: `array[1,2]::numeric[]`, - }, - "int any slice": { - input: []any{1, 2}, expected: `array[1,2]::numeric[]`, - }, - "slice of arrays": { - input: []any{[]int{1, 2}, []int{3, 4}}, expected: `array['[1,2]'::jsonb,'[3,4]'::jsonb]::jsonb[]`, - }, - - "any slice mixed types": { - input: []any{1, "foo"}, expected: `ERROR`, - }, -} - -func TestGoToPostgres(t *testing.T) { - for name, test := range goToPostgresTestCases { - res, err := GoToPostgresString(test.input) - if err != nil { - if test.expected != "ERROR" { - t.Errorf("Test: '%s'' FAILED : \nunexpected error %v", name, err) - } - continue - } - if test.expected == "ERROR" { - t.Errorf("Test: '%s'' FAILED - expected error", name) - continue - } - if test.expected != res { - t.Errorf("Test: '%s'' FAILED : \nexpected:\n %v, \ngot:\n %v\n", name, test.expected, res) - } - } -} diff --git a/types/convert_types.go b/types/convert_types.go index 57f683c..46cf56c 100644 --- a/types/convert_types.go +++ b/types/convert_types.go @@ -10,14 +10,14 @@ import ( "github.com/mitchellh/mapstructure" ) -// SafeString :: convert a value from *string to string. If it is already a string, just return it +// SafeString converts a value from *string to string. If it is already a string, just return it // if the interface is not a string or *string, return empty string func SafeString(x interface{}) string { str, _ := CastString(x) return str } -// CastString :: cast an interface to a string +// CastString casts an interface to a string // if the interface is not a string or *string, return empty string and a 'false' result // This is the same as SafeString except it also returns a success flag func CastString(x interface{}) (string, bool) { @@ -30,7 +30,7 @@ func CastString(x interface{}) (string, bool) { return "", false } -// ToString :: convert most types value to a string +// ToString converts most types value to a string func ToString(x interface{}) string { switch v := x.(type) { case *string: @@ -105,7 +105,7 @@ func ToString(x interface{}) string { return fmt.Sprintf("%+v", x) } -// FloatToString :: convert interface to a string representation of a float. +// FloatToString converts interface to a string representation of a float. // Panic if interface is not convertible or parseable as a float func FloatToString(x interface{}) string { switch v := x.(type) { @@ -135,7 +135,7 @@ func FloatToString(x interface{}) string { panic(fmt.Sprintf(`invalid value '%v' passed to FloatToString`, x)) } -// IntToString :: convert interface to a string representation of an int. +// IntToString converts interface to a string representation of an int. // Panic if interface is not convertible or parseable as a int func IntToString(x interface{}) string { switch v := x.(type) { @@ -196,7 +196,7 @@ func IntToString(x interface{}) string { panic(fmt.Sprintf(`invalid value '%v' passed to IntToString`, x)) } -// ToInt64 :: convert interface to an int64 +// ToInt64 converts interface to an int64 // if interface is not convertible or parseable as an int64, return an error func ToInt64(i interface{}) (int64Val int64, err error) { defer func() { @@ -223,7 +223,7 @@ func ToInt64(i interface{}) (int64Val int64, err error) { return } -// ToFloat64 :: convert interface to an float64 +// ToFloat64 converts interface to an float64 // if interface is not convertible or parseable as a float64, return an error func ToFloat64(i interface{}) (doubleVal float64, err error) { defer func() { @@ -248,7 +248,7 @@ func ToFloat64(i interface{}) (doubleVal float64, err error) { return } -// ToTime :: convert interface to an time +// ToTime converts interface to an time // if interface is not convertible or parseable as a time, return an error func ToTime(i interface{}) (timeVal time.Time, err error) { defer func() { @@ -275,7 +275,7 @@ func ToTime(i interface{}) (timeVal time.Time, err error) { return } -// ToBoolPtr :: convert interface to a bool pointer +// ToBoolPtr converts interface to a bool pointer // if the value is nil, or there is a conversion error, return nil func ToBoolPtr(i interface{}) *bool { if i == nil { @@ -288,7 +288,7 @@ func ToBoolPtr(i interface{}) *bool { return &res } -// ToBool :: convert interface to an bool +// ToBool converts interface to an bool // if interface is not convertible or parseable as a bool, return an error func ToBool(i interface{}) (boolValue bool, err error) { defer func() { @@ -361,7 +361,7 @@ func StringValue(v *string) string { return "" } -// StringSlice :: convert a slice of string values into a slice of +// StringSlice converts a slice of string values into a slice of // string pointers func StringSlice(src []string) []*string { dst := make([]*string, len(src)) @@ -371,7 +371,7 @@ func StringSlice(src []string) []*string { return dst } -// StringValueSlice :: convert a slice of string pointers into a slice of +// StringValueSlice converts a slice of string pointers into a slice of // string values func StringValueSlice(src []*string) []string { dst := make([]string, len(src)) @@ -383,7 +383,7 @@ func StringValueSlice(src []*string) []string { return dst } -// Float64SliceToStringSlice :: convert a slice of float64 into a slice of +// Float64SliceToStringSlice converts a slice of float64 into a slice of // string values func Float64SliceToStringSlice(src []float64) []string { dst := make([]string, len(src)) @@ -393,7 +393,7 @@ func Float64SliceToStringSlice(src []float64) []string { return dst } -// StringMap :: convert a string map of string values into a string +// StringMap converts a string map of string values into a string // map of string pointers func StringMap(src map[string]string) map[string]*string { dst := make(map[string]*string) @@ -404,7 +404,7 @@ func StringMap(src map[string]string) map[string]*string { return dst } -// StringValueMap :: convert a string map of string pointers into a string +// StringValueMap converts a string map of string pointers into a string // map of string values func StringValueMap(src map[string]*string) map[string]string { dst := make(map[string]string) @@ -430,7 +430,7 @@ func BoolValue(v *bool) bool { return false } -// BoolSlice :: convert a slice of bool values into a slice of +// BoolSlice converts a slice of bool values into a slice of // bool pointers func BoolSlice(src []bool) []*bool { dst := make([]*bool, len(src)) @@ -440,7 +440,7 @@ func BoolSlice(src []bool) []*bool { return dst } -// BoolValueSlice :: convert a slice of bool pointers into a slice of +// BoolValueSlice converts a slice of bool pointers into a slice of // bool values func BoolValueSlice(src []*bool) []bool { dst := make([]bool, len(src)) @@ -452,7 +452,7 @@ func BoolValueSlice(src []*bool) []bool { return dst } -// BoolMap :: convert a string map of bool values into a string +// BoolMap converts a string map of bool values into a string // map of bool pointers func BoolMap(src map[string]bool) map[string]*bool { dst := make(map[string]*bool) @@ -463,7 +463,7 @@ func BoolMap(src map[string]bool) map[string]*bool { return dst } -// BoolValueMap :: convert a string map of bool pointers into a string +// BoolValueMap converts a string map of bool pointers into a string // map of bool values func BoolValueMap(src map[string]*bool) map[string]bool { dst := make(map[string]bool) @@ -489,7 +489,7 @@ func IntValue(v *int) int { return 0 } -// IntSlice :: convert a slice of int values into a slice of +// IntSlice converts a slice of int values into a slice of // int pointers func IntSlice(src []int) []*int { dst := make([]*int, len(src)) @@ -499,7 +499,7 @@ func IntSlice(src []int) []*int { return dst } -// IntValueSlice :: convert a slice of int pointers into a slice of +// IntValueSlice converts a slice of int pointers into a slice of // int values func IntValueSlice(src []*int) []int { dst := make([]int, len(src)) @@ -511,7 +511,7 @@ func IntValueSlice(src []*int) []int { return dst } -// IntMap :: convert a string map of int values into a string +// IntMap converts a string map of int values into a string // map of int pointers func IntMap(src map[string]int) map[string]*int { dst := make(map[string]*int) @@ -522,7 +522,7 @@ func IntMap(src map[string]int) map[string]*int { return dst } -// IntValueMap :: convert a string map of int pointers into a string +// IntValueMap converts a string map of int pointers into a string // map of int values func IntValueMap(src map[string]*int) map[string]int { dst := make(map[string]int) @@ -548,7 +548,7 @@ func UintValue(v *uint) uint { return 0 } -// UintSlice :: convert a slice of uint values uinto a slice of +// UintSlice converts a slice of uint values uinto a slice of // uint pointers func UintSlice(src []uint) []*uint { dst := make([]*uint, len(src)) @@ -558,7 +558,7 @@ func UintSlice(src []uint) []*uint { return dst } -// UintValueSlice :: convert a slice of uint pointers uinto a slice of +// UintValueSlice converts a slice of uint pointers uinto a slice of // uint values func UintValueSlice(src []*uint) []uint { dst := make([]uint, len(src)) @@ -570,7 +570,7 @@ func UintValueSlice(src []*uint) []uint { return dst } -// UintMap :: convert a string map of uint values uinto a string +// UintMap converts a string map of uint values uinto a string // map of uint pointers func UintMap(src map[string]uint) map[string]*uint { dst := make(map[string]*uint) @@ -581,7 +581,7 @@ func UintMap(src map[string]uint) map[string]*uint { return dst } -// UintValueMap :: convert a string map of uint pointers uinto a string +// UintValueMap converts a string map of uint pointers uinto a string // map of uint values func UintValueMap(src map[string]*uint) map[string]uint { dst := make(map[string]uint) @@ -607,7 +607,7 @@ func Int8Value(v *int8) int8 { return 0 } -// Int8Slice :: convert a slice of int8 values into a slice of +// Int8Slice converts a slice of int8 values into a slice of // int8 pointers func Int8Slice(src []int8) []*int8 { dst := make([]*int8, len(src)) @@ -617,7 +617,7 @@ func Int8Slice(src []int8) []*int8 { return dst } -// Int8ValueSlice :: convert a slice of int8 pointers into a slice of +// Int8ValueSlice converts a slice of int8 pointers into a slice of // int8 values func Int8ValueSlice(src []*int8) []int8 { dst := make([]int8, len(src)) @@ -629,7 +629,7 @@ func Int8ValueSlice(src []*int8) []int8 { return dst } -// Int8Map :: convert a string map of int8 values into a string +// Int8Map converts a string map of int8 values into a string // map of int8 pointers func Int8Map(src map[string]int8) map[string]*int8 { dst := make(map[string]*int8) @@ -640,7 +640,7 @@ func Int8Map(src map[string]int8) map[string]*int8 { return dst } -// Int8ValueMap :: convert a string map of int8 pointers into a string +// Int8ValueMap converts a string map of int8 pointers into a string // map of int8 values func Int8ValueMap(src map[string]*int8) map[string]int8 { dst := make(map[string]int8) @@ -666,7 +666,7 @@ func Int16Value(v *int16) int16 { return 0 } -// Int16Slice :: convert a slice of int16 values into a slice of +// Int16Slice converts a slice of int16 values into a slice of // int16 pointers func Int16Slice(src []int16) []*int16 { dst := make([]*int16, len(src)) @@ -676,7 +676,7 @@ func Int16Slice(src []int16) []*int16 { return dst } -// Int16ValueSlice :: convert a slice of int16 pointers into a slice of +// Int16ValueSlice converts a slice of int16 pointers into a slice of // int16 values func Int16ValueSlice(src []*int16) []int16 { dst := make([]int16, len(src)) @@ -688,7 +688,7 @@ func Int16ValueSlice(src []*int16) []int16 { return dst } -// Int16Map :: convert a string map of int16 values into a string +// Int16Map converts a string map of int16 values into a string // map of int16 pointers func Int16Map(src map[string]int16) map[string]*int16 { dst := make(map[string]*int16) @@ -699,7 +699,7 @@ func Int16Map(src map[string]int16) map[string]*int16 { return dst } -// Int16ValueMap :: convert a string map of int16 pointers into a string +// Int16ValueMap converts a string map of int16 pointers into a string // map of int16 values func Int16ValueMap(src map[string]*int16) map[string]int16 { dst := make(map[string]int16) @@ -725,7 +725,7 @@ func Int32Value(v *int32) int32 { return 0 } -// Int32Slice :: convert a slice of int32 values into a slice of +// Int32Slice converts a slice of int32 values into a slice of // int32 pointers func Int32Slice(src []int32) []*int32 { dst := make([]*int32, len(src)) @@ -735,7 +735,7 @@ func Int32Slice(src []int32) []*int32 { return dst } -// Int32ValueSlice :: convert a slice of int32 pointers into a slice of +// Int32ValueSlice converts a slice of int32 pointers into a slice of // int32 values func Int32ValueSlice(src []*int32) []int32 { dst := make([]int32, len(src)) @@ -747,7 +747,7 @@ func Int32ValueSlice(src []*int32) []int32 { return dst } -// Int32Map :: convert a string map of int32 values into a string +// Int32Map converts a string map of int32 values into a string // map of int32 pointers func Int32Map(src map[string]int32) map[string]*int32 { dst := make(map[string]*int32) @@ -758,7 +758,7 @@ func Int32Map(src map[string]int32) map[string]*int32 { return dst } -// Int32ValueMap :: convert a string map of int32 pointers into a string +// Int32ValueMap converts a string map of int32 pointers into a string // map of int32 values func Int32ValueMap(src map[string]*int32) map[string]int32 { dst := make(map[string]int32) @@ -784,7 +784,7 @@ func Int64Value(v *int64) int64 { return 0 } -// Int64Slice :: convert a slice of int64 values into a slice of +// Int64Slice converts a slice of int64 values into a slice of // int64 pointers func Int64Slice(src []int64) []*int64 { dst := make([]*int64, len(src)) @@ -794,7 +794,7 @@ func Int64Slice(src []int64) []*int64 { return dst } -// Int64ValueSlice :: convert a slice of int64 pointers into a slice of +// Int64ValueSlice converts a slice of int64 pointers into a slice of // int64 values func Int64ValueSlice(src []*int64) []int64 { dst := make([]int64, len(src)) @@ -806,7 +806,7 @@ func Int64ValueSlice(src []*int64) []int64 { return dst } -// Int64Map :: convert a string map of int64 values into a string +// Int64Map converts a string map of int64 values into a string // map of int64 pointers func Int64Map(src map[string]int64) map[string]*int64 { dst := make(map[string]*int64) @@ -817,7 +817,7 @@ func Int64Map(src map[string]int64) map[string]*int64 { return dst } -// Int64ValueMap :: convert a string map of int64 pointers into a string +// Int64ValueMap converts a string map of int64 pointers into a string // map of int64 values func Int64ValueMap(src map[string]*int64) map[string]int64 { dst := make(map[string]int64) @@ -843,7 +843,7 @@ func Uint8Value(v *uint8) uint8 { return 0 } -// Uint8Slice :: convert a slice of uint8 values into a slice of +// Uint8Slice converts a slice of uint8 values into a slice of // uint8 pointers func Uint8Slice(src []uint8) []*uint8 { dst := make([]*uint8, len(src)) @@ -853,7 +853,7 @@ func Uint8Slice(src []uint8) []*uint8 { return dst } -// Uint8ValueSlice :: convert a slice of uint8 pointers into a slice of +// Uint8ValueSlice converts a slice of uint8 pointers into a slice of // uint8 values func Uint8ValueSlice(src []*uint8) []uint8 { dst := make([]uint8, len(src)) @@ -865,7 +865,7 @@ func Uint8ValueSlice(src []*uint8) []uint8 { return dst } -// Uint8Map :: convert a string map of uint8 values into a string +// Uint8Map converts a string map of uint8 values into a string // map of uint8 pointers func Uint8Map(src map[string]uint8) map[string]*uint8 { dst := make(map[string]*uint8) @@ -876,7 +876,7 @@ func Uint8Map(src map[string]uint8) map[string]*uint8 { return dst } -// Uint8ValueMap :: convert a string map of uint8 pointers into a string +// Uint8ValueMap converts a string map of uint8 pointers into a string // map of uint8 values func Uint8ValueMap(src map[string]*uint8) map[string]uint8 { dst := make(map[string]uint8) @@ -902,7 +902,7 @@ func Uint16Value(v *uint16) uint16 { return 0 } -// Uint16Slice :: convert a slice of uint16 values into a slice of +// Uint16Slice converts a slice of uint16 values into a slice of // uint16 pointers func Uint16Slice(src []uint16) []*uint16 { dst := make([]*uint16, len(src)) @@ -912,7 +912,7 @@ func Uint16Slice(src []uint16) []*uint16 { return dst } -// Uint16ValueSlice :: convert a slice of uint16 pointers into a slice of +// Uint16ValueSlice converts a slice of uint16 pointers into a slice of // uint16 values func Uint16ValueSlice(src []*uint16) []uint16 { dst := make([]uint16, len(src)) @@ -924,7 +924,7 @@ func Uint16ValueSlice(src []*uint16) []uint16 { return dst } -// Uint16Map :: convert a string map of uint16 values into a string +// Uint16Map converts a string map of uint16 values into a string // map of uint16 pointers func Uint16Map(src map[string]uint16) map[string]*uint16 { dst := make(map[string]*uint16) @@ -935,7 +935,7 @@ func Uint16Map(src map[string]uint16) map[string]*uint16 { return dst } -// Uint16ValueMap :: convert a string map of uint16 pointers into a string +// Uint16ValueMap converts a string map of uint16 pointers into a string // map of uint16 values func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { dst := make(map[string]uint16) @@ -961,7 +961,7 @@ func Uint32Value(v *uint32) uint32 { return 0 } -// Uint32Slice :: convert a slice of uint32 values into a slice of +// Uint32Slice converts a slice of uint32 values into a slice of // uint32 pointers func Uint32Slice(src []uint32) []*uint32 { dst := make([]*uint32, len(src)) @@ -971,7 +971,7 @@ func Uint32Slice(src []uint32) []*uint32 { return dst } -// Uint32ValueSlice :: convert a slice of uint32 pointers into a slice of +// Uint32ValueSlice converts a slice of uint32 pointers into a slice of // uint32 values func Uint32ValueSlice(src []*uint32) []uint32 { dst := make([]uint32, len(src)) @@ -983,7 +983,7 @@ func Uint32ValueSlice(src []*uint32) []uint32 { return dst } -// Uint32Map :: convert a string map of uint32 values into a string +// Uint32Map converts a string map of uint32 values into a string // map of uint32 pointers func Uint32Map(src map[string]uint32) map[string]*uint32 { dst := make(map[string]*uint32) @@ -994,7 +994,7 @@ func Uint32Map(src map[string]uint32) map[string]*uint32 { return dst } -// Uint32ValueMap :: convert a string map of uint32 pointers into a string +// Uint32ValueMap converts a string map of uint32 pointers into a string // map of uint32 values func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { dst := make(map[string]uint32) @@ -1020,7 +1020,7 @@ func Uint64Value(v *uint64) uint64 { return 0 } -// Uint64Slice :: convert a slice of uint64 values into a slice of +// Uint64Slice converts a slice of uint64 values into a slice of // uint64 pointers func Uint64Slice(src []uint64) []*uint64 { dst := make([]*uint64, len(src)) @@ -1030,7 +1030,7 @@ func Uint64Slice(src []uint64) []*uint64 { return dst } -// Uint64ValueSlice :: convert a slice of uint64 pointers into a slice of +// Uint64ValueSlice converts a slice of uint64 pointers into a slice of // uint64 values func Uint64ValueSlice(src []*uint64) []uint64 { dst := make([]uint64, len(src)) @@ -1042,7 +1042,7 @@ func Uint64ValueSlice(src []*uint64) []uint64 { return dst } -// Uint64Map :: convert a string map of uint64 values into a string +// Uint64Map converts a string map of uint64 values into a string // map of uint64 pointers func Uint64Map(src map[string]uint64) map[string]*uint64 { dst := make(map[string]*uint64) @@ -1053,7 +1053,7 @@ func Uint64Map(src map[string]uint64) map[string]*uint64 { return dst } -// Uint64ValueMap :: convert a string map of uint64 pointers into a string +// Uint64ValueMap converts a string map of uint64 pointers into a string // map of uint64 values func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { dst := make(map[string]uint64) @@ -1079,7 +1079,7 @@ func Float32Value(v *float32) float32 { return 0 } -// Float32Slice :: convert a slice of float32 values into a slice of +// Float32Slice converts a slice of float32 values into a slice of // float32 pointers func Float32Slice(src []float32) []*float32 { dst := make([]*float32, len(src)) @@ -1089,7 +1089,7 @@ func Float32Slice(src []float32) []*float32 { return dst } -// Float32ValueSlice :: convert a slice of float32 pointers into a slice of +// Float32ValueSlice converts a slice of float32 pointers into a slice of // float32 values func Float32ValueSlice(src []*float32) []float32 { dst := make([]float32, len(src)) @@ -1101,7 +1101,7 @@ func Float32ValueSlice(src []*float32) []float32 { return dst } -// Float32Map :: convert a string map of float32 values into a string +// Float32Map converts a string map of float32 values into a string // map of float32 pointers func Float32Map(src map[string]float32) map[string]*float32 { dst := make(map[string]*float32) @@ -1112,7 +1112,7 @@ func Float32Map(src map[string]float32) map[string]*float32 { return dst } -// Float32ValueMap :: convert a string map of float32 pointers into a string +// Float32ValueMap converts a string map of float32 pointers into a string // map of float32 values func Float32ValueMap(src map[string]*float32) map[string]float32 { dst := make(map[string]float32) @@ -1138,7 +1138,7 @@ func Float64Value(v *float64) float64 { return 0 } -// Float64Slice :: convert a slice of float64 values into a slice of +// Float64Slice converts a slice of float64 values into a slice of // float64 pointers func Float64Slice(src []float64) []*float64 { dst := make([]*float64, len(src)) @@ -1148,7 +1148,7 @@ func Float64Slice(src []float64) []*float64 { return dst } -// Float64ValueSlice :: convert a slice of float64 pointers into a slice of +// Float64ValueSlice converts a slice of float64 pointers into a slice of // float64 values func Float64ValueSlice(src []*float64) []float64 { dst := make([]float64, len(src)) @@ -1160,7 +1160,7 @@ func Float64ValueSlice(src []*float64) []float64 { return dst } -// Float64Map :: convert a string map of float64 values into a string +// Float64Map converts a string map of float64 values into a string // map of float64 pointers func Float64Map(src map[string]float64) map[string]*float64 { dst := make(map[string]*float64) @@ -1171,7 +1171,7 @@ func Float64Map(src map[string]float64) map[string]*float64 { return dst } -// Float64ValueMap :: convert a string map of float64 pointers into a string +// Float64ValueMap converts a string map of float64 pointers into a string // map of float64 values func Float64ValueMap(src map[string]*float64) map[string]float64 { dst := make(map[string]float64) @@ -1197,7 +1197,7 @@ func TimeValue(v *time.Time) time.Time { return time.Time{} } -// SecondsTimeValue :: convert an int64 pointer to a time.Time value +// SecondsTimeValue converts an int64 pointer to a time.Time value // representing seconds since Epoch or time.Time{} if the pointer is nil. func SecondsTimeValue(v *int64) time.Time { if v != nil { @@ -1206,7 +1206,7 @@ func SecondsTimeValue(v *int64) time.Time { return time.Time{} } -// MillisecondsTimeValue :: convert an int64 pointer to a time.Time value +// MillisecondsTimeValue converts an int64 pointer to a time.Time value // representing milliseconds sinch Epoch or time.Time{} if the pointer is nil. func MillisecondsTimeValue(v *int64) time.Time { if v != nil { @@ -1227,7 +1227,7 @@ func TimeUnixMilli(t time.Time) int64 { return t.UnixNano() / int64(time.Millisecond/time.Nanosecond) } -// TimeSlice :: convert a slice of time.Time values into a slice of +// TimeSlice converts a slice of time.Time values into a slice of // time.Time pointers func TimeSlice(src []time.Time) []*time.Time { dst := make([]*time.Time, len(src)) @@ -1237,7 +1237,7 @@ func TimeSlice(src []time.Time) []*time.Time { return dst } -// TimeValueSlice :: convert a slice of time.Time pointers into a slice of +// TimeValueSlice converts a slice of time.Time pointers into a slice of // time.Time values func TimeValueSlice(src []*time.Time) []time.Time { dst := make([]time.Time, len(src)) @@ -1249,7 +1249,7 @@ func TimeValueSlice(src []*time.Time) []time.Time { return dst } -// TimeMap :: convert a string map of time.Time values into a string +// TimeMap converts a string map of time.Time values into a string // map of time.Time pointers func TimeMap(src map[string]time.Time) map[string]*time.Time { dst := make(map[string]*time.Time) @@ -1260,7 +1260,7 @@ func TimeMap(src map[string]time.Time) map[string]*time.Time { return dst } -// TimeValueMap :: convert a string map of time.Time pointers into a string +// TimeValueMap converts a string map of time.Time pointers into a string // map of time.Time values func TimeValueMap(src map[string]*time.Time) map[string]time.Time { dst := make(map[string]time.Time)