bring back yahoo pipes!
1package transforms
2
3import (
4 "context"
5 "fmt"
6 "sort"
7
8 "github.com/kierank/pipes/nodes"
9)
10
11type SortNode struct{}
12
13func (n *SortNode) Type() string { return "sort" }
14func (n *SortNode) Label() string { return "Sort" }
15func (n *SortNode) Description() string { return "Sort items by a field" }
16func (n *SortNode) Category() string { return "transform" }
17func (n *SortNode) Inputs() int { return 1 }
18func (n *SortNode) Outputs() int { return 1 }
19
20func (n *SortNode) Execute(ctx context.Context, config map[string]interface{}, inputs [][]interface{}, execCtx *nodes.Context) ([]interface{}, error) {
21 if len(inputs) == 0 {
22 return []interface{}{}, nil
23 }
24
25 items := inputs[0]
26 field, _ := config["field"].(string)
27 order, _ := config["order"].(string)
28
29 if field == "" {
30 return items, nil
31 }
32
33 if order == "" {
34 order = "desc"
35 }
36
37 // Create a sortable slice
38 sorted := make([]interface{}, len(items))
39 copy(sorted, items)
40
41 sort.SliceStable(sorted, func(i, j int) bool {
42 iMap, iOk := sorted[i].(map[string]interface{})
43 jMap, jOk := sorted[j].(map[string]interface{})
44
45 if !iOk || !jOk {
46 return false
47 }
48
49 iRaw := getNestedValue(iMap, field)
50 jRaw := getNestedValue(jMap, field)
51
52 // Try numeric comparison first (for timestamps, etc.)
53 iNum, iIsNum := toFloat(iRaw)
54 jNum, jIsNum := toFloat(jRaw)
55
56 if iIsNum && jIsNum {
57 if order == "desc" {
58 return iNum > jNum
59 }
60 return iNum < jNum
61 }
62
63 // Fall back to string comparison
64 iVal := fmt.Sprintf("%v", iRaw)
65 jVal := fmt.Sprintf("%v", jRaw)
66
67 if order == "desc" {
68 return iVal > jVal
69 }
70 return iVal < jVal
71 })
72
73 execCtx.Log("sort", "info", fmt.Sprintf("Sorted %d items by %s (%s)", len(sorted), field, order))
74
75 return sorted, nil
76}
77
78func (n *SortNode) ValidateConfig(config map[string]interface{}) error {
79 return nil
80}
81
82func (n *SortNode) GetConfigSchema() *nodes.ConfigSchema {
83 return &nodes.ConfigSchema{
84 Fields: []nodes.ConfigField{
85 {
86 Name: "field",
87 Label: "Field Path",
88 Type: "text",
89 Required: true,
90 Placeholder: "published_at",
91 HelpText: "Field to sort by (use published_at or updated_at for date sorting)",
92 },
93 {
94 Name: "order",
95 Label: "Order",
96 Type: "select",
97 Required: false,
98 DefaultValue: "desc",
99 HelpText: "Descending = newest first (for dates), Ascending = oldest first",
100 Options: []nodes.FieldOption{
101 {Value: "desc", Label: "Descending (newest first)"},
102 {Value: "asc", Label: "Ascending (oldest first)"},
103 },
104 },
105 },
106 }
107}