ToLiteral converts a Go value to its corresponding SQL literal representation. It handles primitive types and lists. All other types are emitted as JSON-encoded strings.
(val any)
| 13 | // ToLiteral converts a Go value to its corresponding SQL literal representation. |
| 14 | // It handles primitive types and lists. All other types are emitted as JSON-encoded strings. |
| 15 | func ToLiteral(val any) string { |
| 16 | if val == nil { |
| 17 | return "NULL" |
| 18 | } |
| 19 | |
| 20 | v := reflect.ValueOf(val) |
| 21 | |
| 22 | // Unwrap pointers |
| 23 | for v.Kind() == reflect.Ptr { |
| 24 | if v.IsNil() { |
| 25 | return "NULL" |
| 26 | } |
| 27 | v = v.Elem() |
| 28 | } |
| 29 | |
| 30 | // Check for time.Time after unwrapping pointers |
| 31 | if v.Type() == reflect.TypeOf(time.Time{}) { |
| 32 | return "'" + v.Interface().(time.Time).Format(time.RFC3339Nano) + "'" |
| 33 | } |
| 34 | |
| 35 | switch v.Kind() { |
| 36 | case reflect.String: |
| 37 | return "'" + strings.ReplaceAll(v.String(), "'", "''") + "'" |
| 38 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| 39 | return strconv.FormatInt(v.Int(), 10) |
| 40 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| 41 | return strconv.FormatUint(v.Uint(), 10) |
| 42 | case reflect.Float32: |
| 43 | return strconv.FormatFloat(v.Float(), 'f', -1, 32) |
| 44 | case reflect.Float64: |
| 45 | return strconv.FormatFloat(v.Float(), 'f', -1, 64) |
| 46 | case reflect.Bool: |
| 47 | if v.Bool() { |
| 48 | return "TRUE" |
| 49 | } |
| 50 | return "FALSE" |
| 51 | case reflect.Slice, reflect.Array: |
| 52 | // []byte → hex literal |
| 53 | if v.Type().Elem().Kind() == reflect.Uint8 { |
| 54 | return "X'" + hex.EncodeToString(v.Bytes()) + "'" |
| 55 | } |
| 56 | if v.Len() == 0 { |
| 57 | return "(NULL)" |
| 58 | } |
| 59 | parts := make([]string, v.Len()) |
| 60 | for i := range parts { |
| 61 | parts[i] = ToLiteral(v.Index(i).Interface()) |
| 62 | } |
| 63 | return "(" + strings.Join(parts, ", ") + ")" |
| 64 | default: |
| 65 | // Fallback: JSON-encode and treat as string |
| 66 | b, err := json.Marshal(v.Interface()) |
| 67 | if err != nil { |
| 68 | b = fmt.Appendf([]byte{}, "<json error: %s>", err.Error()) |
| 69 | } |
| 70 | return "'" + strings.ReplaceAll(string(b), "'", "''") + "'" |
| 71 | } |
| 72 | } |