559 lines
12 KiB
Go
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
|
|
}
|