github.com/tomwright/dasel@v1.27.3/node_query.go (about) 1 package dasel 2 3 import ( 4 "fmt" 5 "reflect" 6 ) 7 8 // Query uses the given selector to query the current node and return the result. 9 func (n *Node) Query(selector string) (*Node, error) { 10 n.Selector.Remaining = selector 11 rootNode := n 12 13 if err := buildFindChain(rootNode); err != nil { 14 return nil, err 15 } 16 17 return lastNode(rootNode), nil 18 } 19 20 // lastNode returns the last node in the chain. 21 // If a node contains multiple next nodes, the first node is taken. 22 func lastNode(n *Node) *Node { 23 node := n 24 for { 25 if node.Next == nil { 26 return node 27 } 28 node = node.Next 29 } 30 } 31 32 func isFinalSelector(selector string) bool { 33 return selector == "" || selector == "." 34 } 35 36 func buildFindChain(n *Node) error { 37 if isFinalSelector(n.Selector.Remaining) { 38 // We've reached the end 39 return nil 40 } 41 42 var err error 43 nextNode := &Node{} 44 45 // Parse the selector. 46 nextNode.Selector, err = ParseSelector(n.Selector.Remaining) 47 if err != nil { 48 return fmt.Errorf("failed to parse selector: %w", err) 49 } 50 51 // Link the nodes. 52 n.Next = nextNode 53 nextNode.Previous = n 54 55 // Populate the value for the new node. 56 nextNode.Value, err = findValue(nextNode, false) 57 if err != nil { 58 return fmt.Errorf("could not find value: %w", err) 59 } 60 61 return buildFindChain(nextNode) 62 } 63 64 func findValuePropertyWork(n *Node, createIfNotExists bool, value reflect.Value) (reflect.Value, error) { 65 switch value.Kind() { 66 case reflect.Map: 67 for _, key := range value.MapKeys() { 68 if fmt.Sprint(key.Interface()) == n.Selector.Property { 69 return value.MapIndex(key), nil 70 } 71 } 72 if createIfNotExists { 73 return nilValue(), nil 74 } 75 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 76 77 case reflect.Struct: 78 fieldV := value.FieldByName(n.Selector.Property) 79 if fieldV.IsValid() { 80 return fieldV, nil 81 } 82 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 83 84 case reflect.Ptr: 85 return findValuePropertyWork(n, createIfNotExists, derefValue(value)) 86 } 87 88 return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value} 89 } 90 91 // findValueProperty finds the value for the given node using the property selector 92 // information. 93 func findValueProperty(n *Node, createIfNotExists bool) (reflect.Value, error) { 94 if !isValid(n.Previous.Value) { 95 return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current} 96 } 97 return findValuePropertyWork(n, createIfNotExists, unwrapValue(n.Previous.Value)) 98 } 99 100 // findValueIndex finds the value for the given node using the index selector 101 // information. 102 func findValueIndex(n *Node, createIfNotExists bool) (reflect.Value, error) { 103 if !isValid(n.Previous.Value) { 104 return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current} 105 } 106 107 value := unwrapValue(n.Previous.Value) 108 109 if value.Kind() == reflect.Slice { 110 valueLen := value.Len() 111 if n.Selector.Index >= 0 && n.Selector.Index < valueLen { 112 return value.Index(n.Selector.Index), nil 113 } 114 if createIfNotExists { 115 return nilValue(), nil 116 } 117 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 118 } 119 120 return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value} 121 } 122 123 // findNextAvailableIndex finds the value for the given node using the index selector 124 // information. 125 func findNextAvailableIndex(n *Node, createIfNotExists bool) (reflect.Value, error) { 126 if !createIfNotExists { 127 // Next available index isn't supported unless it's creating the item. 128 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 129 } 130 return nilValue(), nil 131 } 132 133 // processFindDynamicItem is used by findValueDynamic. 134 func processFindDynamicItem(n *Node, object reflect.Value, key string) (bool, error) { 135 // Loop through each condition. 136 allConditionsMatched := true 137 for _, c := range n.Selector.Conditions { 138 // If the object doesn't match any checks, return a ValueNotFound. 139 140 var found bool 141 var err error 142 switch cond := c.(type) { 143 case *KeyEqualCondition: 144 found, err = cond.Check(reflect.ValueOf(key)) 145 default: 146 found, err = cond.Check(object) 147 } 148 149 if err != nil { 150 return false, err 151 } 152 if !found { 153 allConditionsMatched = false 154 break 155 } 156 } 157 if allConditionsMatched { 158 return true, nil 159 } 160 return false, nil 161 } 162 163 // findValueDynamic finds the value for the given node using the dynamic selector 164 // information. 165 func findValueDynamic(n *Node, createIfNotExists bool) (reflect.Value, error) { 166 if !isValid(n.Previous.Value) { 167 return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current} 168 } 169 170 value := unwrapValue(n.Previous.Value) 171 172 switch value.Kind() { 173 case reflect.Slice: 174 for i := 0; i < value.Len(); i++ { 175 object := value.Index(i) 176 found, err := processFindDynamicItem(n, object, fmt.Sprint(i)) 177 if err != nil { 178 return nilValue(), err 179 } 180 if found { 181 n.Selector.Type = "INDEX" 182 n.Selector.Index = i 183 return object, nil 184 } 185 } 186 if createIfNotExists { 187 n.Selector.Type = "NEXT_AVAILABLE_INDEX" 188 return nilValue(), nil 189 } 190 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 191 192 case reflect.Map: 193 for _, key := range value.MapKeys() { 194 object := value.MapIndex(key) 195 found, err := processFindDynamicItem(n, object, key.String()) 196 if err != nil { 197 return nilValue(), err 198 } 199 if found { 200 n.Selector.Type = "PROPERTY" 201 n.Selector.Property = key.String() 202 return object, nil 203 } 204 } 205 return nilValue(), &ValueNotFound{Selector: n.Selector.Current, PreviousValue: n.Previous.Value} 206 } 207 208 return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value} 209 } 210 211 func findValueLengthWork(n *Node, value reflect.Value) (reflect.Value, error) { 212 switch value.Kind() { 213 case reflect.Slice: 214 return reflect.ValueOf(value.Len()), nil 215 216 case reflect.Map: 217 return reflect.ValueOf(value.Len()), nil 218 219 case reflect.String: 220 return reflect.ValueOf(value.Len()), nil 221 222 case reflect.Struct: 223 return reflect.ValueOf(value.NumField()), nil 224 225 case reflect.Ptr: 226 return findValueLengthWork(n, derefValue(value)) 227 } 228 229 return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value} 230 } 231 232 // findValueLength returns the length of the current node. 233 func findValueLength(n *Node, createIfNotExists bool) (reflect.Value, error) { 234 if !isValid(n.Previous.Value) { 235 return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current} 236 } 237 return findValueLengthWork(n, unwrapValue(n.Previous.Value)) 238 } 239 240 func findValueTypeWork(n *Node, value reflect.Value) (reflect.Value, error) { 241 switch value.Kind() { 242 case reflect.Slice: 243 return reflect.ValueOf("array"), nil 244 245 case reflect.Map: 246 return reflect.ValueOf("map"), nil 247 248 case reflect.String: 249 return reflect.ValueOf("string"), nil 250 251 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 252 return reflect.ValueOf("int"), nil 253 254 case reflect.Float32, reflect.Float64: 255 return reflect.ValueOf("float"), nil 256 257 case reflect.Bool: 258 return reflect.ValueOf("bool"), nil 259 260 case reflect.Struct: 261 return reflect.ValueOf("struct"), nil 262 263 case reflect.Ptr: 264 return findValueTypeWork(n, derefValue(value)) 265 } 266 267 return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value} 268 } 269 270 // findValueType returns the type of the current node. 271 func findValueType(n *Node, createIfNotExists bool) (reflect.Value, error) { 272 if !isValid(n.Previous.Value) { 273 return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current} 274 } 275 return findValueTypeWork(n, unwrapValue(n.Previous.Value)) 276 } 277 278 // findValue finds the value for the given node. 279 // The value is essentially pulled from the previous node, using the (already parsed) selector 280 // information stored on the current node. 281 func findValue(n *Node, createIfNotExists bool) (reflect.Value, error) { 282 if n.Previous == nil { 283 // previous node is required to get it's value. 284 return nilValue(), ErrMissingPreviousNode 285 } 286 287 if createIfNotExists && !isValid(n.Previous.Value) { 288 n.Previous.Value = initialiseEmptyValue(n.Selector, n.Previous.Value) 289 } 290 291 switch n.Selector.Type { 292 case "PROPERTY": 293 return findValueProperty(n, createIfNotExists) 294 case "INDEX": 295 return findValueIndex(n, createIfNotExists) 296 case "NEXT_AVAILABLE_INDEX": 297 return findNextAvailableIndex(n, createIfNotExists) 298 case "DYNAMIC": 299 return findValueDynamic(n, createIfNotExists) 300 case "LENGTH": 301 return findValueLength(n, createIfNotExists) 302 case "TYPE": 303 return findValueType(n, createIfNotExists) 304 default: 305 return nilValue(), &UnsupportedSelector{Selector: n.Selector.Raw} 306 } 307 }