github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/define_index_objects.go (about) 1 package lang 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/lmorg/murex/lang/types" 10 ) 11 12 // IndexTemplateObject is a handy standard indexer you can use in your custom data types for structured object types. 13 // The point of this is to minimize code rewriting and standardising the behavior of the indexer. 14 func IndexTemplateObject(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 15 if p.IsNot { 16 return itoNot(p, params, object, marshaller) 17 } 18 return itoIndex(p, params, object, marshaller) 19 } 20 21 // itoIndex allow 22 func itoIndex(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 23 var objArray []interface{} 24 switch v := (*object).(type) { 25 case []interface{}: 26 for _, key := range params { 27 i, err := strconv.Atoi(key) 28 if err != nil { 29 return err 30 } 31 if i < 0 { 32 //i = len(v) + i 33 i += len(v) 34 } 35 if i >= len(v) { 36 return errors.New("key '" + key + "' greater than number of items in array") 37 } 38 39 if len(params) > 1 { 40 objArray = append(objArray, v[i]) 41 42 } else { 43 switch v[i].(type) { 44 case nil: 45 p.Stdout.SetDataType(types.Null) 46 case bool: 47 p.Stdout.SetDataType(types.Boolean) 48 if v[i].(bool) { 49 p.Stdout.Write(types.TrueByte) 50 } else { 51 p.Stdout.Write(types.FalseByte) 52 } 53 case int: 54 p.Stdout.SetDataType(types.Integer) 55 s := strconv.Itoa(v[i].(int)) 56 p.Stdout.Write([]byte(s)) 57 case float64: 58 p.Stdout.SetDataType(types.Number) 59 s := types.FloatToString(v[i].(float64)) 60 p.Stdout.Write([]byte(s)) 61 case string: 62 p.Stdout.SetDataType(types.String) 63 p.Stdout.Write([]byte(v[i].(string))) 64 default: 65 b, err := marshaller(v[i]) 66 if err != nil { 67 return err 68 } 69 p.Stdout.Writeln(b) 70 } 71 } 72 } 73 if len(objArray) > 0 { 74 b, err := marshaller(objArray) 75 if err != nil { 76 return err 77 } 78 p.Stdout.Writeln(b) 79 } 80 return nil 81 82 case map[string]interface{}: 83 var ( 84 obj interface{} 85 err error 86 ) 87 88 for i := range params { 89 if len(params[i]) > 2 && params[i][0] == '[' && params[i][len(params[i])-1] == ']' { 90 obj, err = ElementLookup(v, params[i][1:len(params[i])-1]) 91 if err != nil { 92 return err 93 } 94 95 } else { 96 97 switch { 98 case v[params[i]] != nil: 99 obj = v[params[i]] 100 case v[strings.Title(params[i])] != nil: 101 obj = v[strings.Title(params[i])] 102 case v[strings.ToLower(params[i])] != nil: 103 obj = v[strings.ToLower(params[i])] 104 case v[strings.ToUpper(params[i])] != nil: 105 obj = v[strings.ToUpper(params[i])] 106 default: 107 return errors.New("key '" + params[i] + "' not found") 108 } 109 } 110 111 if len(params) > 1 { 112 objArray = append(objArray, obj) 113 114 } else { 115 switch obj := obj.(type) { 116 case nil: 117 p.Stdout.SetDataType(types.Null) 118 case bool: 119 p.Stdout.SetDataType(types.Boolean) 120 if obj { 121 p.Stdout.Write(types.TrueByte) 122 } else { 123 p.Stdout.Write(types.FalseByte) 124 } 125 case int: 126 p.Stdout.SetDataType(types.Integer) 127 s := strconv.Itoa(obj) 128 p.Stdout.Write([]byte(s)) 129 case float64: 130 p.Stdout.SetDataType(types.Number) 131 s := types.FloatToString(obj) 132 p.Stdout.Write([]byte(s)) 133 case string: 134 p.Stdout.SetDataType(types.String) 135 p.Stdout.Write([]byte(obj)) 136 default: 137 b, err := marshaller(obj) 138 if err != nil { 139 return err 140 } 141 p.Stdout.Writeln(b) 142 } 143 } 144 } 145 if len(objArray) > 0 { 146 b, err := marshaller(objArray) 147 if err != nil { 148 return err 149 } 150 p.Stdout.Writeln(b) 151 } 152 return nil 153 154 case map[interface{}]interface{}: 155 for i := range params { 156 //if v[key] == nil { 157 // return errors.New("key '" + key + "' not found.") 158 //} 159 switch { 160 case v[params[i]] != nil: 161 case v[strings.Title(params[i])] != nil: 162 params[i] = strings.Title(params[i]) 163 case v[strings.ToLower(params[i])] != nil: 164 params[i] = strings.ToLower(params[i]) 165 case v[strings.ToUpper(params[i])] != nil: 166 params[i] = strings.ToUpper(params[i]) 167 //case v[strings.ToTitle(params[i])] != nil: 168 // params[i] = strings.ToTitle(params[i]) 169 default: 170 return errors.New("key '" + params[i] + "' not found") 171 } 172 173 if len(params) > 1 { 174 objArray = append(objArray, v[params[i]]) 175 176 } else { 177 switch v[params[i]].(type) { 178 case nil: 179 p.Stdout.SetDataType(types.Null) 180 case bool: 181 p.Stdout.SetDataType(types.Boolean) 182 if v[params[i]].(bool) { 183 p.Stdout.Write(types.TrueByte) 184 } else { 185 p.Stdout.Write(types.FalseByte) 186 } 187 case int: 188 p.Stdout.SetDataType(types.Integer) 189 s := strconv.Itoa(v[params[i]].(int)) 190 p.Stdout.Write([]byte(s)) 191 case float64: 192 p.Stdout.SetDataType(types.Number) 193 s := types.FloatToString(v[params[i]].(float64)) 194 p.Stdout.Write([]byte(s)) 195 case string: 196 p.Stdout.SetDataType(types.String) 197 p.Stdout.Write([]byte(v[params[i]].(string))) 198 default: 199 b, err := marshaller(v[params[i]]) 200 if err != nil { 201 return err 202 } 203 p.Stdout.Writeln(b) 204 } 205 } 206 } 207 if len(objArray) > 0 { 208 b, err := marshaller(objArray) 209 if err != nil { 210 return err 211 } 212 p.Stdout.Writeln(b) 213 } 214 return nil 215 216 default: 217 return errors.New("object cannot be indexed") 218 } 219 } 220 221 // itoNot requires the indexes to be explicit 222 func itoNot(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 223 switch v := (*object).(type) { 224 case []interface{}: 225 var objArray []interface{} 226 not := make(map[int]bool) 227 for _, key := range params { 228 i, err := strconv.Atoi(key) 229 if err != nil { 230 return err 231 } 232 if i < 0 { 233 return errors.New("cannot have negative keys in array") 234 } 235 if i >= len(v) { 236 return errors.New("Key '" + key + "' greater than number of items in array") 237 } 238 239 not[i] = true 240 } 241 242 for i := range v { 243 if !not[i] { 244 objArray = append(objArray, v[i]) 245 } 246 } 247 248 //if len(objArray) > 0 { 249 b, err := marshaller(objArray) 250 if err != nil { 251 return err 252 } 253 _, err = p.Stdout.Writeln(b) 254 //} 255 return err 256 257 case map[string]interface{}: 258 objMap := make(map[string]interface{}) 259 not := make(map[string]bool) 260 for _, key := range params { 261 not[key] = true 262 not[strings.Title(key)] = true 263 not[strings.ToLower(key)] = true 264 not[strings.ToUpper(key)] = true 265 //not[strings.ToTitle(key)] = true 266 } 267 268 for s := range v { 269 if !not[s] { 270 objMap[s] = v[s] 271 } 272 } 273 274 //if len(objMap) > 0 { 275 b, err := marshaller(objMap) 276 if err != nil { 277 return err 278 } 279 p.Stdout.Writeln(b) 280 //} 281 return nil 282 283 case map[interface{}]interface{}: 284 objMap := make(map[interface{}]interface{}) 285 not := make(map[string]bool) 286 for _, key := range params { 287 not[key] = true 288 not[strings.Title(key)] = true 289 not[strings.ToLower(key)] = true 290 not[strings.ToUpper(key)] = true 291 //not[strings.ToTitle(key)] = true 292 } 293 294 for iface := range v { 295 s := fmt.Sprint(iface) 296 if !not[s] { 297 objMap[iface] = v[iface] 298 } 299 } 300 301 //if len(objMap) > 0 { 302 b, err := marshaller(objMap) 303 if err != nil { 304 return err 305 } 306 _, err = p.Stdout.Writeln(b) 307 //} 308 return err 309 310 default: 311 return errors.New("object cannot be !indexed") 312 } 313 }