1
0
mirror of https://github.com/TomWright/dasel.git synced 2022-05-22 02:32:45 +03:00

Add type selector

This commit is contained in:
Tom Wright
2021-11-03 17:30:40 +00:00
parent 67b89e9e0c
commit 0d4692801c
9 changed files with 269 additions and 105 deletions

View File

@@ -36,21 +36,22 @@ func (c EqualCondition) Check(other reflect.Value) (bool, error) {
return c.check(value.Interface(), c.Value)
}
switch value.Kind() {
case reflect.Map, reflect.Slice:
fmt.Println("here456")
subRootNode := New(value.Interface())
foundNode, err := subRootNode.Query(c.Key)
fmt.Println("789", err)
if err != nil {
fmt.Println("here123")
var valueNotFound = &ValueNotFound{}
if errors.As(err, &valueNotFound) {
return false, nil
}
var unsupportedType = &UnsupportedTypeForSelector{}
if errors.As(err, &unsupportedType) {
return false, nil
}
return false, fmt.Errorf("subquery failed: %w", err)
}
return c.check(foundNode.InterfaceValue(), c.Value)
}
return false, &UnhandledCheckType{Value: value.String()}
}

View File

@@ -31,8 +31,6 @@ func (c SortedComparisonCondition) Check(other reflect.Value) (bool, error) {
return fmt.Sprint(value.Interface()) == c.Value, nil
}
switch value.Kind() {
case reflect.Map, reflect.Slice:
subRootNode := New(value.Interface())
foundNode, err := subRootNode.Query(c.Key)
if err != nil {
@@ -62,6 +60,3 @@ func (c SortedComparisonCondition) Check(other reflect.Value) (bool, error) {
return false, nil
}
return false, &UnhandledCheckType{Value: value.String()}
}

View File

@@ -67,11 +67,6 @@ func TestEqualCondition_Check(t *testing.T) {
nil,
false, &dasel.UnhandledCheckType{Value: nil},
))
t.Run("String", conditionTest(
c,
"",
false, &dasel.UnhandledCheckType{Value: ""},
))
}
func TestSortedComparisonCondition_Check(t *testing.T) {
@@ -163,11 +158,6 @@ func TestSortedComparisonCondition_Check(t *testing.T) {
nil,
false, &dasel.UnhandledCheckType{Value: nil},
))
t.Run("String", conditionTest(
&dasel.SortedComparisonCondition{Key: "x", Value: "4"},
"",
false, &dasel.UnhandledCheckType{Value: ""},
))
}
func TestKeyEqualCondition_Check(t *testing.T) {

View File

@@ -493,6 +493,44 @@ func TestRootCmd_Select_JSON(t *testing.T) {
}
`, nil, "--escape-html=false"))
t.Run("MixedDynamicSelectors", selectTest(`{
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/gitlab",
[
"@semantic-release/git",
{
"assets": [
"tbump.toml",
"**/pyproject.toml",
"**/setup.py",
"README.md"
],
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
}
],
[
"@semantic-release/git",
{
"assets": [
"y"
],
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
}
]
]
}`, "json", `.plugins.([@]=array).([@]=map).assets`, `[
"tbump.toml",
"**/pyproject.toml",
"**/setup.py",
"README.md"
]
[
"y"
]
`, nil, "-m"))
}
func TestRootCmd_Select_YAML(t *testing.T) {

View File

@@ -218,6 +218,37 @@ func findValueLength(n *Node, createIfNotExists bool) (reflect.Value, error) {
return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value}
}
// findValueType returns the type of the current node.
func findValueType(n *Node, createIfNotExists bool) (reflect.Value, error) {
if !isValid(n.Previous.Value) {
return nilValue(), &UnexpectedPreviousNilValue{Selector: n.Previous.Selector.Current}
}
value := unwrapValue(n.Previous.Value)
switch value.Kind() {
case reflect.Slice:
return reflect.ValueOf("array"), nil
case reflect.Map:
return reflect.ValueOf("map"), nil
case reflect.String:
return reflect.ValueOf("string"), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return reflect.ValueOf("int"), nil
case reflect.Float32, reflect.Float64:
return reflect.ValueOf("float"), nil
case reflect.Bool:
return reflect.ValueOf("bool"), nil
}
return nilValue(), &UnsupportedTypeForSelector{Selector: n.Selector, Value: value}
}
// findValue finds the value for the given node.
// The value is essentially pulled from the previous node, using the (already parsed) selector
// information stored on the current node.
@@ -242,6 +273,8 @@ func findValue(n *Node, createIfNotExists bool) (reflect.Value, error) {
return findValueDynamic(n, createIfNotExists)
case "LENGTH":
return findValueLength(n, createIfNotExists)
case "TYPE":
return findValueType(n, createIfNotExists)
default:
return nilValue(), &UnsupportedSelector{Selector: n.Selector.Raw}
}

View File

@@ -145,32 +145,6 @@ func TestFindValueDynamic(t *testing.T) {
return
}
})
t.Run("UnsupportedCheckType", func(t *testing.T) {
itemVal := 1
val := []interface{}{
itemVal,
}
n := getNodeWithValue(val)
n.Selector.Current = "(name=x)"
n.Selector.Conditions = []Condition{
&EqualCondition{Key: "name", Value: "x"},
}
got, err := findValueDynamic(n, false)
assertQueryResult(t, nilValue(), &UnhandledCheckType{Value: reflect.TypeOf(itemVal).Kind().String()}, got, err)
})
t.Run("UnsupportedCheckTypeMap", func(t *testing.T) {
itemVal := 1
val := map[string]interface{}{
"x": itemVal,
}
n := getNodeWithValue(val)
n.Selector.Current = "(name=x)"
n.Selector.Conditions = []Condition{
&EqualCondition{Key: "name", Value: "x"},
}
got, err := findValueDynamic(n, false)
assertQueryResult(t, nilValue(), &UnhandledCheckType{Value: reflect.TypeOf(itemVal).Kind().String()}, got, err)
})
t.Run("UnsupportedType", func(t *testing.T) {
val := 0
n := getNodeWithValue(val)
@@ -227,6 +201,57 @@ func TestFindValueLength(t *testing.T) {
})
}
func TestFindValueType(t *testing.T) {
t.Run("NilValue", func(t *testing.T) {
n := getNodeWithValue(nil)
n.Previous.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, nilValue(), &UnexpectedPreviousNilValue{Selector: ".[#]"}, got, err)
})
t.Run("Int", func(t *testing.T) {
val := 0
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("int"), nil, got, err)
})
t.Run("Float", func(t *testing.T) {
val := 1.1
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("float"), nil, got, err)
})
t.Run("Bool", func(t *testing.T) {
val := true
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("bool"), nil, got, err)
})
t.Run("String", func(t *testing.T) {
val := "x"
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("string"), nil, got, err)
})
t.Run("Map", func(t *testing.T) {
val := map[string]interface{}{"x": 1}
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("map"), nil, got, err)
})
t.Run("Array", func(t *testing.T) {
val := []interface{}{1}
n := getNodeWithValue(val)
n.Selector.Current = ".[#]"
got, err := findValueType(n, false)
assertQueryResult(t, reflect.ValueOf("array"), nil, got, err)
})
}
func TestFindValue(t *testing.T) {
t.Run("MissingPreviousNode", func(t *testing.T) {
n := New(nil)

View File

@@ -459,6 +459,61 @@ func findNodesLength(selector Selector, previousValue reflect.Value) ([]*Node, e
return nil, &UnsupportedTypeForSelector{Selector: selector, Value: value}
}
// findNodesType returns the length
func findNodesType(selector Selector, previousValue reflect.Value) ([]*Node, error) {
if !isValid(previousValue) {
return nil, &UnexpectedPreviousNilValue{Selector: selector.Raw}
}
value := unwrapValue(previousValue)
switch value.Kind() {
case reflect.Slice:
node := &Node{
Value: reflect.ValueOf("array"),
Selector: selector,
}
return []*Node{node}, nil
case reflect.Map:
node := &Node{
Value: reflect.ValueOf("map"),
Selector: selector,
}
return []*Node{node}, nil
case reflect.String:
node := &Node{
Value: reflect.ValueOf("string"),
Selector: selector,
}
return []*Node{node}, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
node := &Node{
Value: reflect.ValueOf("int"),
Selector: selector,
}
return []*Node{node}, nil
case reflect.Float32, reflect.Float64:
node := &Node{
Value: reflect.ValueOf("float"),
Selector: selector,
}
return []*Node{node}, nil
case reflect.Bool:
node := &Node{
Value: reflect.ValueOf("bool"),
Selector: selector,
}
return []*Node{node}, nil
}
return nil, &UnsupportedTypeForSelector{Selector: selector, Value: value}
}
func initialiseEmptyValue(selector Selector, previousValue reflect.Value) reflect.Value {
switch selector.Type {
case "PROPERTY":
@@ -489,6 +544,8 @@ func findNodes(selector Selector, previousNode *Node, createIfNotExists bool) ([
res, err = findNodesAnyIndex(selector, previousNode.Value)
case "LENGTH":
res, err = findNodesLength(selector, previousNode.Value)
case "TYPE":
res, err = findNodesType(selector, previousNode.Value)
case "DYNAMIC":
res, err = findNodesDynamic(selector, previousNode.Value, createIfNotExists)
case "SEARCH":

View File

@@ -131,6 +131,50 @@ func TestFindNodesLength(t *testing.T) {
})
}
func TestFindNodesType(t *testing.T) {
t.Run("NilValue", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
got, err := findNodesType(selector, nilValue())
assertQueryMultipleResult(t, []reflect.Value{}, &UnexpectedPreviousNilValue{Selector: ".[#]"}, got, err)
})
t.Run("Int", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := 0
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("int")}, nil, got, err)
})
t.Run("Float", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := 1.1
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("float")}, nil, got, err)
})
t.Run("Bool", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := true
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("bool")}, nil, got, err)
})
t.Run("String", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := "a"
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("string")}, nil, got, err)
})
t.Run("Map", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := map[string]interface{}{"x": 1}
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("map")}, nil, got, err)
})
t.Run("Array", func(t *testing.T) {
selector := Selector{Current: ".[#]", Raw: ".[#]"}
val := []interface{}{"x"}
got, err := findNodesType(selector, reflect.ValueOf(val))
assertQueryMultipleResult(t, []reflect.Value{reflect.ValueOf("array")}, nil, got, err)
})
}
func TestFindNodesPropertyKeys(t *testing.T) {
t.Run("NilValue", func(t *testing.T) {
selector := Selector{Current: ".", Raw: "."}
@@ -279,32 +323,6 @@ func TestFindNodesDynamic(t *testing.T) {
return
}
})
t.Run("UnsupportedCheckType", func(t *testing.T) {
previousValue := reflect.ValueOf([]interface{}{
1,
})
selector := Selector{
Current: "(name=x)",
Conditions: []Condition{
&EqualCondition{Key: "name", Value: "x"},
},
}
got, err := findNodesDynamic(selector, previousValue, false)
assertQueryMultipleResult(t, []reflect.Value{}, &UnhandledCheckType{Value: previousValue.Kind().String()}, got, err)
})
t.Run("UnsupportedCheckTypeMap", func(t *testing.T) {
previousValue := reflect.ValueOf(map[string]interface{}{
"x": 1,
})
selector := Selector{
Current: "(name=x)",
Conditions: []Condition{
&EqualCondition{Key: "name", Value: "x"},
},
}
got, err := findNodesDynamic(selector, previousValue, false)
assertQueryMultipleResult(t, []reflect.Value{}, &UnhandledCheckType{Value: previousValue.Kind().String()}, got, err)
})
t.Run("UnsupportedType", func(t *testing.T) {
previousValue := reflect.ValueOf(0)
selector := Selector{

View File

@@ -37,6 +37,8 @@ func ParseSelector(selector string) (Selector, error) {
sel, err = processParseSelectorIndexAny(nextSel, sel)
case nextSel == "[#]":
sel, err = processParseSelectorLength(nextSel, sel)
case nextSel == "[@]":
sel, err = processParseSelectorType(nextSel, sel)
case strings.HasPrefix(nextSel, "[") && strings.HasSuffix(nextSel, "]"):
sel, err = processParseSelectorIndex(nextSel, sel)
default:
@@ -168,6 +170,11 @@ func processParseSelectorLength(selector string, sel Selector) (Selector, error)
return sel, nil
}
func processParseSelectorType(selector string, sel Selector) (Selector, error) {
sel.Type = "TYPE"
return sel, nil
}
func processParseSelectorIndex(selector string, sel Selector) (Selector, error) {
sel.Type = "INDEX"
indexStr := selector[1 : len(selector)-1]