Files
2026-07-04 01:42:34 +01:00

559 lines
12 KiB
Go

package record
import (
"fmt"
"reflect"
"strconv"
)
// Record stores mixed scalar data (Boolean, numeric, and string) and provides type-safe methods to retrieve it.
// It automatically casts values where possible.
//
// https://go.dev/ref/spec#Types
type Record map[string]any
func (r Record) Bool(column string) bool {
value, _ := r.BoolSafe(column)
return value
}
func (r Record) BoolSafe(column string) (bool, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
return r[column].(bool), true
case "int":
return r[column].(int) > 0, true
case "int16":
return r[column].(int16) > 0, true
case "int32":
return r[column].(int32) > 0, true
case "int64":
return r[column].(int64) > 0, true
case "string":
if value, err := strconv.ParseBool(r[column].(string)); err == nil {
return value, true
}
case "uint":
return r[column].(uint) > 0, true
case "uint8":
return r[column].(uint8) > 0, true
case "uint16":
return r[column].(uint16) > 0, true
case "uint32":
return r[column].(uint32) > 0, true
case "uint64":
return r[column].(uint64) > 0, true
}
}
return false, false
}
func (r Record) Byte(column string) byte {
value, _ := r.ByteSafe(column)
return value
}
func (r Record) ByteSafe(column string) (byte, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "byte":
return r[column].(byte), true
case "uint8":
return byte(r[column].(uint8)), true
}
}
return byte(0), false
}
func (r Record) Float32(column string) float32 {
value, _ := r.Float32Safe(column)
return value
}
func (r Record) Float32Safe(column string) (float32, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "float32":
return r[column].(float32), true
case "float64":
return float32(r[column].(float64)), true
case "int":
return float32(r[column].(int)), true
case "int16":
return float32(r[column].(int16)), true
case "int32":
return float32(r[column].(int32)), true
case "int64":
return float32(r[column].(int64)), true
case "string":
if value, err := strconv.ParseFloat(r[column].(string), 32); err == nil {
return float32(value), true
}
case "uint":
return float32(r[column].(uint)), true
case "uint8":
return float32(r[column].(uint8)), true
case "uint16":
return float32(r[column].(uint16)), true
case "uint32":
return float32(r[column].(uint32)), true
case "uint64":
return float32(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Float64(column string) float64 {
value, _ := r.Float64Safe(column)
return value
}
func (r Record) Float64Safe(column string) (float64, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "float32":
return float64(r[column].(float32)), true
case "float64":
return r[column].(float64), true
case "int":
return float64(r[column].(int)), true
case "int16":
return float64(r[column].(int16)), true
case "int32":
return float64(r[column].(int32)), true
case "int64":
return float64(r[column].(int64)), true
case "string":
if value, err := strconv.ParseFloat(r[column].(string), 64); err == nil {
return float64(value), true
}
case "uint":
return float64(r[column].(uint)), true
case "uint8":
return float64(r[column].(uint8)), true
case "uint16":
return float64(r[column].(uint16)), true
case "uint32":
return float64(r[column].(uint32)), true
case "uint64":
return float64(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Has(column string) bool {
_, ok := r.TypeOf(column)
return ok
}
func (r Record) Int(column string) int {
value, _ := r.IntSafe(column)
return value
}
func (r Record) IntSafe(column string) (int, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return r[column].(int), true
case "int16":
return int(r[column].(int16)), true
case "int32":
return int(r[column].(int32)), true
case "int64":
return int(r[column].(int64)), true
case "string":
if value, err := strconv.ParseInt(r[column].(string), 10, 0); err == nil {
return int(value), true
}
case "uint":
return int(r[column].(uint)), true
case "uint8":
return int(r[column].(uint8)), true
case "uint16":
return int(r[column].(uint16)), true
case "uint32":
return int(r[column].(uint32)), true
case "uint64":
return int(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Int16(column string) int16 {
value, _ := r.Int16Safe(column)
return value
}
func (r Record) Int16Safe(column string) (int16, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return int16(r[column].(int)), true
case "int16":
return r[column].(int16), true
case "int32":
return int16(r[column].(int32)), true
case "int64":
return int16(r[column].(int64)), true
case "string":
if value, err := strconv.ParseInt(r[column].(string), 10, 16); err == nil {
return int16(value), true
}
case "uint":
return int16(r[column].(uint)), true
case "uint8":
return int16(r[column].(uint8)), true
case "uint16":
return int16(r[column].(uint16)), true
case "uint32":
return int16(r[column].(uint32)), true
case "uint64":
return int16(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Int32(column string) int32 {
value, _ := r.Int32Safe(column)
return value
}
func (r Record) Int32Safe(column string) (int32, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return int32(r[column].(int)), true
case "int16":
return int32(r[column].(int16)), true
case "int32":
return r[column].(int32), true
case "int64":
return int32(r[column].(int64)), true
case "string":
if value, err := strconv.ParseInt(r[column].(string), 10, 32); err == nil {
return int32(value), true
}
case "uint":
return int32(r[column].(uint)), true
case "uint8":
return int32(r[column].(uint8)), true
case "uint16":
return int32(r[column].(uint16)), true
case "uint32":
return int32(r[column].(uint32)), true
case "uint64":
return int32(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Int64(column string) int64 {
value, _ := r.Int64Safe(column)
return value
}
func (r Record) Int64Safe(column string) (int64, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return int64(r[column].(int)), true
case "int16":
return int64(r[column].(int16)), true
case "int32":
return int64(r[column].(int32)), true
case "int64":
return r[column].(int64), true
case "string":
if value, err := strconv.ParseInt(r[column].(string), 10, 64); err == nil {
return value, true
}
case "uint":
return int64(r[column].(uint)), true
case "uint8":
return int64(r[column].(uint8)), true
case "uint16":
return int64(r[column].(uint16)), true
case "uint32":
return int64(r[column].(uint32)), true
case "uint64":
return int64(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) String(column string) string {
value, _ := r.StringSafe(column)
return value
}
func (r Record) StringSafe(column string) (string, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "string":
return r[column].(string), true
default:
return fmt.Sprint(r[column]), true
}
}
return "", false
}
func (r Record) TypeOf(column string) (reflect.Type, bool) {
if r[column] != nil {
return reflect.TypeOf(r[column]), true
}
return nil, false
}
func (r Record) Uint(column string) uint {
value, _ := r.UintSafe(column)
return value
}
func (r Record) UintSafe(column string) (uint, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return uint(r[column].(int)), true
case "int16":
return uint(r[column].(int16)), true
case "int32":
return uint(r[column].(int32)), true
case "int64":
return uint(r[column].(int64)), true
case "string":
if value, err := strconv.ParseUint(r[column].(string), 10, 0); err == nil {
return uint(value), true
}
case "uint":
return r[column].(uint), true
case "uint8":
return uint(r[column].(uint8)), true
case "uint16":
return uint(r[column].(uint16)), true
case "uint32":
return uint(r[column].(uint32)), true
case "uint64":
return uint(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Uint8(column string) uint8 {
value, _ := r.Uint8Safe(column)
return value
}
func (r Record) Uint8Safe(column string) (uint8, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return uint8(r[column].(int)), true
case "int16":
return uint8(r[column].(int16)), true
case "int32":
return uint8(r[column].(int32)), true
case "int64":
return uint8(r[column].(int64)), true
case "string":
if value, err := strconv.ParseUint(r[column].(string), 10, 16); err == nil {
return uint8(value), true
}
case "uint":
return uint8(r[column].(uint)), true
case "uint8":
return r[column].(uint8), true
case "uint16":
return uint8(r[column].(uint16)), true
case "uint32":
return uint8(r[column].(uint32)), true
case "uint64":
return uint8(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Uint16(column string) uint16 {
value, _ := r.Uint16Safe(column)
return value
}
func (r Record) Uint16Safe(column string) (uint16, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return uint16(r[column].(int)), true
case "int16":
return uint16(r[column].(int16)), true
case "int32":
return uint16(r[column].(int32)), true
case "int64":
return uint16(r[column].(int64)), true
case "string":
if value, err := strconv.ParseUint(r[column].(string), 10, 16); err == nil {
return uint16(value), true
}
case "uint":
return uint16(r[column].(uint)), true
case "uint8":
return uint16(r[column].(uint8)), true
case "uint16":
return r[column].(uint16), true
case "uint32":
return uint16(r[column].(uint32)), true
case "uint64":
return uint16(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Uint32(column string) uint32 {
value, _ := r.Uint32Safe(column)
return value
}
func (r Record) Uint32Safe(column string) (uint32, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return uint32(r[column].(int)), true
case "int16":
return uint32(r[column].(int16)), true
case "int32":
return uint32(r[column].(int32)), true
case "int64":
return uint32(r[column].(int64)), true
case "string":
if value, err := strconv.ParseUint(r[column].(string), 10, 32); err == nil {
return uint32(value), true
}
case "uint":
return uint32(r[column].(uint)), true
case "uint8":
return uint32(r[column].(uint8)), true
case "uint16":
return uint32(r[column].(uint16)), true
case "uint32":
return r[column].(uint32), true
case "uint64":
return uint32(r[column].(uint64)), true
}
}
return 0, false
}
func (r Record) Uint64(column string) uint64 {
value, _ := r.Uint64Safe(column)
return value
}
func (r Record) Uint64Safe(column string) (uint64, bool) {
if t, ok := r.TypeOf(column); ok {
switch t.Name() {
case "bool":
if r[column].(bool) {
return 1, true
} else {
return 0, true
}
case "int":
return uint64(r[column].(int)), true
case "int16":
return uint64(r[column].(int16)), true
case "int32":
return uint64(r[column].(int32)), true
case "int64":
return uint64(r[column].(int64)), true
case "string":
if value, err := strconv.ParseUint(r[column].(string), 10, 64); err == nil {
return value, true
}
case "uint":
return uint64(r[column].(uint)), true
case "uint8":
return uint64(r[column].(uint8)), true
case "uint16":
return uint64(r[column].(uint16)), true
case "uint32":
return uint64(r[column].(uint32)), true
case "uint64":
return r[column].(uint64), true
}
}
return 0, false
}