1 package jmespath
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "math"
8 "reflect"
9 "sort"
10 "strconv"
11 "strings"
12 "unicode/utf8"
13 )
14
15 type jpFunction func(arguments []interface{}) (interface{}, error)
16
17 type jpType string
18
19 const (
20 jpNumber jpType = "number"
21 jpString jpType = "string"
22 jpArray jpType = "array"
23 jpObject jpType = "object"
24 jpArrayNumber jpType = "array[number]"
25 jpArrayString jpType = "array[string]"
26 jpExpref jpType = "expref"
27 jpAny jpType = "any"
28 )
29
30 type functionEntry struct {
31 name string
32 arguments []argSpec
33 handler jpFunction
34 hasExpRef bool
35 }
36
37 type argSpec struct {
38 types []jpType
39 variadic bool
40 }
41
42 type byExprString struct {
43 intr *treeInterpreter
44 node ASTNode
45 items []interface{}
46 hasError bool
47 }
48
49 func (a *byExprString) Len() int {
50 return len(a.items)
51 }
52 func (a *byExprString) Swap(i, j int) {
53 a.items[i], a.items[j] = a.items[j], a.items[i]
54 }
55 func (a *byExprString) Less(i, j int) bool {
56 first, err := a.intr.Execute(a.node, a.items[i])
57 if err != nil {
58 a.hasError = true
59
60 return true
61 }
62 ith, ok := first.(string)
63 if !ok {
64 a.hasError = true
65 return true
66 }
67 second, err := a.intr.Execute(a.node, a.items[j])
68 if err != nil {
69 a.hasError = true
70
71 return true
72 }
73 jth, ok := second.(string)
74 if !ok {
75 a.hasError = true
76 return true
77 }
78 return ith < jth
79 }
80
81 type byExprFloat struct {
82 intr *treeInterpreter
83 node ASTNode
84 items []interface{}
85 hasError bool
86 }
87
88 func (a *byExprFloat) Len() int {
89 return len(a.items)
90 }
91 func (a *byExprFloat) Swap(i, j int) {
92 a.items[i], a.items[j] = a.items[j], a.items[i]
93 }
94 func (a *byExprFloat) Less(i, j int) bool {
95 first, err := a.intr.Execute(a.node, a.items[i])
96 if err != nil {
97 a.hasError = true
98
99 return true
100 }
101 ith, ok := first.(float64)
102 if !ok {
103 a.hasError = true
104 return true
105 }
106 second, err := a.intr.Execute(a.node, a.items[j])
107 if err != nil {
108 a.hasError = true
109
110 return true
111 }
112 jth, ok := second.(float64)
113 if !ok {
114 a.hasError = true
115 return true
116 }
117 return ith < jth
118 }
119
120 type functionCaller struct {
121 functionTable map[string]functionEntry
122 }
123
124 func newFunctionCaller() *functionCaller {
125 caller := &functionCaller{}
126 caller.functionTable = map[string]functionEntry{
127 "length": {
128 name: "length",
129 arguments: []argSpec{
130 {types: []jpType{jpString, jpArray, jpObject}},
131 },
132 handler: jpfLength,
133 },
134 "starts_with": {
135 name: "starts_with",
136 arguments: []argSpec{
137 {types: []jpType{jpString}},
138 {types: []jpType{jpString}},
139 },
140 handler: jpfStartsWith,
141 },
142 "abs": {
143 name: "abs",
144 arguments: []argSpec{
145 {types: []jpType{jpNumber}},
146 },
147 handler: jpfAbs,
148 },
149 "avg": {
150 name: "avg",
151 arguments: []argSpec{
152 {types: []jpType{jpArrayNumber}},
153 },
154 handler: jpfAvg,
155 },
156 "ceil": {
157 name: "ceil",
158 arguments: []argSpec{
159 {types: []jpType{jpNumber}},
160 },
161 handler: jpfCeil,
162 },
163 "contains": {
164 name: "contains",
165 arguments: []argSpec{
166 {types: []jpType{jpArray, jpString}},
167 {types: []jpType{jpAny}},
168 },
169 handler: jpfContains,
170 },
171 "ends_with": {
172 name: "ends_with",
173 arguments: []argSpec{
174 {types: []jpType{jpString}},
175 {types: []jpType{jpString}},
176 },
177 handler: jpfEndsWith,
178 },
179 "floor": {
180 name: "floor",
181 arguments: []argSpec{
182 {types: []jpType{jpNumber}},
183 },
184 handler: jpfFloor,
185 },
186 "map": {
187 name: "amp",
188 arguments: []argSpec{
189 {types: []jpType{jpExpref}},
190 {types: []jpType{jpArray}},
191 },
192 handler: jpfMap,
193 hasExpRef: true,
194 },
195 "max": {
196 name: "max",
197 arguments: []argSpec{
198 {types: []jpType{jpArrayNumber, jpArrayString}},
199 },
200 handler: jpfMax,
201 },
202 "merge": {
203 name: "merge",
204 arguments: []argSpec{
205 {types: []jpType{jpObject}, variadic: true},
206 },
207 handler: jpfMerge,
208 },
209 "max_by": {
210 name: "max_by",
211 arguments: []argSpec{
212 {types: []jpType{jpArray}},
213 {types: []jpType{jpExpref}},
214 },
215 handler: jpfMaxBy,
216 hasExpRef: true,
217 },
218 "sum": {
219 name: "sum",
220 arguments: []argSpec{
221 {types: []jpType{jpArrayNumber}},
222 },
223 handler: jpfSum,
224 },
225 "min": {
226 name: "min",
227 arguments: []argSpec{
228 {types: []jpType{jpArrayNumber, jpArrayString}},
229 },
230 handler: jpfMin,
231 },
232 "min_by": {
233 name: "min_by",
234 arguments: []argSpec{
235 {types: []jpType{jpArray}},
236 {types: []jpType{jpExpref}},
237 },
238 handler: jpfMinBy,
239 hasExpRef: true,
240 },
241 "type": {
242 name: "type",
243 arguments: []argSpec{
244 {types: []jpType{jpAny}},
245 },
246 handler: jpfType,
247 },
248 "keys": {
249 name: "keys",
250 arguments: []argSpec{
251 {types: []jpType{jpObject}},
252 },
253 handler: jpfKeys,
254 },
255 "values": {
256 name: "values",
257 arguments: []argSpec{
258 {types: []jpType{jpObject}},
259 },
260 handler: jpfValues,
261 },
262 "sort": {
263 name: "sort",
264 arguments: []argSpec{
265 {types: []jpType{jpArrayString, jpArrayNumber}},
266 },
267 handler: jpfSort,
268 },
269 "sort_by": {
270 name: "sort_by",
271 arguments: []argSpec{
272 {types: []jpType{jpArray}},
273 {types: []jpType{jpExpref}},
274 },
275 handler: jpfSortBy,
276 hasExpRef: true,
277 },
278 "join": {
279 name: "join",
280 arguments: []argSpec{
281 {types: []jpType{jpString}},
282 {types: []jpType{jpArrayString}},
283 },
284 handler: jpfJoin,
285 },
286 "reverse": {
287 name: "reverse",
288 arguments: []argSpec{
289 {types: []jpType{jpArray, jpString}},
290 },
291 handler: jpfReverse,
292 },
293 "to_array": {
294 name: "to_array",
295 arguments: []argSpec{
296 {types: []jpType{jpAny}},
297 },
298 handler: jpfToArray,
299 },
300 "to_string": {
301 name: "to_string",
302 arguments: []argSpec{
303 {types: []jpType{jpAny}},
304 },
305 handler: jpfToString,
306 },
307 "to_number": {
308 name: "to_number",
309 arguments: []argSpec{
310 {types: []jpType{jpAny}},
311 },
312 handler: jpfToNumber,
313 },
314 "not_null": {
315 name: "not_null",
316 arguments: []argSpec{
317 {types: []jpType{jpAny}, variadic: true},
318 },
319 handler: jpfNotNull,
320 },
321 }
322 return caller
323 }
324
325 func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) {
326 if len(e.arguments) == 0 {
327 return arguments, nil
328 }
329 if !e.arguments[len(e.arguments)-1].variadic {
330 if len(e.arguments) != len(arguments) {
331 return nil, errors.New("incorrect number of args")
332 }
333 for i, spec := range e.arguments {
334 userArg := arguments[i]
335 err := spec.typeCheck(userArg)
336 if err != nil {
337 return nil, err
338 }
339 }
340 return arguments, nil
341 }
342 if len(arguments) < len(e.arguments) {
343 return nil, errors.New("invalid arity")
344 }
345 return arguments, nil
346 }
347
348 func (a *argSpec) typeCheck(arg interface{}) error {
349 for _, t := range a.types {
350 switch t {
351 case jpNumber:
352 if _, ok := arg.(float64); ok {
353 return nil
354 }
355 case jpString:
356 if _, ok := arg.(string); ok {
357 return nil
358 }
359 case jpArray:
360 if isSliceType(arg) {
361 return nil
362 }
363 case jpObject:
364 if _, ok := arg.(map[string]interface{}); ok {
365 return nil
366 }
367 case jpArrayNumber:
368 if _, ok := toArrayNum(arg); ok {
369 return nil
370 }
371 case jpArrayString:
372 if _, ok := toArrayStr(arg); ok {
373 return nil
374 }
375 case jpAny:
376 return nil
377 case jpExpref:
378 if _, ok := arg.(expRef); ok {
379 return nil
380 }
381 }
382 }
383 return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types)
384 }
385
386 func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) {
387 entry, ok := f.functionTable[name]
388 if !ok {
389 return nil, errors.New("unknown function: " + name)
390 }
391 resolvedArgs, err := entry.resolveArgs(arguments)
392 if err != nil {
393 return nil, err
394 }
395 if entry.hasExpRef {
396 var extra []interface{}
397 extra = append(extra, intr)
398 resolvedArgs = append(extra, resolvedArgs...)
399 }
400 return entry.handler(resolvedArgs)
401 }
402
403 func jpfAbs(arguments []interface{}) (interface{}, error) {
404 num := arguments[0].(float64)
405 return math.Abs(num), nil
406 }
407
408 func jpfLength(arguments []interface{}) (interface{}, error) {
409 arg := arguments[0]
410 if c, ok := arg.(string); ok {
411 return float64(utf8.RuneCountInString(c)), nil
412 } else if isSliceType(arg) {
413 v := reflect.ValueOf(arg)
414 return float64(v.Len()), nil
415 } else if c, ok := arg.(map[string]interface{}); ok {
416 return float64(len(c)), nil
417 }
418 return nil, errors.New("could not compute length()")
419 }
420
421 func jpfStartsWith(arguments []interface{}) (interface{}, error) {
422 search := arguments[0].(string)
423 prefix := arguments[1].(string)
424 return strings.HasPrefix(search, prefix), nil
425 }
426
427 func jpfAvg(arguments []interface{}) (interface{}, error) {
428
429
430 args := arguments[0].([]interface{})
431 length := float64(len(args))
432 numerator := 0.0
433 for _, n := range args {
434 numerator += n.(float64)
435 }
436 return numerator / length, nil
437 }
438 func jpfCeil(arguments []interface{}) (interface{}, error) {
439 val := arguments[0].(float64)
440 return math.Ceil(val), nil
441 }
442 func jpfContains(arguments []interface{}) (interface{}, error) {
443 search := arguments[0]
444 el := arguments[1]
445 if searchStr, ok := search.(string); ok {
446 if elStr, ok := el.(string); ok {
447 return strings.Contains(searchStr, elStr), nil
448 }
449 return false, nil
450 }
451
452 general := search.([]interface{})
453 for _, item := range general {
454 if item == el {
455 return true, nil
456 }
457 }
458 return false, nil
459 }
460 func jpfEndsWith(arguments []interface{}) (interface{}, error) {
461 search := arguments[0].(string)
462 suffix := arguments[1].(string)
463 return strings.HasSuffix(search, suffix), nil
464 }
465 func jpfFloor(arguments []interface{}) (interface{}, error) {
466 val := arguments[0].(float64)
467 return math.Floor(val), nil
468 }
469 func jpfMap(arguments []interface{}) (interface{}, error) {
470 intr := arguments[0].(*treeInterpreter)
471 exp := arguments[1].(expRef)
472 node := exp.ref
473 arr := arguments[2].([]interface{})
474 mapped := make([]interface{}, 0, len(arr))
475 for _, value := range arr {
476 current, err := intr.Execute(node, value)
477 if err != nil {
478 return nil, err
479 }
480 mapped = append(mapped, current)
481 }
482 return mapped, nil
483 }
484 func jpfMax(arguments []interface{}) (interface{}, error) {
485 if items, ok := toArrayNum(arguments[0]); ok {
486 if len(items) == 0 {
487 return nil, nil
488 }
489 if len(items) == 1 {
490 return items[0], nil
491 }
492 best := items[0]
493 for _, item := range items[1:] {
494 if item > best {
495 best = item
496 }
497 }
498 return best, nil
499 }
500
501 items, _ := toArrayStr(arguments[0])
502 if len(items) == 0 {
503 return nil, nil
504 }
505 if len(items) == 1 {
506 return items[0], nil
507 }
508 best := items[0]
509 for _, item := range items[1:] {
510 if item > best {
511 best = item
512 }
513 }
514 return best, nil
515 }
516 func jpfMerge(arguments []interface{}) (interface{}, error) {
517 final := make(map[string]interface{})
518 for _, m := range arguments {
519 mapped := m.(map[string]interface{})
520 for key, value := range mapped {
521 final[key] = value
522 }
523 }
524 return final, nil
525 }
526 func jpfMaxBy(arguments []interface{}) (interface{}, error) {
527 intr := arguments[0].(*treeInterpreter)
528 arr := arguments[1].([]interface{})
529 exp := arguments[2].(expRef)
530 node := exp.ref
531 if len(arr) == 0 {
532 return nil, nil
533 } else if len(arr) == 1 {
534 return arr[0], nil
535 }
536 start, err := intr.Execute(node, arr[0])
537 if err != nil {
538 return nil, err
539 }
540 switch t := start.(type) {
541 case float64:
542 bestVal := t
543 bestItem := arr[0]
544 for _, item := range arr[1:] {
545 result, err := intr.Execute(node, item)
546 if err != nil {
547 return nil, err
548 }
549 current, ok := result.(float64)
550 if !ok {
551 return nil, errors.New("invalid type, must be number")
552 }
553 if current > bestVal {
554 bestVal = current
555 bestItem = item
556 }
557 }
558 return bestItem, nil
559 case string:
560 bestVal := t
561 bestItem := arr[0]
562 for _, item := range arr[1:] {
563 result, err := intr.Execute(node, item)
564 if err != nil {
565 return nil, err
566 }
567 current, ok := result.(string)
568 if !ok {
569 return nil, errors.New("invalid type, must be string")
570 }
571 if current > bestVal {
572 bestVal = current
573 bestItem = item
574 }
575 }
576 return bestItem, nil
577 default:
578 return nil, errors.New("invalid type, must be number of string")
579 }
580 }
581 func jpfSum(arguments []interface{}) (interface{}, error) {
582 items, _ := toArrayNum(arguments[0])
583 sum := 0.0
584 for _, item := range items {
585 sum += item
586 }
587 return sum, nil
588 }
589
590 func jpfMin(arguments []interface{}) (interface{}, error) {
591 if items, ok := toArrayNum(arguments[0]); ok {
592 if len(items) == 0 {
593 return nil, nil
594 }
595 if len(items) == 1 {
596 return items[0], nil
597 }
598 best := items[0]
599 for _, item := range items[1:] {
600 if item < best {
601 best = item
602 }
603 }
604 return best, nil
605 }
606 items, _ := toArrayStr(arguments[0])
607 if len(items) == 0 {
608 return nil, nil
609 }
610 if len(items) == 1 {
611 return items[0], nil
612 }
613 best := items[0]
614 for _, item := range items[1:] {
615 if item < best {
616 best = item
617 }
618 }
619 return best, nil
620 }
621
622 func jpfMinBy(arguments []interface{}) (interface{}, error) {
623 intr := arguments[0].(*treeInterpreter)
624 arr := arguments[1].([]interface{})
625 exp := arguments[2].(expRef)
626 node := exp.ref
627 if len(arr) == 0 {
628 return nil, nil
629 } else if len(arr) == 1 {
630 return arr[0], nil
631 }
632 start, err := intr.Execute(node, arr[0])
633 if err != nil {
634 return nil, err
635 }
636 if t, ok := start.(float64); ok {
637 bestVal := t
638 bestItem := arr[0]
639 for _, item := range arr[1:] {
640 result, err := intr.Execute(node, item)
641 if err != nil {
642 return nil, err
643 }
644 current, ok := result.(float64)
645 if !ok {
646 return nil, errors.New("invalid type, must be number")
647 }
648 if current < bestVal {
649 bestVal = current
650 bestItem = item
651 }
652 }
653 return bestItem, nil
654 } else if t, ok := start.(string); ok {
655 bestVal := t
656 bestItem := arr[0]
657 for _, item := range arr[1:] {
658 result, err := intr.Execute(node, item)
659 if err != nil {
660 return nil, err
661 }
662 current, ok := result.(string)
663 if !ok {
664 return nil, errors.New("invalid type, must be string")
665 }
666 if current < bestVal {
667 bestVal = current
668 bestItem = item
669 }
670 }
671 return bestItem, nil
672 } else {
673 return nil, errors.New("invalid type, must be number of string")
674 }
675 }
676 func jpfType(arguments []interface{}) (interface{}, error) {
677 arg := arguments[0]
678 if _, ok := arg.(float64); ok {
679 return "number", nil
680 }
681 if _, ok := arg.(string); ok {
682 return "string", nil
683 }
684 if _, ok := arg.([]interface{}); ok {
685 return "array", nil
686 }
687 if _, ok := arg.(map[string]interface{}); ok {
688 return "object", nil
689 }
690 if arg == nil {
691 return "null", nil
692 }
693 if arg == true || arg == false {
694 return "boolean", nil
695 }
696 return nil, errors.New("unknown type")
697 }
698 func jpfKeys(arguments []interface{}) (interface{}, error) {
699 arg := arguments[0].(map[string]interface{})
700 collected := make([]interface{}, 0, len(arg))
701 for key := range arg {
702 collected = append(collected, key)
703 }
704 return collected, nil
705 }
706 func jpfValues(arguments []interface{}) (interface{}, error) {
707 arg := arguments[0].(map[string]interface{})
708 collected := make([]interface{}, 0, len(arg))
709 for _, value := range arg {
710 collected = append(collected, value)
711 }
712 return collected, nil
713 }
714 func jpfSort(arguments []interface{}) (interface{}, error) {
715 if items, ok := toArrayNum(arguments[0]); ok {
716 d := sort.Float64Slice(items)
717 sort.Stable(d)
718 final := make([]interface{}, len(d))
719 for i, val := range d {
720 final[i] = val
721 }
722 return final, nil
723 }
724
725 items, _ := toArrayStr(arguments[0])
726 d := sort.StringSlice(items)
727 sort.Stable(d)
728 final := make([]interface{}, len(d))
729 for i, val := range d {
730 final[i] = val
731 }
732 return final, nil
733 }
734 func jpfSortBy(arguments []interface{}) (interface{}, error) {
735 intr := arguments[0].(*treeInterpreter)
736 arr := arguments[1].([]interface{})
737 exp := arguments[2].(expRef)
738 node := exp.ref
739 if len(arr) == 0 {
740 return arr, nil
741 } else if len(arr) == 1 {
742 return arr, nil
743 }
744 start, err := intr.Execute(node, arr[0])
745 if err != nil {
746 return nil, err
747 }
748 if _, ok := start.(float64); ok {
749 sortable := &byExprFloat{intr, node, arr, false}
750 sort.Stable(sortable)
751 if sortable.hasError {
752 return nil, errors.New("error in sort_by comparison")
753 }
754 return arr, nil
755 } else if _, ok := start.(string); ok {
756 sortable := &byExprString{intr, node, arr, false}
757 sort.Stable(sortable)
758 if sortable.hasError {
759 return nil, errors.New("error in sort_by comparison")
760 }
761 return arr, nil
762 } else {
763 return nil, errors.New("invalid type, must be number of string")
764 }
765 }
766 func jpfJoin(arguments []interface{}) (interface{}, error) {
767 sep := arguments[0].(string)
768
769
770 arrayStr := []string{}
771 for _, item := range arguments[1].([]interface{}) {
772 arrayStr = append(arrayStr, item.(string))
773 }
774 return strings.Join(arrayStr, sep), nil
775 }
776 func jpfReverse(arguments []interface{}) (interface{}, error) {
777 if s, ok := arguments[0].(string); ok {
778 r := []rune(s)
779 for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
780 r[i], r[j] = r[j], r[i]
781 }
782 return string(r), nil
783 }
784 items := arguments[0].([]interface{})
785 length := len(items)
786 reversed := make([]interface{}, length)
787 for i, item := range items {
788 reversed[length-(i+1)] = item
789 }
790 return reversed, nil
791 }
792 func jpfToArray(arguments []interface{}) (interface{}, error) {
793 if _, ok := arguments[0].([]interface{}); ok {
794 return arguments[0], nil
795 }
796 return arguments[:1:1], nil
797 }
798 func jpfToString(arguments []interface{}) (interface{}, error) {
799 if v, ok := arguments[0].(string); ok {
800 return v, nil
801 }
802 result, err := json.Marshal(arguments[0])
803 if err != nil {
804 return nil, err
805 }
806 return string(result), nil
807 }
808 func jpfToNumber(arguments []interface{}) (interface{}, error) {
809 arg := arguments[0]
810 if v, ok := arg.(float64); ok {
811 return v, nil
812 }
813 if v, ok := arg.(string); ok {
814 conv, err := strconv.ParseFloat(v, 64)
815 if err != nil {
816 return nil, nil
817 }
818 return conv, nil
819 }
820 if _, ok := arg.([]interface{}); ok {
821 return nil, nil
822 }
823 if _, ok := arg.(map[string]interface{}); ok {
824 return nil, nil
825 }
826 if arg == nil {
827 return nil, nil
828 }
829 if arg == true || arg == false {
830 return nil, nil
831 }
832 return nil, errors.New("unknown type")
833 }
834 func jpfNotNull(arguments []interface{}) (interface{}, error) {
835 for _, arg := range arguments {
836 if arg != nil {
837 return arg, nil
838 }
839 }
840 return nil, nil
841 }
842
View as plain text