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) return c.check(value.Interface(), c.Value)
} }
switch value.Kind() { fmt.Println("here456")
case reflect.Map, reflect.Slice: subRootNode := New(value.Interface())
subRootNode := New(value.Interface()) foundNode, err := subRootNode.Query(c.Key)
foundNode, err := subRootNode.Query(c.Key) fmt.Println("789", err)
if err != nil { if err != nil {
var valueNotFound = &ValueNotFound{} fmt.Println("here123")
if errors.As(err, &valueNotFound) { var valueNotFound = &ValueNotFound{}
return false, nil if errors.As(err, &valueNotFound) {
} return false, nil
}
return false, fmt.Errorf("subquery failed: %w", err) var unsupportedType = &UnsupportedTypeForSelector{}
if errors.As(err, &unsupportedType) {
return false, nil
} }
return c.check(foundNode.InterfaceValue(), c.Value) return false, fmt.Errorf("subquery failed: %w", err)
} }
return c.check(foundNode.InterfaceValue(), c.Value)
return false, &UnhandledCheckType{Value: value.String()}
} }

View File

@@ -31,37 +31,32 @@ func (c SortedComparisonCondition) Check(other reflect.Value) (bool, error) {
return fmt.Sprint(value.Interface()) == c.Value, nil return fmt.Sprint(value.Interface()) == c.Value, nil
} }
switch value.Kind() { subRootNode := New(value.Interface())
case reflect.Map, reflect.Slice: foundNode, err := subRootNode.Query(c.Key)
subRootNode := New(value.Interface()) if err != nil {
foundNode, err := subRootNode.Query(c.Key) var valueNotFound = &ValueNotFound{}
if err != nil { if errors.As(err, &valueNotFound) {
var valueNotFound = &ValueNotFound{} return false, nil
if errors.As(err, &valueNotFound) {
return false, nil
}
return false, fmt.Errorf("subquery failed: %w", err)
} }
foundValueStr := fmt.Sprint(foundNode.InterfaceValue()) return false, fmt.Errorf("subquery failed: %w", err)
// Check if the values are equal
if foundValueStr == c.Value {
return c.Equal, nil
}
sortedVals := []string{foundValueStr, c.Value}
sort.Strings(sortedVals)
if !c.After && sortedVals[1] == c.Value {
return true, nil
} else if c.After && sortedVals[0] == c.Value {
return true, nil
}
return false, nil
} }
return false, &UnhandledCheckType{Value: value.String()} foundValueStr := fmt.Sprint(foundNode.InterfaceValue())
// Check if the values are equal
if foundValueStr == c.Value {
return c.Equal, nil
}
sortedVals := []string{foundValueStr, c.Value}
sort.Strings(sortedVals)
if !c.After && sortedVals[1] == c.Value {
return true, nil
} else if c.After && sortedVals[0] == c.Value {
return true, nil
}
return false, nil
} }

View File

@@ -67,11 +67,6 @@ func TestEqualCondition_Check(t *testing.T) {
nil, nil,
false, &dasel.UnhandledCheckType{Value: nil}, false, &dasel.UnhandledCheckType{Value: nil},
)) ))
t.Run("String", conditionTest(
c,
"",
false, &dasel.UnhandledCheckType{Value: ""},
))
} }
func TestSortedComparisonCondition_Check(t *testing.T) { func TestSortedComparisonCondition_Check(t *testing.T) {
@@ -163,11 +158,6 @@ func TestSortedComparisonCondition_Check(t *testing.T) {
nil, nil,
false, &dasel.UnhandledCheckType{Value: 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) { func TestKeyEqualCondition_Check(t *testing.T) {

View File

@@ -493,6 +493,44 @@ func TestRootCmd_Select_JSON(t *testing.T) {
} }
`, nil, "--escape-html=false")) `, 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) { 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} 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. // findValue finds the value for the given node.
// The value is essentially pulled from the previous node, using the (already parsed) selector // The value is essentially pulled from the previous node, using the (already parsed) selector
// information stored on the current node. // information stored on the current node.
@@ -242,6 +273,8 @@ func findValue(n *Node, createIfNotExists bool) (reflect.Value, error) {
return findValueDynamic(n, createIfNotExists) return findValueDynamic(n, createIfNotExists)
case "LENGTH": case "LENGTH":
return findValueLength(n, createIfNotExists) return findValueLength(n, createIfNotExists)
case "TYPE":
return findValueType(n, createIfNotExists)
default: default:
return nilValue(), &UnsupportedSelector{Selector: n.Selector.Raw} return nilValue(), &UnsupportedSelector{Selector: n.Selector.Raw}
} }

View File

@@ -145,32 +145,6 @@ func TestFindValueDynamic(t *testing.T) {
return 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) { t.Run("UnsupportedType", func(t *testing.T) {
val := 0 val := 0
n := getNodeWithValue(val) 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) { func TestFindValue(t *testing.T) {
t.Run("MissingPreviousNode", func(t *testing.T) { t.Run("MissingPreviousNode", func(t *testing.T) {
n := New(nil) 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} 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 { func initialiseEmptyValue(selector Selector, previousValue reflect.Value) reflect.Value {
switch selector.Type { switch selector.Type {
case "PROPERTY": case "PROPERTY":
@@ -489,6 +544,8 @@ func findNodes(selector Selector, previousNode *Node, createIfNotExists bool) ([
res, err = findNodesAnyIndex(selector, previousNode.Value) res, err = findNodesAnyIndex(selector, previousNode.Value)
case "LENGTH": case "LENGTH":
res, err = findNodesLength(selector, previousNode.Value) res, err = findNodesLength(selector, previousNode.Value)
case "TYPE":
res, err = findNodesType(selector, previousNode.Value)
case "DYNAMIC": case "DYNAMIC":
res, err = findNodesDynamic(selector, previousNode.Value, createIfNotExists) res, err = findNodesDynamic(selector, previousNode.Value, createIfNotExists)
case "SEARCH": 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) { func TestFindNodesPropertyKeys(t *testing.T) {
t.Run("NilValue", func(t *testing.T) { t.Run("NilValue", func(t *testing.T) {
selector := Selector{Current: ".", Raw: "."} selector := Selector{Current: ".", Raw: "."}
@@ -279,32 +323,6 @@ func TestFindNodesDynamic(t *testing.T) {
return 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) { t.Run("UnsupportedType", func(t *testing.T) {
previousValue := reflect.ValueOf(0) previousValue := reflect.ValueOf(0)
selector := Selector{ selector := Selector{

View File

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