github.com/MontFerret/ferret@v0.18.0/pkg/runtime/values/helpers.go (about) 1 package values 2 3 import ( 4 "context" 5 "encoding/binary" 6 "encoding/json" 7 "hash/fnv" 8 "reflect" 9 "sort" 10 "strconv" 11 "time" 12 13 "github.com/wI2L/jettison" 14 15 "github.com/MontFerret/ferret/pkg/runtime/core" 16 "github.com/MontFerret/ferret/pkg/runtime/values/types" 17 ) 18 19 // GetIn checks that from implements core.Getter interface. If it implements, 20 // GetIn call from.GetIn method, otherwise iterates over values and tries to resolve a given path. 21 func GetIn(ctx context.Context, from core.Value, byPath []core.Value) (core.Value, core.PathError) { 22 if len(byPath) == 0 { 23 return None, nil 24 } 25 26 var result = from 27 28 for i, segment := range byPath { 29 if result == None || result == nil { 30 break 31 } 32 33 segType := segment.Type() 34 35 switch curVal := result.(type) { 36 case *Object: 37 result, _ = curVal.Get(ToString(segment)) 38 case *Array: 39 if segType != types.Int { 40 return nil, core.NewPathError( 41 core.TypeError(segType, types.Int), 42 i, 43 ) 44 } 45 46 result = curVal.Get(segment.(Int)) 47 case String: 48 if segType != types.Int { 49 return nil, core.NewPathError( 50 core.TypeError(segType, types.Int), 51 i, 52 ) 53 } 54 55 result = curVal.At(ToInt(segment)) 56 case core.Getter: 57 return curVal.GetIn(ctx, byPath[i:]) 58 default: 59 return None, core.NewPathError(core.ErrInvalidPath, i) 60 } 61 } 62 63 return result, nil 64 } 65 66 func SetIn(ctx context.Context, to core.Value, byPath []core.Value, value core.Value) core.PathError { 67 if len(byPath) == 0 { 68 return nil 69 } 70 71 var parent core.Value 72 var current = to 73 target := len(byPath) - 1 74 75 for idx, segment := range byPath { 76 parent = current 77 isTarget := target == idx 78 segmentType := segment.Type() 79 80 switch parVal := parent.(type) { 81 case *Object: 82 if segmentType != types.String { 83 return core.NewPathError( 84 core.TypeError(segmentType, types.String), 85 idx, 86 ) 87 } 88 89 if !isTarget { 90 current, _ = parVal.Get(segment.(String)) 91 } else { 92 parVal.Set(segment.(String), value) 93 } 94 case *Array: 95 if segmentType != types.Int { 96 return core.NewPathError( 97 core.TypeError(segmentType, types.Int), 98 idx, 99 ) 100 } 101 102 if !isTarget { 103 current = parVal.Get(segment.(Int)) 104 } else { 105 if err := parVal.Set(segment.(Int), value); err != nil { 106 return core.NewPathError(err, idx) 107 } 108 } 109 case core.Setter: 110 return parVal.SetIn(ctx, byPath[idx:], value) 111 default: 112 // redefine parent 113 isArray := segmentType.Equals(types.Int) 114 115 // it's not an index 116 if !isArray { 117 obj := NewObject() 118 parent = obj 119 120 if segmentType != types.String { 121 return core.NewPathError(core.TypeError(segmentType, types.String), idx) 122 } 123 124 if isTarget { 125 obj.Set(segment.(String), value) 126 } 127 } else { 128 arr := NewArray(10) 129 parent = arr 130 131 if isTarget { 132 if err := arr.Set(segment.(Int), value); err != nil { 133 return core.NewPathError(err, idx) 134 } 135 } 136 } 137 138 // set new parent 139 nextPath := byPath 140 141 if idx > 0 { 142 nextPath = byPath[0 : idx-1] 143 } else { 144 nextPath = byPath[0:] 145 } 146 147 if err := SetIn(ctx, to, nextPath, parent); err != nil { 148 return err 149 } 150 151 if !isTarget { 152 current = None 153 } 154 } 155 } 156 157 return nil 158 } 159 160 func ReturnOrNext(ctx context.Context, path []core.Value, idx int, out core.Value, err error) (core.Value, core.PathError) { 161 if err != nil { 162 pathErr, ok := err.(core.PathError) 163 164 if ok { 165 return None, core.NewPathErrorFrom(pathErr, idx) 166 } 167 168 return None, core.NewPathError(err, idx) 169 } 170 171 if len(path) > (idx + 1) { 172 out, pathErr := GetIn(ctx, out, path[idx+1:]) 173 174 if pathErr != nil { 175 return None, core.NewPathErrorFrom(pathErr, idx) 176 } 177 178 return out, nil 179 } 180 181 return out, nil 182 } 183 184 func Parse(input interface{}) core.Value { 185 switch value := input.(type) { 186 case bool: 187 return NewBoolean(value) 188 case string: 189 return NewString(value) 190 case int64: 191 return NewInt(int(value)) 192 case int32: 193 return NewInt(int(value)) 194 case int16: 195 return NewInt(int(value)) 196 case int8: 197 return NewInt(int(value)) 198 case int: 199 return NewInt(value) 200 case float64: 201 return NewFloat(value) 202 case float32: 203 return NewFloat(float64(value)) 204 case time.Time: 205 return NewDateTime(value) 206 case []interface{}: 207 arr := NewArray(len(value)) 208 209 for _, el := range value { 210 arr.Push(Parse(el)) 211 } 212 213 return arr 214 case map[string]interface{}: 215 obj := NewObject() 216 217 for key, el := range value { 218 obj.Set(NewString(key), Parse(el)) 219 } 220 221 return obj 222 case []byte: 223 return NewBinary(value) 224 case nil: 225 return None 226 default: 227 v := reflect.ValueOf(value) 228 t := reflect.TypeOf(value) 229 kind := t.Kind() 230 231 if kind == reflect.Ptr { 232 el := v.Elem() 233 234 if el.Kind() == 0 { 235 return None 236 } 237 238 return Parse(el.Interface()) 239 } 240 241 if kind == reflect.Slice || kind == reflect.Array { 242 size := v.Len() 243 arr := NewArray(size) 244 245 for i := 0; i < size; i++ { 246 curVal := v.Index(i) 247 arr.Push(Parse(curVal.Interface())) 248 } 249 250 return arr 251 } 252 253 if kind == reflect.Map { 254 keys := v.MapKeys() 255 obj := NewObject() 256 257 for _, k := range keys { 258 key := Parse(k.Interface()) 259 curVal := v.MapIndex(k) 260 261 obj.Set(NewString(key.String()), Parse(curVal.Interface())) 262 } 263 264 return obj 265 } 266 267 if kind == reflect.Struct { 268 obj := NewObject() 269 size := t.NumField() 270 271 for i := 0; i < size; i++ { 272 field := t.Field(i) 273 fieldValue := v.Field(i) 274 275 obj.Set(NewString(field.Name), Parse(fieldValue.Interface())) 276 } 277 278 return obj 279 } 280 281 return None 282 } 283 } 284 285 func Unmarshal(value json.RawMessage) (core.Value, error) { 286 var o interface{} 287 288 err := json.Unmarshal(value, &o) 289 290 if err != nil { 291 return None, err 292 } 293 294 return Parse(o), nil 295 } 296 297 func MustMarshal(value core.Value) json.RawMessage { 298 out, err := value.MarshalJSON() 299 300 if err != nil { 301 panic(err) 302 } 303 304 return out 305 } 306 307 func MustMarshalAny(input interface{}) json.RawMessage { 308 out, err := jettison.MarshalOpts(input, jettison.NoHTMLEscaping()) 309 310 if err != nil { 311 panic(err) 312 } 313 314 return out 315 } 316 317 func ToBoolean(input core.Value) Boolean { 318 switch input.Type() { 319 case types.Boolean: 320 return input.(Boolean) 321 case types.String: 322 return NewBoolean(input.(String) != "") 323 case types.Int: 324 return NewBoolean(input.(Int) != 0) 325 case types.Float: 326 return NewBoolean(input.(Float) != 0) 327 case types.DateTime: 328 return NewBoolean(!input.(DateTime).IsZero()) 329 case types.None: 330 return False 331 default: 332 return True 333 } 334 } 335 336 func ToFloat(input core.Value) Float { 337 switch val := input.(type) { 338 case Float: 339 return val 340 case Int: 341 return Float(val) 342 case String: 343 i, err := strconv.ParseFloat(string(val), 64) 344 345 if err != nil { 346 return ZeroFloat 347 } 348 349 return Float(i) 350 case Boolean: 351 if val { 352 return Float(1) 353 } 354 355 return Float(0) 356 case DateTime: 357 dt := input.(DateTime) 358 359 if dt.IsZero() { 360 return ZeroFloat 361 } 362 363 return NewFloat(float64(dt.Unix())) 364 case *Array: 365 length := val.Length() 366 367 if length == 0 { 368 return ZeroFloat 369 } 370 371 res := ZeroFloat 372 373 for i := Int(0); i < length; i++ { 374 res += ToFloat(val.Get(i)) 375 } 376 377 return res 378 default: 379 return ZeroFloat 380 } 381 } 382 383 func ToString(input core.Value) String { 384 switch val := input.(type) { 385 case String: 386 return val 387 default: 388 return NewString(val.String()) 389 } 390 } 391 392 func ToInt(input core.Value) Int { 393 switch val := input.(type) { 394 case Int: 395 return val 396 case Float: 397 return Int(val) 398 case String: 399 i, err := strconv.ParseInt(string(val), 10, 64) 400 401 if err != nil { 402 return ZeroInt 403 } 404 405 return Int(i) 406 case Boolean: 407 if val { 408 return Int(1) 409 } 410 411 return Int(0) 412 case DateTime: 413 dt := input.(DateTime) 414 415 if dt.IsZero() { 416 return ZeroInt 417 } 418 419 return NewInt(int(dt.Unix())) 420 case *Array: 421 length := val.Length() 422 423 if length == 0 { 424 return ZeroInt 425 } 426 427 res := ZeroInt 428 429 for i := Int(0); i < length; i++ { 430 res += ToInt(val.Get(i)) 431 } 432 433 return res 434 default: 435 return ZeroInt 436 } 437 } 438 439 func ToIntDefault(input core.Value, defaultValue Int) Int { 440 if result := ToInt(input); result > 0 { 441 return result 442 } 443 444 return defaultValue 445 } 446 447 func ToArray(ctx context.Context, input core.Value) *Array { 448 switch value := input.(type) { 449 case Boolean, 450 Int, 451 Float, 452 String, 453 DateTime: 454 455 return NewArrayWith(value) 456 case *Array: 457 return value.Copy().(*Array) 458 case *Object: 459 arr := NewArray(int(value.Length())) 460 461 value.ForEach(func(value core.Value, key string) bool { 462 arr.Push(value) 463 464 return true 465 }) 466 467 return arr 468 case core.Iterable: 469 iterator, err := value.Iterate(ctx) 470 471 if err != nil { 472 return NewArray(0) 473 } 474 475 arr := NewArray(10) 476 477 for { 478 val, _, err := iterator.Next(ctx) 479 480 if err != nil { 481 return NewArray(0) 482 } 483 484 if val == None { 485 break 486 } 487 488 arr.Push(val) 489 } 490 491 return arr 492 default: 493 return EmptyArray() 494 } 495 } 496 497 func ToObject(ctx context.Context, input core.Value) *Object { 498 switch value := input.(type) { 499 case *Object: 500 return value 501 case *Array: 502 obj := NewObject() 503 504 value.ForEach(func(value core.Value, idx int) bool { 505 obj.Set(ToString(Int(idx)), value) 506 507 return true 508 }) 509 510 return obj 511 case core.Iterable: 512 iterator, err := value.Iterate(ctx) 513 514 if err != nil { 515 return NewObject() 516 } 517 518 obj := NewObject() 519 520 for { 521 val, key, err := iterator.Next(ctx) 522 523 if err != nil { 524 return obj 525 } 526 527 if val == None { 528 break 529 } 530 531 obj.Set(String(key.String()), val) 532 } 533 534 return obj 535 default: 536 return NewObject() 537 } 538 } 539 540 func ToStrings(input *Array) []String { 541 res := make([]String, input.Length()) 542 543 input.ForEach(func(v core.Value, i int) bool { 544 res[i] = NewString(v.String()) 545 546 return true 547 }) 548 549 return res 550 } 551 552 func Hash(rtType core.Type, content []byte) uint64 { 553 h := fnv.New64a() 554 555 h.Write([]byte(rtType.String())) 556 h.Write([]byte(":")) 557 h.Write(content) 558 559 return h.Sum64() 560 } 561 562 func MapHash(input map[string]core.Value) uint64 { 563 h := fnv.New64a() 564 565 keys := make([]string, 0, len(input)) 566 567 for key := range input { 568 keys = append(keys, key) 569 } 570 571 // order does not really matter 572 // but it will give us a consistent hash sum 573 sort.Strings(keys) 574 endIndex := len(keys) - 1 575 576 h.Write([]byte("{")) 577 578 for idx, key := range keys { 579 h.Write([]byte(key)) 580 h.Write([]byte(":")) 581 582 el := input[key] 583 584 bytes := make([]byte, 8) 585 binary.LittleEndian.PutUint64(bytes, el.Hash()) 586 587 h.Write(bytes) 588 589 if idx != endIndex { 590 h.Write([]byte(",")) 591 } 592 } 593 594 h.Write([]byte("}")) 595 596 return h.Sum64() 597 } 598 599 func IsNumber(input core.Value) Boolean { 600 t := input.Type() 601 602 return t == types.Int || t == types.Float 603 } 604 605 func UnwrapStrings(values []String) []string { 606 out := make([]string, len(values)) 607 608 for i, v := range values { 609 out[i] = v.String() 610 } 611 612 return out 613 }