// // Copyright 2026 The InfiniFlow Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package utility import ( "encoding/json" "fmt" "os" "strconv" "strings" "time" ) // JSONFloat64 is a float64 that always marshals with decimal point type JSONFloat64 float64 func (f JSONFloat64) MarshalJSON() ([]byte, error) { // Always output with decimal point (e.g., 0.0 instead of 0) return []byte(fmt.Sprintf("%.1f", float64(f))), nil } // GetProjectBaseDirectory returns the current working directory. // If an error occurs while getting the current directory, it returns ".". // // Returns: // - string: The current working directory path, or "." if an error occurs. // // Example: // // baseDir := utility.GetProjectBaseDirectory() // configPath := filepath.Join(baseDir, "conf", "config.json") func GetProjectBaseDirectory() string { cwd, err := os.Getwd() if err != nil { return "." } return cwd } // StringPtr converts a string to a pointer of string. // If the input string is empty, it returns nil. // // Parameters: // - s: The string to convert to a pointer. // // Returns: // - *string: A pointer to the input string, or nil if the input is empty. // // Example: // // name := utility.StringPtr("example") // returns &"example" // empty := utility.StringPtr("") // returns nil func StringPtr(s string) *string { if s == "" { return nil } return &s } // ParseInt64 parses a string to int64. // If parsing fails, it returns 0. // // Parameters: // - s: The string to parse. // // Returns: // - int64: The parsed integer value, or 0 if parsing fails. // // Example: // // val := utility.ParseInt64("123") // returns 123 // val := utility.ParseInt64("abc") // returns 0 // val := utility.ParseInt64("") // returns 0 func ParseInt64(s string) int64 { var result int64 fmt.Sscanf(s, "%d", &result) return result } // FormatTime formats time for display func FormatTime(t time.Time) string { if t.IsZero() { return "N/A (Perpetual)" } return t.Format("2006-01-02 15:04:05") } // FormatTimeToString converts time.Time to string in specified format func FormatTimeToString(t *time.Time, format string) interface{} { if t == nil { return nil } return t.Format(format) } // ConvertHexToPositionIntArray converts hex string to position int array (grouped by 5) func ConvertHexToPositionIntArray(hexStr string) interface{} { if hexStr == "" { return nil } parts := strings.Split(hexStr, "_") var intVals []int for _, part := range parts { if part == "" { continue } val, err := strconv.ParseInt(part, 16, 64) if err != nil { continue } intVals = append(intVals, int(val)) } if len(intVals) == 0 { return nil } // Group by 5 elements var result [][]int for i := 0; i < len(intVals); i += 5 { end := i + 5 if end > len(intVals) { end = len(intVals) } result = append(result, intVals[i:end]) } return result } // ConvertPositionIntArrayToHex converts position_int list (2D) to hex string // e.g. [[1,2],[3,4]] -> "0000000100000002_0000000300000004" func ConvertPositionIntArrayToHex(list []interface{}) string { var hexParts []string for _, item := range list { if inner, ok := item.([]interface{}); ok { for _, num := range inner { if n, ok := num.(float64); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", int64(n))) } else if n, ok := num.(int64); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", n)) } else if n, ok := num.(int); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", n)) } } } } return strings.Join(hexParts, "_") } // ConvertHexToIntArray converts hex string to int array (split by "_") func ConvertHexToIntArray(hexStr string) interface{} { if hexStr == "" { return nil } parts := strings.Split(hexStr, "_") var result []int for _, part := range parts { if part == "" { continue } val, err := strconv.ParseInt(part, 16, 64) if err != nil { continue } result = append(result, int(val)) } if len(result) == 0 { return nil } return result } // ConvertIntArrayToHex converts int array to hex string // e.g. [1, 2] -> "00000001_00000002" func ConvertIntArrayToHex(list []interface{}) string { var hexParts []string for _, num := range list { if n, ok := num.(float64); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", int64(n))) } else if n, ok := num.(int64); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", n)) } else if n, ok := num.(int); ok { hexParts = append(hexParts, fmt.Sprintf("%08x", n)) } } return strings.Join(hexParts, "_") } // IsEmpty checks if value is empty (nil, empty array, or empty string) func IsEmpty(v interface{}) bool { if v == nil { return true } if arr, ok := v.([]interface{}); ok { return len(arr) == 0 } if arr, ok := v.([]string); ok { return len(arr) == 0 } if arr, ok := v.([]int); ok { return len(arr) == 0 } if strVal, ok := v.(string); ok && strVal == "" { return true } return false } // IsNumericValue checks if a value is numeric (int, uint, float, or numeric string) func IsNumericValue(v interface{}) bool { if v == nil { return false } switch val := v.(type) { case int, int8, int16, int32, int64: return true case uint, uint8, uint16, uint32, uint64: return true case float32, float64: return true case string: _, err := strconv.ParseFloat(val, 64) return err == nil default: return false } } // SetFieldArray copies value to dest key, or sets empty array if value is empty func SetFieldArray(result map[string]interface{}, destKey string, v interface{}) { if IsEmpty(v) { result[destKey] = []interface{}{} } else { result[destKey] = v } } // ToFloat64 converts various types to float64 func ToFloat64(val interface{}) (float64, bool) { switch v := val.(type) { case float64: return v, true case float32: return float64(v), true case int: return float64(v), true case int64: return float64(v), true case string: f, err := strconv.ParseFloat(v, 64) if err != nil { return 0, false } return f, true default: return 0, false } } // ConvertToStringSlice converts an interface{} to []string // e.g. []interface{}{"a", "b", "c"} -> []string{"a", "b", "c"} // e.g. "hello" -> []string{"hello"} func ConvertToStringSlice(v interface{}) []string { if v == nil { return nil } switch val := v.(type) { case []interface{}: result := make([]string, 0, len(val)) for _, item := range val { if s, ok := item.(string); ok { result = append(result, s) } else { result = append(result, fmt.Sprintf("%v", item)) } } return result case []string: return val case string: return []string{val} default: return nil } } // ConvertToString converts an interface{} to space-separated string // For []interface{}, joins elements with space; for other types, returns string representation // e.g. []interface{}{"a", "b", "c"} -> "a b c" // e.g. "hello" -> "hello" func ConvertToString(v interface{}) string { if v == nil { return "" } switch val := v.(type) { case []interface{}: parts := make([]string, 0, len(val)) for _, item := range val { if s, ok := item.(string); ok { parts = append(parts, s) } else { parts = append(parts, fmt.Sprintf("%v", item)) } } return strings.Join(parts, " ") default: return fmt.Sprintf("%v", v) } } // ConvertMapToJSONString converts a map to JSON string for Infinity JSON columns // If v is a map[string]interface{}, marshals it to JSON string // If v is nil, returns "{}" // Otherwise returns v as-is // // e.g. map[string]interface{}{"key": "value"}) -> `"{\"key\":\"value\"}"` func ConvertMapToJSONString(v interface{}) interface{} { if v == nil { return "{}" } if m, ok := v.(map[string]interface{}); ok { jsonBytes, _ := json.Marshal(m) return string(jsonBytes) } return v } // FloatToString formats a float like Python's str() - adds ".0" if needed func FloatToString(f float64) string { s := strconv.FormatFloat(f, 'f', -1, 64) if !strings.Contains(s, ".") && !strings.Contains(s, "e") { s = s + ".0" } return s }