diff --git a/value/bool.go b/value/bool.go new file mode 100644 index 00000000..235e9ef3 --- /dev/null +++ b/value/bool.go @@ -0,0 +1,22 @@ +package value + +import ( + "encoding/json" + "strconv" +) + +func NewBoolValue(v bool) BoolValue { + if v { + return BoolValueTrue + } + return BoolValueFalse +} + +func (m BoolValue) Nil() bool { return false } +func (m BoolValue) Err() bool { return false } +func (m BoolValue) Type() ValueType { return BoolType } +func (m BoolValue) Value() interface{} { return m.v } +func (m BoolValue) Val() bool { return m.v } +func (m BoolValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m BoolValue) ToString() string { return strconv.FormatBool(m.v) } +func (m BoolValue) IsZero() bool { return m.v == false } diff --git a/value/bool_test.go b/value/bool_test.go new file mode 100644 index 00000000..ceaa1559 --- /dev/null +++ b/value/bool_test.go @@ -0,0 +1,16 @@ +package value + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBoolValue(t *testing.T) { + vt := NewBoolValue(true) + assert.Equal(t, strconv.FormatBool(true), vt) + assert.False(t, vt.Nil()) + vf := NewBoolValue(false) + assert.True(t, vf.IsZero()) +} diff --git a/value/byteslice.go b/value/byteslice.go new file mode 100644 index 00000000..fa3df6f0 --- /dev/null +++ b/value/byteslice.go @@ -0,0 +1,17 @@ +package value + +import "encoding/json" + +func NewByteSliceValue(v []byte) ByteSliceValue { + return ByteSliceValue{v: v} +} + +func (m ByteSliceValue) Nil() bool { return len(m.v) == 0 } +func (m ByteSliceValue) Err() bool { return false } +func (m ByteSliceValue) Type() ValueType { return ByteSliceType } +func (m ByteSliceValue) Value() interface{} { return m.v } +func (m ByteSliceValue) Val() []byte { return m.v } +func (m ByteSliceValue) ToString() string { return string(m.v) } +func (m ByteSliceValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m ByteSliceValue) Len() int { return len(m.v) } +func (m ByteSliceValue) IsZero() bool { return m.Nil() } diff --git a/value/byteslice_test.go b/value/byteslice_test.go new file mode 100644 index 00000000..ed06aac2 --- /dev/null +++ b/value/byteslice_test.go @@ -0,0 +1,19 @@ +package value + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestByteSliceValue(t *testing.T) { + s := "mybyte" + v := NewByteSliceValue([]byte(s)) + assert.Equal(t, s, v.ToString()) + { + v := NewByteSliceValue([]byte{}) + assert.True(t, v.Nil()) + assert.True(t, v.IsZero()) + assert.Equal(t, 0, v.Len()) + } +} diff --git a/value/map.go b/value/map.go new file mode 100644 index 00000000..beb56358 --- /dev/null +++ b/value/map.go @@ -0,0 +1,290 @@ +package value + +import ( + "encoding/json" + "fmt" + "math" + "strconv" + "time" +) + +func NewMapValue(v map[string]interface{}) MapValue { + mv := make(map[string]Value) + for n, val := range v { + mv[n] = NewValue(val) + } + return MapValue{v: mv} +} + +func (m MapValue) Nil() bool { return len(m.v) == 0 } +func (m MapValue) Err() bool { return false } +func (m MapValue) Type() ValueType { return MapValueType } +func (m MapValue) Value() interface{} { return m.v } +func (m MapValue) Val() map[string]Value { return m.v } +func (m MapValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapValue) Len() int { return len(m.v) } +func (m MapValue) IsZero() bool { return m.Nil() } +func (m MapValue) MapInt() map[string]int64 { + mv := make(map[string]int64, len(m.v)) + for n, v := range m.v { + intVal, ok := ValueToInt64(v) + if ok { + mv[n] = intVal + } + } + return mv +} +func (m MapValue) MapFloat() map[string]float64 { + mv := make(map[string]float64, len(m.v)) + for n, v := range m.v { + fv, _ := ValueToFloat64(v) + if !math.IsNaN(fv) { + mv[n] = fv + } + } + return mv +} +func (m MapValue) MapString() map[string]string { + mv := make(map[string]string, len(m.v)) + for n, v := range m.v { + mv[n] = v.ToString() + } + return mv +} +func (m MapValue) MapValue() MapValue { + return m +} +func (m MapValue) MapTime() MapTimeValue { + mv := make(map[string]time.Time, len(m.v)) + for k, v := range m.v { + t, ok := ValueToTime(v) + if ok && !t.IsZero() { + mv[k] = t + } + } + return NewMapTimeValue(mv) +} +func (m MapValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + return v, ok +} +func NewMapStringValue(v map[string]string) MapStringValue { + return MapStringValue{v: v} +} + +func (m MapStringValue) Nil() bool { return len(m.v) == 0 } +func (m MapStringValue) Err() bool { return false } +func (m MapStringValue) Type() ValueType { return MapStringType } +func (m MapStringValue) Value() interface{} { return m.v } +func (m MapStringValue) Val() map[string]string { return m.v } +func (m MapStringValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapStringValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapStringValue) Len() int { return len(m.v) } +func (m MapStringValue) IsZero() bool { return m.Nil() } +func (m MapStringValue) MapBool() MapBoolValue { + mb := make(map[string]bool) + for n, sv := range m.Val() { + b, err := strconv.ParseBool(sv) + if err == nil { + mb[n] = b + } + } + return NewMapBoolValue(mb) +} +func (m MapStringValue) MapInt() MapIntValue { + mi := make(map[string]int64) + for n, sv := range m.Val() { + iv, err := strconv.ParseInt(sv, 10, 64) + if err == nil { + mi[n] = iv + } + } + return NewMapIntValue(mi) +} +func (m MapStringValue) MapNumber() MapNumberValue { + mn := make(map[string]float64) + for n, sv := range m.Val() { + fv, err := strconv.ParseFloat(sv, 64) + if err == nil { + mn[n] = fv + } + } + return NewMapNumberValue(mn) +} +func (m MapStringValue) MapValue() MapValue { + mv := make(map[string]Value) + for n, val := range m.v { + mv[n] = NewStringValue(val) + } + return MapValue{v: mv} +} +func (m MapStringValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + if ok { + return NewStringValue(v), ok + } + return nil, ok +} +func (m MapStringValue) SliceValue() []Value { + vs := make([]Value, 0, len(m.v)) + for k := range m.v { + vs = append(vs, NewStringValue(k)) + } + return vs +} + +func NewMapIntValue(v map[string]int64) MapIntValue { + return MapIntValue{v: v} +} + +func (m MapIntValue) Nil() bool { return len(m.v) == 0 } +func (m MapIntValue) Err() bool { return false } +func (m MapIntValue) Type() ValueType { return MapIntType } +func (m MapIntValue) Value() interface{} { return m.v } +func (m MapIntValue) Val() map[string]int64 { return m.v } +func (m MapIntValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapIntValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapIntValue) Len() int { return len(m.v) } +func (m MapIntValue) MapInt() map[string]int64 { return m.v } +func (m MapIntValue) IsZero() bool { return m.Nil() } +func (m MapIntValue) MapFloat() map[string]float64 { + mv := make(map[string]float64, len(m.v)) + for n, iv := range m.v { + mv[n] = float64(iv) + } + return mv +} +func (m MapIntValue) MapValue() MapValue { + mv := make(map[string]Value) + for n, val := range m.v { + mv[n] = NewIntValue(val) + } + return MapValue{v: mv} +} +func (m MapIntValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + if ok { + return NewIntValue(v), ok + } + return nil, ok +} +func (m MapIntValue) SliceValue() []Value { + vs := make([]Value, 0, len(m.v)) + for k := range m.v { + vs = append(vs, NewStringValue(k)) + } + return vs +} + +func NewMapNumberValue(v map[string]float64) MapNumberValue { + return MapNumberValue{v: v} +} + +func (m MapNumberValue) Nil() bool { return len(m.v) == 0 } +func (m MapNumberValue) Err() bool { return false } +func (m MapNumberValue) Type() ValueType { return MapNumberType } +func (m MapNumberValue) Value() interface{} { return m.v } +func (m MapNumberValue) Val() map[string]float64 { return m.v } +func (m MapNumberValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapNumberValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapNumberValue) Len() int { return len(m.v) } +func (m MapNumberValue) IsZero() bool { return m.Nil() } +func (m MapNumberValue) MapInt() map[string]int64 { + mv := make(map[string]int64, len(m.v)) + for n, v := range m.v { + mv[n] = int64(v) + } + return mv +} +func (m MapNumberValue) MapValue() MapValue { + mv := make(map[string]Value) + for n, val := range m.v { + mv[n] = NewNumberValue(val) + } + return MapValue{v: mv} +} +func (m MapNumberValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + if ok { + return NewNumberValue(v), ok + } + return nil, ok +} +func (m MapNumberValue) SliceValue() []Value { + vs := make([]Value, 0, len(m.v)) + for k := range m.v { + vs = append(vs, NewStringValue(k)) + } + return vs +} + +func NewMapTimeValue(v map[string]time.Time) MapTimeValue { + return MapTimeValue{v: v} +} + +func (m MapTimeValue) Nil() bool { return len(m.v) == 0 } +func (m MapTimeValue) Err() bool { return false } +func (m MapTimeValue) Type() ValueType { return MapTimeType } +func (m MapTimeValue) Value() interface{} { return m.v } +func (m MapTimeValue) Val() map[string]time.Time { return m.v } +func (m MapTimeValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapTimeValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapTimeValue) Len() int { return len(m.v) } +func (m MapTimeValue) IsZero() bool { return m.Nil() } +func (m MapTimeValue) MapInt() map[string]int64 { + mv := make(map[string]int64, len(m.v)) + for n, v := range m.v { + mv[n] = v.UnixNano() + } + return mv +} +func (m MapTimeValue) MapValue() MapValue { + mv := make(map[string]Value) + for n, val := range m.v { + mv[n] = NewTimeValue(val) + } + return MapValue{v: mv} +} +func (m MapTimeValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + if ok { + return NewTimeValue(v), ok + } + return nil, ok +} + +func NewMapBoolValue(v map[string]bool) MapBoolValue { + return MapBoolValue{v: v} +} + +func (m MapBoolValue) Nil() bool { return len(m.v) == 0 } +func (m MapBoolValue) Err() bool { return false } +func (m MapBoolValue) Type() ValueType { return MapBoolType } +func (m MapBoolValue) Value() interface{} { return m.v } +func (m MapBoolValue) Val() map[string]bool { return m.v } +func (m MapBoolValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m MapBoolValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m MapBoolValue) Len() int { return len(m.v) } +func (m MapBoolValue) IsZero() bool { return m.Nil() } +func (m MapBoolValue) MapValue() MapValue { + mv := make(map[string]Value) + for n, val := range m.v { + mv[n] = NewBoolValue(val) + } + return MapValue{v: mv} +} +func (m MapBoolValue) Get(key string) (Value, bool) { + v, ok := m.v[key] + if ok { + return NewBoolValue(v), ok + } + return nil, ok +} +func (m MapBoolValue) SliceValue() []Value { + vs := make([]Value, 0, len(m.v)) + for k := range m.v { + vs = append(vs, NewStringValue(k)) + } + return vs +} diff --git a/value/map_test.go b/value/map_test.go new file mode 100644 index 00000000..19111e2f --- /dev/null +++ b/value/map_test.go @@ -0,0 +1,133 @@ +package value + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestMapValue(t *testing.T) { + mv := map[string]interface{}{"k1": 10} + v := NewMapValue(mv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + mi := v.MapInt() + assert.Equal(t, 1, len(mi)) + assert.Equal(t, int64(10), mi["k1"]) + mf := v.MapFloat() + assert.Equal(t, 1, len(mf)) + assert.Equal(t, float64(10), mf["k1"]) + ms := v.MapString() + assert.Equal(t, 1, len(mf)) + assert.Equal(t, "10", ms["k1"]) + v = NewMapValue(map[string]interface{}{"k1": "hello"}) + mt := v.MapTime() + assert.Equal(t, 0, mt.Len()) + v = NewMapValue(map[string]interface{}{"k1": "now-4d"}) + mt = v.MapTime() + assert.Equal(t, 1, mt.Len()) + assert.True(t, mt.Val()["k1"].Unix() > 10000) +} + +func TestMapStringValue(t *testing.T) { + msv := map[string]string{"k1": "10"} + v := NewMapStringValue(msv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + lv := v.SliceValue() + assert.Equal(t, 1, len(lv)) + mi := v.MapInt() + assert.Equal(t, 1, mi.Len()) + assert.Equal(t, int64(10), mi.Val()["k1"]) + mf := v.MapNumber() + assert.Equal(t, 1, mf.Len()) + assert.Equal(t, float64(10), mf.Val()["k1"]) + mb := v.MapBool() + assert.Equal(t, 0, mb.Len()) + v = NewMapStringValue(map[string]string{"k1": "true"}) + mb = v.MapBool() + assert.Equal(t, 1, mb.Len()) + assert.Equal(t, true, mb.Val()["k1"]) +} + +func TestMapIntValue(t *testing.T) { + miv := map[string]int64{"k1": 10} + v := NewMapIntValue(miv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + lv := v.SliceValue() + assert.Equal(t, 1, len(lv)) + mi := v.MapInt() + assert.Equal(t, 1, len(mi)) + assert.Equal(t, int64(10), mi["k1"]) + mf := v.MapFloat() + assert.Equal(t, 1, len(mf)) + assert.Equal(t, float64(10), mf["k1"]) + + mv := v.MapValue() + assert.Equal(t, 1, mv.Len()) + assert.Equal(t, int64(10), mv.Val()["k1"].Value()) +} + +func TestMapNumberValue(t *testing.T) { + mfv := map[string]float64{"k1": 10} + v := NewMapNumberValue(mfv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + lv := v.SliceValue() + assert.Equal(t, 1, len(lv)) + mi := v.MapInt() + assert.Equal(t, 1, len(mi)) + assert.Equal(t, int64(10), mi["k1"]) + + mv := v.MapValue() + assert.Equal(t, 1, mv.Len()) + assert.Equal(t, float64(10), mv.Val()["k1"].Value()) +} +func TestMapTimeValue(t *testing.T) { + n := time.Now() + mtv := map[string]time.Time{"k1": n} + v := NewMapTimeValue(mtv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + + mi := v.MapInt() + assert.Equal(t, 1, len(mi)) + assert.True(t, CloseEnuf(float64(n.UnixNano()), float64(mi["k1"]))) + + mv := v.MapValue() + assert.Equal(t, 1, mv.Len()) + assert.Equal(t, n, mv.Val()["k1"].Value()) +} +func TestMapBoolValue(t *testing.T) { + + mbv := map[string]bool{"k1": true} + v := NewMapBoolValue(mbv) + _, ok := v.Get("k1") + assert.True(t, ok) + _, ok = v.Get("nope") + assert.Equal(t, false, ok) + assert.Equal(t, 1, v.MapValue().Len()) + lv := v.SliceValue() + assert.Equal(t, 1, len(lv)) + + mv := v.MapValue() + assert.Equal(t, 1, mv.Len()) + assert.Equal(t, true, mv.Val()["k1"].Value()) +} diff --git a/value/numeric.go b/value/numeric.go new file mode 100644 index 00000000..fb2e2a1c --- /dev/null +++ b/value/numeric.go @@ -0,0 +1,51 @@ +package value + +import ( + "fmt" + "math" + "strconv" +) + +func NewNumberValue(v float64) NumberValue { + return NumberValue{v: v} +} +func NewNumberNil() NumberValue { + v := NumberValue{v: math.NaN()} + return v +} +func (m NumberValue) Nil() bool { return math.IsNaN(m.v) } +func (m NumberValue) Err() bool { return math.IsNaN(m.v) } +func (m NumberValue) Type() ValueType { return NumberType } +func (m NumberValue) Value() interface{} { return m.v } +func (m NumberValue) Val() float64 { return m.v } +func (m NumberValue) MarshalJSON() ([]byte, error) { return marshalFloat(float64(m.v)) } +func (m NumberValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m NumberValue) Float() float64 { return m.v } +func (m NumberValue) Int() int64 { return int64(m.v) } +func (m NumberValue) IsZero() bool { return m.v == float64(0) } + +func NewIntValue(v int64) IntValue { + return IntValue{v: v} +} + +func NewIntNil() IntValue { + v := IntValue{v: math.MinInt32} + return v +} + +func (m IntValue) Nil() bool { return m.v == math.MinInt32 } +func (m IntValue) Err() bool { return m.v == math.MinInt32 } +func (m IntValue) Type() ValueType { return IntType } +func (m IntValue) Value() interface{} { return m.v } +func (m IntValue) Val() int64 { return m.v } +func (m IntValue) MarshalJSON() ([]byte, error) { return marshalFloat(float64(m.v)) } +func (m IntValue) NumberValue() NumberValue { return NewNumberValue(float64(m.v)) } +func (m IntValue) IsZero() bool { return m.v == int64(0) } +func (m IntValue) ToString() string { + if m.v == math.MinInt32 { + return "" + } + return strconv.FormatInt(m.v, 10) +} +func (m IntValue) Float() float64 { return float64(m.v) } +func (m IntValue) Int() int64 { return m.v } diff --git a/value/numeric_test.go b/value/numeric_test.go new file mode 100644 index 00000000..77f63be3 --- /dev/null +++ b/value/numeric_test.go @@ -0,0 +1,29 @@ +package value + +import ( + "encoding/json" + "math" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIntValue(t *testing.T) { + v := NewIntNil() + assert.True(t, v.Nil()) + assert.Equal(t, "", v.ToString()) + v = NewIntValue(32) + nv := v.NumberValue() + assert.Equal(t, nv.Int(), int64(32)) +} +func TestValueNumber(t *testing.T) { + v := NewNumberValue(math.NaN()) + _, err := json.Marshal(&v) + assert.Equal(t, nil, err) + v = NewNumberValue(math.Inf(1)) + _, err = json.Marshal(&v) + assert.Equal(t, nil, err) + v = NewNumberValue(math.Inf(-1)) + _, err = json.Marshal(&v) + assert.Equal(t, nil, err) +} diff --git a/value/slice.go b/value/slice.go new file mode 100644 index 00000000..9c64f0e6 --- /dev/null +++ b/value/slice.go @@ -0,0 +1,43 @@ +package value + +import ( + "encoding/json" + "strings" +) + +func NewSliceValues(v []Value) SliceValue { + return SliceValue{v: v} +} +func NewSliceValuesNative(iv []interface{}) SliceValue { + vs := make([]Value, len(iv)) + for i, v := range iv { + vs[i] = NewValue(v) + } + return SliceValue{v: vs} +} + +func (m SliceValue) Nil() bool { return len(m.v) == 0 } +func (m SliceValue) Err() bool { return false } +func (m SliceValue) Type() ValueType { return SliceValueType } +func (m SliceValue) Value() interface{} { return m.v } +func (m SliceValue) Val() []Value { return m.v } +func (m SliceValue) IsZero() bool { return m.Nil() } +func (m SliceValue) ToString() string { + sv := make([]string, len(m.Val())) + for i, val := range m.v { + sv[i] = val.ToString() + } + return strings.Join(sv, ",") +} + +func (m *SliceValue) Append(v Value) { m.v = append(m.v, v) } +func (m SliceValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m SliceValue) Len() int { return len(m.v) } +func (m SliceValue) SliceValue() []Value { return m.v } +func (m SliceValue) Values() []interface{} { + vals := make([]interface{}, len(m.v)) + for i, v := range m.v { + vals[i] = v.Value() + } + return vals +} diff --git a/value/slice_test.go b/value/slice_test.go new file mode 100644 index 00000000..52124832 --- /dev/null +++ b/value/slice_test.go @@ -0,0 +1,17 @@ +package value + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSliceValues(t *testing.T) { + v := NewSliceValuesNative([]interface{}{"a"}) + assert.Equal(t, 1, v.Len()) + assert.Equal(t, "a", v.Val()[0].ToString()) + v.Append(NewStringValue("b")) + assert.Equal(t, 2, v.Len()) + assert.Equal(t, "b", v.Val()[1].ToString()) + assert.Equal(t, 2, len(v.Values())) +} diff --git a/value/string.go b/value/string.go new file mode 100644 index 00000000..3cfa4941 --- /dev/null +++ b/value/string.go @@ -0,0 +1,77 @@ +package value + +import ( + "encoding/json" + "strconv" + "strings" +) + +func NewStringValue(v string) StringValue { + return StringValue{v: v} +} + +func (m StringValue) Nil() bool { return len(m.v) == 0 } +func (m StringValue) Err() bool { return false } +func (m StringValue) Type() ValueType { return StringType } +func (m StringValue) Value() interface{} { return m.v } +func (m StringValue) Val() string { return m.v } +func (m StringValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m StringValue) IsZero() bool { return m.Nil() } + +func (m StringValue) NumberValue() NumberValue { + fv, _ := StringToFloat64(m.v) + return NewNumberValue(fv) +} +func (m StringValue) StringsValue() StringsValue { return NewStringsValue([]string{m.v}) } +func (m StringValue) ToString() string { return m.v } + +func (m StringValue) IntValue() IntValue { + iv, _ := ValueToInt64(m) + return NewIntValue(iv) +} + +func NewStringsValue(v []string) StringsValue { + return StringsValue{v: v} +} + +func (m StringsValue) Nil() bool { return len(m.v) == 0 } +func (m StringsValue) Err() bool { return false } +func (m StringsValue) Type() ValueType { return StringsType } +func (m StringsValue) Value() interface{} { return m.v } +func (m StringsValue) Val() []string { return m.v } +func (m *StringsValue) Append(sv string) { m.v = append(m.v, sv) } +func (m StringsValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m StringsValue) Len() int { return len(m.v) } +func (m StringsValue) IsZero() bool { return m.Nil() } +func (m StringsValue) NumberValue() NumberValue { + if len(m.v) > 0 { + if fv, err := strconv.ParseFloat(m.v[0], 64); err == nil { + return NewNumberValue(fv) + } + } + return NumberNaNValue +} +func (m StringsValue) IntValue() IntValue { + // Im not confident this is valid? array first element? + if len(m.v) > 0 { + iv, _ := convertStringToInt64(0, m.v[0]) + return NewIntValue(iv) + } + return NewIntValue(0) +} +func (m StringsValue) ToString() string { return strings.Join(m.v, ",") } +func (m StringsValue) Strings() []string { return m.v } +func (m StringsValue) Set() map[string]struct{} { + setvals := make(map[string]struct{}) + for _, sv := range m.v { + setvals[sv] = EmptyStruct + } + return setvals +} +func (m StringsValue) SliceValue() []Value { + vs := make([]Value, len(m.v)) + for i, v := range m.v { + vs[i] = NewStringValue(v) + } + return vs +} diff --git a/value/string_test.go b/value/string_test.go new file mode 100644 index 00000000..9f1e8ec4 --- /dev/null +++ b/value/string_test.go @@ -0,0 +1,48 @@ +package value + +import ( + "math" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestString(t *testing.T) { + v := NewStringValue("a") + slv := v.StringsValue() + assert.Equal(t, 1, slv.Len()) + assert.Equal(t, "a", slv.Val()[0]) + + v = NewStringValue("15.3") + assert.Equal(t, int64(15), v.IntValue().Val()) + v = NewStringValue("15") + assert.Equal(t, int64(15), v.IntValue().Val()) + + sv := NewStringValue("25.5") + nv := sv.NumberValue() + assert.True(t, CloseEnuf(nv.Float(), float64(25.5))) +} + +func TestStrings(t *testing.T) { + v := NewStringsValue([]string{"a"}) + assert.Equal(t, 1, v.Len()) + assert.Equal(t, "a", v.Val()[0]) + v.Append("b") + assert.Equal(t, 2, v.Len()) + assert.Equal(t, "b", v.Val()[1]) + v = NewStringsValue([]string{"25.1"}) + assert.Equal(t, 1, v.Len()) + assert.Equal(t, float64(25.1), v.NumberValue().Float()) + assert.Equal(t, int64(25), v.IntValue().Int()) + v.Append("b") + assert.Equal(t, float64(25.1), v.NumberValue().Float()) + assert.Equal(t, int64(25), v.IntValue().Int()) + v = NewStringsValue(nil) + assert.True(t, math.IsNaN(v.NumberValue().Float())) + assert.Equal(t, int64(0), v.IntValue().Int()) + + v.Append("a") + v.Append("a") + m := v.Set() + assert.Equal(t, 1, len(m)) +} diff --git a/value/time.go b/value/time.go new file mode 100644 index 00000000..bf397778 --- /dev/null +++ b/value/time.go @@ -0,0 +1,23 @@ +package value + +import ( + "encoding/json" + "strconv" + "time" +) + +func NewTimeValue(v time.Time) TimeValue { + return TimeValue{v: v} +} + +func (m TimeValue) Nil() bool { return m.v.IsZero() } +func (m TimeValue) Err() bool { return false } +func (m TimeValue) Type() ValueType { return TimeType } +func (m TimeValue) Value() interface{} { return m.v } +func (m TimeValue) Val() time.Time { return m.v } +func (m TimeValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } +func (m TimeValue) ToString() string { return strconv.FormatInt(m.Int(), 10) } +func (m TimeValue) Float() float64 { return float64(m.Int()) } +func (m TimeValue) Int() int64 { return m.v.In(time.UTC).UnixNano() / 1e6 } +func (m TimeValue) Time() time.Time { return m.v } +func (m TimeValue) IsZero() bool { return m.v.UnixNano() == 0 } diff --git a/value/time_test.go b/value/time_test.go new file mode 100644 index 00000000..a245a148 --- /dev/null +++ b/value/time_test.go @@ -0,0 +1,28 @@ +package value + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestTimeValue(t *testing.T) { + ts := time.Now() + v := NewTimeValue(ts) + assert.False(t, v.Nil()) + tsInt := ts.In(time.UTC).UnixNano() / 1e6 + assert.Equal(t, tsInt, v.Int()) + assert.Equal(t, float64(tsInt), v.Float()) + assert.False(t, v.IsZero()) + + { + v := NewTimeValue(time.Unix(0, 0)) + assert.True(t, v.IsZero()) + } + { + v := NewTimeValue(time.Time{}) + assert.True(t, v.Nil()) + + } +} diff --git a/value/type.go b/value/type.go new file mode 100644 index 00000000..4d9eecac --- /dev/null +++ b/value/type.go @@ -0,0 +1,137 @@ +package value + +import ( + "encoding/json" + "time" +) + +// This is the DataType system, ie string, int, etc +type ValueType uint8 + +const ( + // Enum values for Type system, DO NOT CHANGE the numbers, do not use iota + NilType ValueType = 0 + ErrorType ValueType = 1 + UnknownType ValueType = 2 + ValueInterfaceType ValueType = 3 // Is of type Value Interface, ie unknown + NumberType ValueType = 10 + IntType ValueType = 11 + BoolType ValueType = 12 + TimeType ValueType = 13 + ByteSliceType ValueType = 14 + StringType ValueType = 20 + StringsType ValueType = 21 + MapValueType ValueType = 30 + MapIntType ValueType = 31 + MapStringType ValueType = 32 + MapNumberType ValueType = 33 + MapBoolType ValueType = 34 + MapTimeType ValueType = 35 + SliceValueType ValueType = 40 + StructType ValueType = 50 + JsonType ValueType = 51 +) + +var ( + typeToStr = map[ValueType]string{ + NilType: "nil", + ErrorType: "error", + UnknownType: "unknown", + ValueInterfaceType: "value", + NumberType: "number", + IntType: "int", + BoolType: "bool", + TimeType: "time", + ByteSliceType: "[]byte", + StringType: "string", + StringsType: "[]string", + MapValueType: "map[string]value", + MapIntType: "map[string]string", + MapStringType: "map[string]string", + MapNumberType: "map[string]number", + MapTimeType: "map[string]time", + MapBoolType: "map[string]bool", + SliceValueType: "[]value", + StructType: "struct", + JsonType: "json", + } + mapTypes = map[ValueType]bool{ + MapValueType: true, + MapIntType: true, + MapStringType: true, + MapNumberType: true, + MapTimeType: true, + MapBoolType: true, + } + sliceTypes = map[ValueType]bool{ + StringsType: true, + SliceValueType: true, + } + numTypes = map[ValueType]bool{ + NumberType: true, + IntType: true, + } +) + +func (m ValueType) String() string { + if s, ok := typeToStr[m]; ok { + return s + } + return "invalid" +} + +func (m ValueType) IsMap() bool { + return mapTypes[m] +} + +func (m ValueType) IsSlice() bool { + return sliceTypes[m] +} + +func (m ValueType) IsNumeric() bool { + return numTypes[m] +} + +func (m ValueType) Zero() Value { + switch m { + case NilType: + return NewNilValue() + case ErrorType: + return NewErrorValue(nil) + case ValueInterfaceType: + return NewValue(nil) + case NumberType: + return NewNumberValue(0) + case IntType: + return NewIntValue(0) + case BoolType: + return BoolValueFalse + case TimeType: + return NewTimeValue(time.Unix(0, 0).UTC()) + case ByteSliceType: + return NewByteSliceValue([]byte{}) + case StringType: + return EmptyStringValue + case StringsType: + return NewStringsValue([]string{}) + case MapValueType: + return NewMapValue(map[string]interface{}{}) + case MapIntType: + return NewMapIntValue(map[string]int64{}) + case MapStringType: + return NewMapStringValue(map[string]string{}) + case MapNumberType: + return NewMapNumberValue(map[string]float64{}) + case MapBoolType: + return NewMapBoolValue(map[string]bool{}) + case MapTimeType: + return NewMapTimeValue(map[string]time.Time{}) + case SliceValueType: + return NewSliceValues([]Value{}) + case StructType: + return NewStructValue(nil) + case JsonType: + return NewJsonValue(json.RawMessage{}) + } + return nil +} diff --git a/value/type_test.go b/value/type_test.go new file mode 100644 index 00000000..694d2dbe --- /dev/null +++ b/value/type_test.go @@ -0,0 +1,99 @@ +package value + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + typeToInt = map[ValueType]uint8{ + NilType: 0, + ErrorType: 1, + UnknownType: 2, + ValueInterfaceType: 3, + NumberType: 10, + IntType: 11, + BoolType: 12, + TimeType: 13, + ByteSliceType: 14, + StringType: 20, + StringsType: 21, + MapValueType: 30, + MapIntType: 31, + MapStringType: 32, + MapNumberType: 33, + MapBoolType: 34, + MapTimeType: 35, + SliceValueType: 40, + StructType: 50, + JsonType: 51, + } +) + +func TestAllValueTypesDefined(t *testing.T) { + for v := range typeToInt { + _, ok := typeToStr[v] + assert.True(t, ok) + } + for v := range typeToStr { + _, ok := typeToInt[v] + assert.True(t, ok) + } +} +func TestValueTypeUint8(t *testing.T) { + for v := range typeToStr { + assert.Equal(t, typeToInt[v], uint8(v)) + } +} +func TestValueTypeString(t *testing.T) { + for v, s := range typeToStr { + assert.Equal(t, s, v.String()) + } +} + +func TestIsMap(t *testing.T) { + for v := range mapTypes { + assert.True(t, v.IsMap()) + } + for v := range sliceTypes { + assert.False(t, v.IsMap()) + } + for v := range numTypes { + assert.False(t, v.IsMap()) + } +} + +func TestIsNumeric(t *testing.T) { + for v := range numTypes { + assert.True(t, v.IsNumeric()) + } + for v := range mapTypes { + assert.False(t, v.IsNumeric()) + } + for v := range sliceTypes { + assert.False(t, v.IsNumeric()) + } +} + +func TestIsSlice(t *testing.T) { + for v := range sliceTypes { + assert.True(t, v.IsSlice()) + } + for v := range numTypes { + assert.False(t, v.IsSlice()) + } + for v := range mapTypes { + assert.False(t, v.IsSlice()) + } +} + +func TestZero(t *testing.T) { + for v, s := range typeToStr { + if s == "unknown" { + assert.Nil(t, v.Zero()) + continue + } + assert.NotNilf(t, v.Zero(), "expected not nil for %v", v) + } +} diff --git a/value/value.go b/value/value.go index 7780142c..7fa29398 100644 --- a/value/value.go +++ b/value/value.go @@ -8,8 +8,6 @@ import ( "fmt" "math" "reflect" - "strconv" - "strings" "time" ) @@ -46,104 +44,6 @@ var ( _ Map = (MapBoolValue)(EmptyMapBoolValue) ) -// This is the DataType system, ie string, int, etc -type ValueType uint8 - -const ( - // Enum values for Type system, DO NOT CHANGE the numbers, do not use iota - NilType ValueType = 0 - ErrorType ValueType = 1 - UnknownType ValueType = 2 - ValueInterfaceType ValueType = 3 // Is of type Value Interface, ie unknown - NumberType ValueType = 10 - IntType ValueType = 11 - BoolType ValueType = 12 - TimeType ValueType = 13 - ByteSliceType ValueType = 14 - StringType ValueType = 20 - StringsType ValueType = 21 - MapValueType ValueType = 30 - MapIntType ValueType = 31 - MapStringType ValueType = 32 - MapNumberType ValueType = 33 - MapBoolType ValueType = 34 - MapTimeType ValueType = 35 - SliceValueType ValueType = 40 - StructType ValueType = 50 - JsonType ValueType = 51 -) - -func (m ValueType) String() string { - switch m { - case NilType: - return "nil" - case ErrorType: - return "error" - case UnknownType: - return "unknown" - case ValueInterfaceType: - return "value" - case NumberType: - return "number" - case IntType: - return "int" - case BoolType: - return "bool" - case TimeType: - return "time" - case ByteSliceType: - return "[]byte" - case StringType: - return "string" - case StringsType: - return "[]string" - case MapValueType: - return "map[string]value" - case MapIntType: - return "map[string]int" - case MapStringType: - return "map[string]string" - case MapNumberType: - return "map[string]number" - case MapTimeType: - return "map[string]time" - case MapBoolType: - return "map[string]bool" - case SliceValueType: - return "[]value" - case StructType: - return "struct" - case JsonType: - return "json" - default: - return "invalid" - } -} - -func (m ValueType) IsMap() bool { - switch m { - case MapValueType, MapIntType, MapStringType, MapNumberType, MapTimeType, MapBoolType: - return true - } - return false -} - -func (m ValueType) IsSlice() bool { - switch m { - case StringsType, SliceValueType: - return true - } - return false -} - -func (m ValueType) IsNumeric() bool { - switch m { - case NumberType, IntType: - return true - } - return false -} - type emptyStruct struct{} type ( @@ -156,6 +56,7 @@ type ( Value() interface{} ToString() string Type() ValueType + IsZero() bool } // Certain types are Numeric (Ints, Time, Number) NumericValue interface { @@ -446,454 +347,6 @@ func NewValue(goVal interface{}) Value { } } -func NewNumberValue(v float64) NumberValue { - return NumberValue{v: v} -} -func NewNumberNil() NumberValue { - v := NumberValue{v: math.NaN()} - return v -} -func (m NumberValue) Nil() bool { return math.IsNaN(m.v) } -func (m NumberValue) Err() bool { return math.IsNaN(m.v) } -func (m NumberValue) Type() ValueType { return NumberType } -func (m NumberValue) Value() interface{} { return m.v } -func (m NumberValue) Val() float64 { return m.v } -func (m NumberValue) MarshalJSON() ([]byte, error) { return marshalFloat(float64(m.v)) } -func (m NumberValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m NumberValue) Float() float64 { return m.v } -func (m NumberValue) Int() int64 { return int64(m.v) } - -func NewIntValue(v int64) IntValue { - return IntValue{v: v} -} - -func NewIntNil() IntValue { - v := IntValue{v: math.MinInt32} - return v -} - -func (m IntValue) Nil() bool { return m.v == math.MinInt32 } -func (m IntValue) Err() bool { return m.v == math.MinInt32 } -func (m IntValue) Type() ValueType { return IntType } -func (m IntValue) Value() interface{} { return m.v } -func (m IntValue) Val() int64 { return m.v } -func (m IntValue) MarshalJSON() ([]byte, error) { return marshalFloat(float64(m.v)) } -func (m IntValue) NumberValue() NumberValue { return NewNumberValue(float64(m.v)) } -func (m IntValue) ToString() string { - if m.v == math.MinInt32 { - return "" - } - return strconv.FormatInt(m.v, 10) -} -func (m IntValue) Float() float64 { return float64(m.v) } -func (m IntValue) Int() int64 { return m.v } - -func NewBoolValue(v bool) BoolValue { - if v { - return BoolValueTrue - } - return BoolValueFalse -} - -func (m BoolValue) Nil() bool { return false } -func (m BoolValue) Err() bool { return false } -func (m BoolValue) Type() ValueType { return BoolType } -func (m BoolValue) Value() interface{} { return m.v } -func (m BoolValue) Val() bool { return m.v } -func (m BoolValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m BoolValue) ToString() string { return strconv.FormatBool(m.v) } - -func NewStringValue(v string) StringValue { - return StringValue{v: v} -} - -func (m StringValue) Nil() bool { return len(m.v) == 0 } -func (m StringValue) Err() bool { return false } -func (m StringValue) Type() ValueType { return StringType } -func (m StringValue) Value() interface{} { return m.v } -func (m StringValue) Val() string { return m.v } -func (m StringValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m StringValue) NumberValue() NumberValue { - fv, _ := StringToFloat64(m.v) - return NewNumberValue(fv) -} -func (m StringValue) StringsValue() StringsValue { return NewStringsValue([]string{m.v}) } -func (m StringValue) ToString() string { return m.v } - -func (m StringValue) IntValue() IntValue { - iv, _ := ValueToInt64(m) - return NewIntValue(iv) -} - -func NewStringsValue(v []string) StringsValue { - return StringsValue{v: v} -} - -func (m StringsValue) Nil() bool { return len(m.v) == 0 } -func (m StringsValue) Err() bool { return false } -func (m StringsValue) Type() ValueType { return StringsType } -func (m StringsValue) Value() interface{} { return m.v } -func (m StringsValue) Val() []string { return m.v } -func (m *StringsValue) Append(sv string) { m.v = append(m.v, sv) } -func (m StringsValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m StringsValue) Len() int { return len(m.v) } -func (m StringsValue) NumberValue() NumberValue { - if len(m.v) > 0 { - if fv, err := strconv.ParseFloat(m.v[0], 64); err == nil { - return NewNumberValue(fv) - } - } - return NumberNaNValue -} -func (m StringsValue) IntValue() IntValue { - // Im not confident this is valid? array first element? - if len(m.v) > 0 { - iv, _ := convertStringToInt64(0, m.v[0]) - return NewIntValue(iv) - } - return NewIntValue(0) -} -func (m StringsValue) ToString() string { return strings.Join(m.v, ",") } -func (m StringsValue) Strings() []string { return m.v } -func (m StringsValue) Set() map[string]struct{} { - setvals := make(map[string]struct{}) - for _, sv := range m.v { - setvals[sv] = EmptyStruct - } - return setvals -} -func (m StringsValue) SliceValue() []Value { - vs := make([]Value, len(m.v)) - for i, v := range m.v { - vs[i] = NewStringValue(v) - } - return vs -} - -func NewByteSliceValue(v []byte) ByteSliceValue { - return ByteSliceValue{v: v} -} - -func (m ByteSliceValue) Nil() bool { return len(m.v) == 0 } -func (m ByteSliceValue) Err() bool { return false } -func (m ByteSliceValue) Type() ValueType { return ByteSliceType } -func (m ByteSliceValue) Value() interface{} { return m.v } -func (m ByteSliceValue) Val() []byte { return m.v } -func (m ByteSliceValue) ToString() string { return string(m.v) } -func (m ByteSliceValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m ByteSliceValue) Len() int { return len(m.v) } - -func NewSliceValues(v []Value) SliceValue { - return SliceValue{v: v} -} -func NewSliceValuesNative(iv []interface{}) SliceValue { - vs := make([]Value, len(iv)) - for i, v := range iv { - vs[i] = NewValue(v) - } - return SliceValue{v: vs} -} - -func (m SliceValue) Nil() bool { return len(m.v) == 0 } -func (m SliceValue) Err() bool { return false } -func (m SliceValue) Type() ValueType { return SliceValueType } -func (m SliceValue) Value() interface{} { return m.v } -func (m SliceValue) Val() []Value { return m.v } -func (m SliceValue) ToString() string { - sv := make([]string, len(m.Val())) - for i, val := range m.v { - sv[i] = val.ToString() - } - return strings.Join(sv, ",") -} - -func (m *SliceValue) Append(v Value) { m.v = append(m.v, v) } -func (m SliceValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m SliceValue) Len() int { return len(m.v) } -func (m SliceValue) SliceValue() []Value { return m.v } -func (m SliceValue) Values() []interface{} { - vals := make([]interface{}, len(m.v)) - for i, v := range m.v { - vals[i] = v.Value() - } - return vals -} - -func NewMapValue(v map[string]interface{}) MapValue { - mv := make(map[string]Value) - for n, val := range v { - mv[n] = NewValue(val) - } - return MapValue{v: mv} -} - -func (m MapValue) Nil() bool { return len(m.v) == 0 } -func (m MapValue) Err() bool { return false } -func (m MapValue) Type() ValueType { return MapValueType } -func (m MapValue) Value() interface{} { return m.v } -func (m MapValue) Val() map[string]Value { return m.v } -func (m MapValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapValue) Len() int { return len(m.v) } -func (m MapValue) MapInt() map[string]int64 { - mv := make(map[string]int64, len(m.v)) - for n, v := range m.v { - intVal, ok := ValueToInt64(v) - if ok { - mv[n] = intVal - } - } - return mv -} -func (m MapValue) MapFloat() map[string]float64 { - mv := make(map[string]float64, len(m.v)) - for n, v := range m.v { - fv, _ := ValueToFloat64(v) - if !math.IsNaN(fv) { - mv[n] = fv - } - } - return mv -} -func (m MapValue) MapString() map[string]string { - mv := make(map[string]string, len(m.v)) - for n, v := range m.v { - mv[n] = v.ToString() - } - return mv -} -func (m MapValue) MapValue() MapValue { - return m -} -func (m MapValue) MapTime() MapTimeValue { - mv := make(map[string]time.Time, len(m.v)) - for k, v := range m.v { - t, ok := ValueToTime(v) - if ok && !t.IsZero() { - mv[k] = t - } - } - return NewMapTimeValue(mv) -} -func (m MapValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - return v, ok -} -func NewMapStringValue(v map[string]string) MapStringValue { - return MapStringValue{v: v} -} - -func (m MapStringValue) Nil() bool { return len(m.v) == 0 } -func (m MapStringValue) Err() bool { return false } -func (m MapStringValue) Type() ValueType { return MapStringType } -func (m MapStringValue) Value() interface{} { return m.v } -func (m MapStringValue) Val() map[string]string { return m.v } -func (m MapStringValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapStringValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapStringValue) Len() int { return len(m.v) } -func (m MapStringValue) MapBool() MapBoolValue { - mb := make(map[string]bool) - for n, sv := range m.Val() { - b, err := strconv.ParseBool(sv) - if err == nil { - mb[n] = b - } - } - return NewMapBoolValue(mb) -} -func (m MapStringValue) MapInt() MapIntValue { - mi := make(map[string]int64) - for n, sv := range m.Val() { - iv, err := strconv.ParseInt(sv, 10, 64) - if err == nil { - mi[n] = iv - } - } - return NewMapIntValue(mi) -} -func (m MapStringValue) MapNumber() MapNumberValue { - mn := make(map[string]float64) - for n, sv := range m.Val() { - fv, err := strconv.ParseFloat(sv, 64) - if err == nil { - mn[n] = fv - } - } - return NewMapNumberValue(mn) -} -func (m MapStringValue) MapValue() MapValue { - mv := make(map[string]Value) - for n, val := range m.v { - mv[n] = NewStringValue(val) - } - return MapValue{v: mv} -} -func (m MapStringValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - if ok { - return NewStringValue(v), ok - } - return nil, ok -} -func (m MapStringValue) SliceValue() []Value { - vs := make([]Value, 0, len(m.v)) - for k := range m.v { - vs = append(vs, NewStringValue(k)) - } - return vs -} - -func NewMapIntValue(v map[string]int64) MapIntValue { - return MapIntValue{v: v} -} - -func (m MapIntValue) Nil() bool { return len(m.v) == 0 } -func (m MapIntValue) Err() bool { return false } -func (m MapIntValue) Type() ValueType { return MapIntType } -func (m MapIntValue) Value() interface{} { return m.v } -func (m MapIntValue) Val() map[string]int64 { return m.v } -func (m MapIntValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapIntValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapIntValue) Len() int { return len(m.v) } -func (m MapIntValue) MapInt() map[string]int64 { return m.v } -func (m MapIntValue) MapFloat() map[string]float64 { - mv := make(map[string]float64, len(m.v)) - for n, iv := range m.v { - mv[n] = float64(iv) - } - return mv -} -func (m MapIntValue) MapValue() MapValue { - mv := make(map[string]Value) - for n, val := range m.v { - mv[n] = NewIntValue(val) - } - return MapValue{v: mv} -} -func (m MapIntValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - if ok { - return NewIntValue(v), ok - } - return nil, ok -} -func (m MapIntValue) SliceValue() []Value { - vs := make([]Value, 0, len(m.v)) - for k := range m.v { - vs = append(vs, NewStringValue(k)) - } - return vs -} - -func NewMapNumberValue(v map[string]float64) MapNumberValue { - return MapNumberValue{v: v} -} - -func (m MapNumberValue) Nil() bool { return len(m.v) == 0 } -func (m MapNumberValue) Err() bool { return false } -func (m MapNumberValue) Type() ValueType { return MapNumberType } -func (m MapNumberValue) Value() interface{} { return m.v } -func (m MapNumberValue) Val() map[string]float64 { return m.v } -func (m MapNumberValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapNumberValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapNumberValue) Len() int { return len(m.v) } -func (m MapNumberValue) MapInt() map[string]int64 { - mv := make(map[string]int64, len(m.v)) - for n, v := range m.v { - mv[n] = int64(v) - } - return mv -} -func (m MapNumberValue) MapValue() MapValue { - mv := make(map[string]Value) - for n, val := range m.v { - mv[n] = NewNumberValue(val) - } - return MapValue{v: mv} -} -func (m MapNumberValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - if ok { - return NewNumberValue(v), ok - } - return nil, ok -} -func (m MapNumberValue) SliceValue() []Value { - vs := make([]Value, 0, len(m.v)) - for k := range m.v { - vs = append(vs, NewStringValue(k)) - } - return vs -} - -func NewMapTimeValue(v map[string]time.Time) MapTimeValue { - return MapTimeValue{v: v} -} - -func (m MapTimeValue) Nil() bool { return len(m.v) == 0 } -func (m MapTimeValue) Err() bool { return false } -func (m MapTimeValue) Type() ValueType { return MapTimeType } -func (m MapTimeValue) Value() interface{} { return m.v } -func (m MapTimeValue) Val() map[string]time.Time { return m.v } -func (m MapTimeValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapTimeValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapTimeValue) Len() int { return len(m.v) } -func (m MapTimeValue) MapInt() map[string]int64 { - mv := make(map[string]int64, len(m.v)) - for n, v := range m.v { - mv[n] = v.UnixNano() - } - return mv -} -func (m MapTimeValue) MapValue() MapValue { - mv := make(map[string]Value) - for n, val := range m.v { - mv[n] = NewTimeValue(val) - } - return MapValue{v: mv} -} -func (m MapTimeValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - if ok { - return NewTimeValue(v), ok - } - return nil, ok -} - -func NewMapBoolValue(v map[string]bool) MapBoolValue { - return MapBoolValue{v: v} -} - -func (m MapBoolValue) Nil() bool { return len(m.v) == 0 } -func (m MapBoolValue) Err() bool { return false } -func (m MapBoolValue) Type() ValueType { return MapBoolType } -func (m MapBoolValue) Value() interface{} { return m.v } -func (m MapBoolValue) Val() map[string]bool { return m.v } -func (m MapBoolValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m MapBoolValue) ToString() string { return fmt.Sprintf("%v", m.v) } -func (m MapBoolValue) Len() int { return len(m.v) } -func (m MapBoolValue) MapValue() MapValue { - mv := make(map[string]Value) - for n, val := range m.v { - mv[n] = NewBoolValue(val) - } - return MapValue{v: mv} -} -func (m MapBoolValue) Get(key string) (Value, bool) { - v, ok := m.v[key] - if ok { - return NewBoolValue(v), ok - } - return nil, ok -} -func (m MapBoolValue) SliceValue() []Value { - vs := make([]Value, 0, len(m.v)) - for k := range m.v { - vs = append(vs, NewStringValue(k)) - } - return vs -} - func NewStructValue(v interface{}) StructValue { return StructValue{v: v} } @@ -905,6 +358,7 @@ func (m StructValue) Value() interface{} { return m.v } func (m StructValue) Val() interface{} { return m.v } func (m StructValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } func (m StructValue) ToString() string { return fmt.Sprintf("%v", m.v) } +func (m StructValue) IsZero() bool { return m.Nil() } func NewJsonValue(v json.RawMessage) JsonValue { return JsonValue{v: v} @@ -917,21 +371,7 @@ func (m JsonValue) Value() interface{} { return m.v } func (m JsonValue) Val() interface{} { return m.v } func (m JsonValue) MarshalJSON() ([]byte, error) { return []byte(m.v), nil } func (m JsonValue) ToString() string { return string(m.v) } - -func NewTimeValue(v time.Time) TimeValue { - return TimeValue{v: v} -} - -func (m TimeValue) Nil() bool { return m.v.IsZero() } -func (m TimeValue) Err() bool { return false } -func (m TimeValue) Type() ValueType { return TimeType } -func (m TimeValue) Value() interface{} { return m.v } -func (m TimeValue) Val() time.Time { return m.v } -func (m TimeValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } -func (m TimeValue) ToString() string { return strconv.FormatInt(m.Int(), 10) } -func (m TimeValue) Float() float64 { return float64(m.v.In(time.UTC).UnixNano() / 1e6) } -func (m TimeValue) Int() int64 { return m.v.In(time.UTC).UnixNano() / 1e6 } -func (m TimeValue) Time() time.Time { return m.v } +func (m JsonValue) IsZero() bool { return m.Nil() } func NewErrorValue(v error) ErrorValue { return ErrorValue{v: v} @@ -948,6 +388,7 @@ func (m ErrorValue) Value() interface{} { return m.v } func (m ErrorValue) Val() error { return m.v } func (m ErrorValue) MarshalJSON() ([]byte, error) { return json.Marshal(m.v) } func (m ErrorValue) ToString() string { return m.v.Error() } +func (m ErrorValue) IsZero() bool { return m.v == nil } // ErrorValues implement Go's error interface so they can easily cross the // VM/Go boundary. @@ -964,3 +405,4 @@ func (m NilValue) Value() interface{} { return nil } func (m NilValue) Val() interface{} { return nil } func (m NilValue) MarshalJSON() ([]byte, error) { return []byte("null"), nil } func (m NilValue) ToString() string { return "" } +func (m NilValue) IsZero() bool { return m.Nil() } diff --git a/value/value_test.go b/value/value_test.go index 5142ec31..617d977e 100644 --- a/value/value_test.go +++ b/value/value_test.go @@ -118,7 +118,7 @@ var ( ) // TestNewValue tests the conversion from Go types to Values. -func TestValues(t *testing.T) { +func TestNewValue(t *testing.T) { var ty ValueType assert.Equal(t, "nil", ty.String()) @@ -271,40 +271,7 @@ func TestValues(t *testing.T) { } } -func TestIntValue(t *testing.T) { - v := NewIntNil() - assert.True(t, v.Nil()) - assert.Equal(t, "", v.ToString()) - v = NewIntValue(32) - nv := v.NumberValue() - assert.Equal(t, nv.Int(), int64(32)) -} -func TestValueNumber(t *testing.T) { - v := NewNumberValue(math.NaN()) - _, err := json.Marshal(&v) - assert.Equal(t, nil, err) - v = NewNumberValue(math.Inf(1)) - _, err = json.Marshal(&v) - assert.Equal(t, nil, err) - v = NewNumberValue(math.Inf(-1)) - _, err = json.Marshal(&v) - assert.Equal(t, nil, err) - - sv := NewStringValue("25.5") - nv := sv.NumberValue() - assert.True(t, CloseEnuf(nv.Float(), float64(25.5))) -} -func TestString(t *testing.T) { - v := NewStringValue("a") - slv := v.StringsValue() - assert.Equal(t, 1, slv.Len()) - assert.Equal(t, "a", slv.Val()[0]) - v = NewStringValue("15.3") - assert.Equal(t, int64(15), v.IntValue().Val()) - v = NewStringValue("15") - assert.Equal(t, int64(15), v.IntValue().Val()) -} func TestErrValue(t *testing.T) { v := NewErrorValuef("%v", "damn") assert.Equal(t, false, v.Nil()) @@ -315,158 +282,3 @@ func TestErrValue(t *testing.T) { assert.Equal(t, nil, err) assert.True(t, v.Err()) } -func TestStrings(t *testing.T) { - v := NewStringsValue([]string{"a"}) - assert.Equal(t, 1, v.Len()) - assert.Equal(t, "a", v.Val()[0]) - v.Append("b") - assert.Equal(t, 2, v.Len()) - assert.Equal(t, "b", v.Val()[1]) - v = NewStringsValue([]string{"25.1"}) - assert.Equal(t, 1, v.Len()) - assert.Equal(t, float64(25.1), v.NumberValue().Float()) - assert.Equal(t, int64(25), v.IntValue().Int()) - v.Append("b") - assert.Equal(t, float64(25.1), v.NumberValue().Float()) - assert.Equal(t, int64(25), v.IntValue().Int()) - v = NewStringsValue(nil) - assert.True(t, math.IsNaN(v.NumberValue().Float())) - assert.Equal(t, int64(0), v.IntValue().Int()) - - v.Append("a") - v.Append("a") - m := v.Set() - assert.Equal(t, 1, len(m)) -} -func TestSliceValues(t *testing.T) { - v := NewSliceValuesNative([]interface{}{"a"}) - assert.Equal(t, 1, v.Len()) - assert.Equal(t, "a", v.Val()[0].ToString()) - v.Append(NewStringValue("b")) - assert.Equal(t, 2, v.Len()) - assert.Equal(t, "b", v.Val()[1].ToString()) - assert.Equal(t, 2, len(v.Values())) -} -func TestMapValue(t *testing.T) { - mv := map[string]interface{}{"k1": 10} - v := NewMapValue(mv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - mi := v.MapInt() - assert.Equal(t, 1, len(mi)) - assert.Equal(t, int64(10), mi["k1"]) - mf := v.MapFloat() - assert.Equal(t, 1, len(mf)) - assert.Equal(t, float64(10), mf["k1"]) - ms := v.MapString() - assert.Equal(t, 1, len(mf)) - assert.Equal(t, "10", ms["k1"]) - v = NewMapValue(map[string]interface{}{"k1": "hello"}) - mt := v.MapTime() - assert.Equal(t, 0, mt.Len()) - v = NewMapValue(map[string]interface{}{"k1": "now-4d"}) - mt = v.MapTime() - assert.Equal(t, 1, mt.Len()) - assert.True(t, mt.Val()["k1"].Unix() > 10000) -} - -func TestMapStringValue(t *testing.T) { - msv := map[string]string{"k1": "10"} - v := NewMapStringValue(msv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - lv := v.SliceValue() - assert.Equal(t, 1, len(lv)) - mi := v.MapInt() - assert.Equal(t, 1, mi.Len()) - assert.Equal(t, int64(10), mi.Val()["k1"]) - mf := v.MapNumber() - assert.Equal(t, 1, mf.Len()) - assert.Equal(t, float64(10), mf.Val()["k1"]) - mb := v.MapBool() - assert.Equal(t, 0, mb.Len()) - v = NewMapStringValue(map[string]string{"k1": "true"}) - mb = v.MapBool() - assert.Equal(t, 1, mb.Len()) - assert.Equal(t, true, mb.Val()["k1"]) -} - -func TestMapIntValue(t *testing.T) { - miv := map[string]int64{"k1": 10} - v := NewMapIntValue(miv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - lv := v.SliceValue() - assert.Equal(t, 1, len(lv)) - mi := v.MapInt() - assert.Equal(t, 1, len(mi)) - assert.Equal(t, int64(10), mi["k1"]) - mf := v.MapFloat() - assert.Equal(t, 1, len(mf)) - assert.Equal(t, float64(10), mf["k1"]) - - mv := v.MapValue() - assert.Equal(t, 1, mv.Len()) - assert.Equal(t, int64(10), mv.Val()["k1"].Value()) -} -func TestMapNumberValue(t *testing.T) { - mfv := map[string]float64{"k1": 10} - v := NewMapNumberValue(mfv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - lv := v.SliceValue() - assert.Equal(t, 1, len(lv)) - mi := v.MapInt() - assert.Equal(t, 1, len(mi)) - assert.Equal(t, int64(10), mi["k1"]) - - mv := v.MapValue() - assert.Equal(t, 1, mv.Len()) - assert.Equal(t, float64(10), mv.Val()["k1"].Value()) -} -func TestMapTimeValue(t *testing.T) { - n := time.Now() - mtv := map[string]time.Time{"k1": n} - v := NewMapTimeValue(mtv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - - mi := v.MapInt() - assert.Equal(t, 1, len(mi)) - assert.True(t, CloseEnuf(float64(n.UnixNano()), float64(mi["k1"]))) - - mv := v.MapValue() - assert.Equal(t, 1, mv.Len()) - assert.Equal(t, n, mv.Val()["k1"].Value()) -} -func TestMapBoolValue(t *testing.T) { - - mbv := map[string]bool{"k1": true} - v := NewMapBoolValue(mbv) - _, ok := v.Get("k1") - assert.True(t, ok) - _, ok = v.Get("nope") - assert.Equal(t, false, ok) - assert.Equal(t, 1, v.MapValue().Len()) - lv := v.SliceValue() - assert.Equal(t, 1, len(lv)) - - mv := v.MapValue() - assert.Equal(t, 1, mv.Len()) - assert.Equal(t, true, mv.Val()["k1"].Value()) -}