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  }