azkustodata/value/value.go (110 lines of code) (raw):

/* Package value holds Kusto data value representations. All types provide a Kusto that stores the native value and Valid which indicates if the value was set or was null. # Kusto Value A value.Kusto can hold types that represent Kusto Scalar types that define column data. We represent that with an interface: type Kusto interface This interface can hold the following values: value.Bool value.Int value.Long value.Real value.Decimal value.String value.Dynamic value.DateTime value.Timespan Each type defined above has at minimum two fields: .Value - The type specific value .Valid - True if the value was non-null in the Kusto table Each provides at minimum the following two methods: .String() - Returns the string representation of the value. .Unmarshal() - Unmarshals the value into a standard Go type. The Unmarshal() is for internal use, it should not be needed by an end user. Use .Value or table.Row.ToStruct() instead. */ package value import ( "fmt" "github.com/Azure/azure-kusto-go/azkustodata/errors" "github.com/Azure/azure-kusto-go/azkustodata/types" "reflect" ) type pointerValue[T any] struct { value *T } func newPointerValue[T any](v *T) pointerValue[T] { return pointerValue[T]{value: v} } func (p *pointerValue[T]) String() string { if p.value == nil { return "" } return fmt.Sprintf("%v", *p.value) } func (p *pointerValue[T]) GetValue() interface{} { return p.value } func (p *pointerValue[T]) Ptr() *T { return p.value } func convertError(expected interface{}, actual interface{}) error { if ref, ok := actual.(reflect.Value); ok { return errors.ES(errors.OpTableAccess, errors.KWrongColumnType, "column with type '%T' had value that was %v", expected, ref.Type()) } return errors.ES(errors.OpTableAccess, errors.KWrongColumnType, "column with type '%T' had value that was %T", expected, actual) } func parseError(expected interface{}, actual interface{}, err error) error { return errors.ES(errors.OpTableAccess, errors.KFailedToParse, "column with type '%T' had value %s which did not parse: %s", expected, actual, err) } func (p *pointerValue[T]) Unmarshal(i interface{}) error { if i == nil { p.value = nil return nil } v, ok := i.(T) if !ok { return convertError(p, i) } p.value = &v return nil } func TryConvert[T any](holder interface{}, p *pointerValue[T], v reflect.Value) bool { t := v.Type() if holder == nil || p.value == nil { v.Set(reflect.Zero(t)) return true } if reflect.TypeOf(*p.value).ConvertibleTo(t) { v.Set(reflect.ValueOf(*p.value).Convert(t)) return true } if reflect.TypeOf(p.value).ConvertibleTo(t) { v.Set(reflect.ValueOf(p.value).Convert(t)) return true } if reflect.TypeOf(holder).ConvertibleTo(t) { v.Set(reflect.ValueOf(holder).Convert(t)) return true } if reflect.TypeOf(&holder).ConvertibleTo(t) { v.Set(reflect.ValueOf(&holder).Convert(t)) return true } return false } func Convert[T any](holder interface{}, p *pointerValue[T], v reflect.Value) error { if !TryConvert[T](holder, p, v) { return convertError(holder, v) } return nil } // Kusto represents a Kusto value. type Kusto interface { fmt.Stringer Convert(v reflect.Value) error GetValue() interface{} GetType() types.Column Unmarshal(interface{}) error } func Default(t types.Column) Kusto { switch t { case types.Bool: return NewNullBool() case types.Int: return NewNullInt() case types.Long: return NewNullLong() case types.Real: return NewNullReal() case types.Decimal: return NewNullDecimal() case types.String: return NewString("") case types.Dynamic: return NewNullDynamic() case types.DateTime: return NewNullDateTime() case types.Timespan: return NewNullTimespan() case types.GUID: return NewNullGUID() default: return nil } } // Values is a list of Kusto values, usually an ordered row. type Values []Kusto