Skip to content

Commit 6d5de06

Browse files
author
André R. de Miranda
authored
Add new types float64, map, slice, nil in object (#186)
* Add new types `float64, map, slice, nil` in object Signed-off-by: André R. de Miranda <andre@galgo.tech> * Add function ToInterface convert from object to any Signed-off-by: André R. de Miranda <andre@galgo.tech> --------- Signed-off-by: André R. de Miranda <andre@galgo.tech>
1 parent cd99303 commit 6d5de06

File tree

4 files changed

+367
-62
lines changed

4 files changed

+367
-62
lines changed

model/object.go

Lines changed: 152 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,23 @@
1515
package model
1616

1717
import (
18+
"bytes"
1819
"encoding/json"
1920
"fmt"
2021
"math"
22+
"strconv"
23+
)
24+
25+
type Type int8
26+
27+
const (
28+
Null Type = iota
29+
String
30+
Int
31+
Float
32+
Map
33+
Slice
34+
Bool
2135
)
2236

2337
// Object is used to allow integration with DeepCopy tool by replacing 'interface' generic type.
@@ -29,80 +43,167 @@ import (
2943
// - String - holds string values
3044
// - Integer - holds int32 values, JSON marshal any number to float64 by default, during the marshaling process it is
3145
// parsed to int32
32-
// - raw - holds any not typed value, replaces the interface{} behavior.
3346
//
3447
// +kubebuilder:validation:Type=object
3548
type Object struct {
36-
Type Type `json:"type,inline"`
37-
IntVal int32 `json:"intVal,inline"`
38-
StrVal string `json:"strVal,inline"`
39-
RawValue json.RawMessage `json:"rawValue,inline"`
40-
BoolValue bool `json:"boolValue,inline"`
49+
Type Type `json:"type,inline"`
50+
StringValue string `json:"strVal,inline"`
51+
IntValue int32 `json:"intVal,inline"`
52+
FloatValue float64
53+
MapValue map[string]Object
54+
SliceValue []Object
55+
BoolValue bool `json:"boolValue,inline"`
4156
}
4257

43-
type Type int64
58+
// UnmarshalJSON implements json.Unmarshaler
59+
func (obj *Object) UnmarshalJSON(data []byte) error {
60+
data = bytes.TrimSpace(data)
4461

45-
const (
46-
Integer Type = iota
47-
String
48-
Raw
49-
Boolean
50-
)
62+
if data[0] == '"' {
63+
obj.Type = String
64+
return json.Unmarshal(data, &obj.StringValue)
65+
} else if data[0] == 't' || data[0] == 'f' {
66+
obj.Type = Bool
67+
return json.Unmarshal(data, &obj.BoolValue)
68+
} else if data[0] == 'n' {
69+
obj.Type = Null
70+
return nil
71+
} else if data[0] == '{' {
72+
obj.Type = Map
73+
return json.Unmarshal(data, &obj.MapValue)
74+
} else if data[0] == '[' {
75+
obj.Type = Slice
76+
return json.Unmarshal(data, &obj.SliceValue)
77+
}
78+
79+
number := string(data)
80+
intValue, err := strconv.ParseInt(number, 10, 32)
81+
if err == nil {
82+
obj.Type = Int
83+
obj.IntValue = int32(intValue)
84+
return nil
85+
}
86+
87+
floatValue, err := strconv.ParseFloat(number, 64)
88+
if err == nil {
89+
obj.Type = Float
90+
obj.FloatValue = floatValue
91+
return nil
92+
}
93+
94+
return fmt.Errorf("json invalid number %q", number)
95+
}
96+
97+
// MarshalJSON marshal the given json object into the respective Object subtype.
98+
func (obj Object) MarshalJSON() ([]byte, error) {
99+
switch obj.Type {
100+
case String:
101+
return []byte(fmt.Sprintf(`%q`, obj.StringValue)), nil
102+
case Int:
103+
return []byte(fmt.Sprintf(`%d`, obj.IntValue)), nil
104+
case Float:
105+
return []byte(fmt.Sprintf(`%f`, obj.FloatValue)), nil
106+
case Map:
107+
return json.Marshal(obj.MapValue)
108+
case Slice:
109+
return json.Marshal(obj.SliceValue)
110+
case Bool:
111+
return []byte(fmt.Sprintf(`%t`, obj.BoolValue)), nil
112+
case Null:
113+
return []byte("null"), nil
114+
default:
115+
panic("object invalid type")
116+
}
117+
}
118+
119+
func FromString(val string) Object {
120+
return Object{Type: String, StringValue: val}
121+
}
51122

52123
func FromInt(val int) Object {
53124
if val > math.MaxInt32 || val < math.MinInt32 {
54125
fmt.Println(fmt.Errorf("value: %d overflows int32", val))
55126
}
56-
return Object{Type: Integer, IntVal: int32(val)}
127+
return Object{Type: Int, IntValue: int32(val)}
57128
}
58129

59-
func FromString(val string) Object {
60-
return Object{Type: String, StrVal: val}
130+
func FromFloat(val float64) Object {
131+
if val > math.MaxFloat64 || val < -math.MaxFloat64 {
132+
fmt.Println(fmt.Errorf("value: %f overflows float64", val))
133+
}
134+
return Object{Type: Float, FloatValue: float64(val)}
61135
}
62136

63-
func FromBool(val bool) Object {
64-
return Object{Type: Boolean, BoolValue: val}
137+
func FromMap(mapValue map[string]any) Object {
138+
mapValueObject := make(map[string]Object, len(mapValue))
139+
for key, value := range mapValue {
140+
mapValueObject[key] = FromInterface(value)
141+
}
142+
return Object{Type: Map, MapValue: mapValueObject}
65143
}
66144

67-
func FromRaw(val interface{}) Object {
68-
custom, err := json.Marshal(val)
69-
if err != nil {
70-
er := fmt.Errorf("failed to parse value to Raw: %w", err)
71-
fmt.Println(er.Error())
72-
return Object{}
145+
func FromSlice(sliceValue []any) Object {
146+
sliceValueObject := make([]Object, len(sliceValue))
147+
for key, value := range sliceValue {
148+
sliceValueObject[key] = FromInterface(value)
73149
}
74-
return Object{Type: Raw, RawValue: custom}
150+
return Object{Type: Slice, SliceValue: sliceValueObject}
75151
}
76152

77-
// UnmarshalJSON implements json.Unmarshaler
78-
func (obj *Object) UnmarshalJSON(data []byte) error {
79-
if data[0] == '"' {
80-
obj.Type = String
81-
return json.Unmarshal(data, &obj.StrVal)
82-
} else if data[0] == 't' || data[0] == 'f' {
83-
obj.Type = Boolean
84-
return json.Unmarshal(data, &obj.BoolValue)
85-
} else if data[0] == '{' {
86-
obj.Type = Raw
87-
return json.Unmarshal(data, &obj.RawValue)
153+
func FromBool(val bool) Object {
154+
return Object{Type: Bool, BoolValue: val}
155+
}
156+
157+
func FromNull() Object {
158+
return Object{Type: Null}
159+
}
160+
161+
func FromInterface(value any) Object {
162+
switch v := value.(type) {
163+
case string:
164+
return FromString(v)
165+
case int:
166+
return FromInt(v)
167+
case int32:
168+
return FromInt(int(v))
169+
case float64:
170+
return FromFloat(v)
171+
case map[string]any:
172+
return FromMap(v)
173+
case []any:
174+
return FromSlice(v)
175+
case bool:
176+
return FromBool(v)
177+
case nil:
178+
return FromNull()
88179
}
89-
obj.Type = Integer
90-
return json.Unmarshal(data, &obj.IntVal)
180+
panic("invalid type")
91181
}
92182

93-
// MarshalJSON marshal the given json object into the respective Object subtype.
94-
func (obj Object) MarshalJSON() ([]byte, error) {
95-
switch obj.Type {
183+
func ToInterface(object Object) any {
184+
switch object.Type {
96185
case String:
97-
return []byte(fmt.Sprintf(`%q`, obj.StrVal)), nil
98-
case Boolean:
99-
return []byte(fmt.Sprintf(`%t`, obj.BoolValue)), nil
100-
case Integer:
101-
return []byte(fmt.Sprintf(`%d`, obj.IntVal)), nil
102-
case Raw:
103-
val, _ := json.Marshal(obj.RawValue)
104-
return val, nil
105-
default:
106-
return []byte(fmt.Sprintf("%+v", obj)), nil
186+
return object.StringValue
187+
case Int:
188+
return object.IntValue
189+
case Float:
190+
return object.FloatValue
191+
case Map:
192+
mapInterface := make(map[string]any, len(object.MapValue))
193+
for key, value := range object.MapValue {
194+
mapInterface[key] = ToInterface(value)
195+
}
196+
return mapInterface
197+
case Slice:
198+
sliceInterface := make([]any, len(object.SliceValue))
199+
for key, value := range object.SliceValue {
200+
sliceInterface[key] = ToInterface(value)
201+
}
202+
return sliceInterface
203+
case Bool:
204+
return object.BoolValue
205+
case Null:
206+
return nil
107207
}
208+
panic("invalid type")
108209
}

0 commit comments

Comments
 (0)