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

Remove duplicate code and add support for key name matches in dynamic selectors

This commit is contained in:
Tom Wright
2021-08-08 22:48:54 +01:00
parent 676c143fe9
commit b3e0bfefde
4 changed files with 132 additions and 126 deletions

View File

@@ -119,12 +119,21 @@ func findNextAvailableIndex(n *Node, createIfNotExists bool) (reflect.Value, err
}
// processFindDynamicItem is used by findValueDynamic.
func processFindDynamicItem(n *Node, object reflect.Value) (bool, error) {
func processFindDynamicItem(n *Node, object reflect.Value, key string) (bool, error) {
// Loop through each condition.
allConditionsMatched := true
for _, c := range n.Selector.Conditions {
// If the object doesn't match any checks, return a ValueNotFound.
found, err := c.Check(object)
var found bool
var err error
switch cond := c.(type) {
case *KeyEqualCondition:
found, err = cond.Check(reflect.ValueOf(key))
default:
found, err = cond.Check(object)
}
if err != nil {
return false, err
}
@@ -152,7 +161,7 @@ func findValueDynamic(n *Node, createIfNotExists bool) (reflect.Value, error) {
case reflect.Slice:
for i := 0; i < value.Len(); i++ {
object := value.Index(i)
found, err := processFindDynamicItem(n, object)
found, err := processFindDynamicItem(n, object, fmt.Sprint(i))
if err != nil {
return nilValue(), err
}
@@ -171,7 +180,7 @@ func findValueDynamic(n *Node, createIfNotExists bool) (reflect.Value, error) {
case reflect.Map:
for _, key := range value.MapKeys() {
object := value.MapIndex(key)
found, err := processFindDynamicItem(n, object)
found, err := processFindDynamicItem(n, object, key.String())
if err != nil {
return nilValue(), err
}

View File

@@ -182,12 +182,21 @@ func findNextAvailableIndexNodes(selector Selector, previousValue reflect.Value,
}
// processFindDynamicItems is used by findNodesDynamic.
func processFindDynamicItems(selector Selector, object reflect.Value) (bool, error) {
func processFindDynamicItems(selector Selector, object reflect.Value, key string) (bool, error) {
// Loop through each condition.
allConditionsMatched := true
for _, c := range selector.Conditions {
// If the object doesn't match any checks, return a ValueNotFound.
found, err := c.Check(object)
var found bool
var err error
switch cond := c.(type) {
case *KeyEqualCondition:
found, err = cond.Check(reflect.ValueOf(key))
default:
found, err = cond.Check(object)
}
if err != nil {
return false, err
}
@@ -215,7 +224,7 @@ func findNodesDynamic(selector Selector, previousValue reflect.Value, createIfNo
results := make([]*Node, 0)
for i := 0; i < value.Len(); i++ {
object := value.Index(i)
found, err := processFindDynamicItems(selector, object)
found, err := processFindDynamicItems(selector, object, fmt.Sprint(i))
if err != nil {
return nil, err
}
@@ -246,7 +255,7 @@ func findNodesDynamic(selector Selector, previousValue reflect.Value, createIfNo
results := make([]*Node, 0)
for _, key := range value.MapKeys() {
object := value.MapIndex(key)
found, err := processFindDynamicItems(selector, object)
found, err := processFindDynamicItems(selector, object, key.String())
if err != nil {
return nil, err
}

View File

@@ -269,6 +269,29 @@ func TestParseSelector(t *testing.T) {
},
},
}))
t.Run("DynamicKey", testParseSelector(".(-=asd)", dasel.Selector{
Raw: ".(-=asd)",
Current: ".(-=asd)",
Remaining: "",
Type: "DYNAMIC",
Conditions: []dasel.Condition{
&dasel.KeyEqualCondition{
Value: "asd",
},
},
}))
t.Run("DynamicKeyNotEqual", testParseSelector(".(-!=asd)", dasel.Selector{
Raw: ".(-!=asd)",
Current: ".(-!=asd)",
Remaining: "",
Type: "DYNAMIC",
Conditions: []dasel.Condition{
&dasel.KeyEqualCondition{
Value: "asd",
Not: true,
},
},
}))
t.Run("DynamicEqual", testParseSelector(".(name=asd)", dasel.Selector{
Raw: ".(name=asd)",
Current: ".(name=asd)",
@@ -418,12 +441,18 @@ func TestNode_QueryMultiple(t *testing.T) {
t.Run("SingleResult", testNodeQueryMultipleArray(".[0].name", []interface{}{
"Tom",
}))
t.Run("SingleResultDynamic", testNodeQueryMultipleArray(".(age=25).name", []interface{}{
t.Run("SingleResultDynamicEqual", testNodeQueryMultipleArray(".(age=25).name", []interface{}{
"Amelia",
}))
t.Run("SingleResultDynamic", testNodeQueryMultipleArray(".(age!=27).name", []interface{}{
t.Run("SingleResultDynamicNotEqual", testNodeQueryMultipleArray(".(age!=27).name", []interface{}{
"Amelia",
}))
t.Run("SingleResultDynamicKeyEqual", testNodeQueryMultipleArray(".(-=0).name", []interface{}{
"Tom",
}))
t.Run("MultipleResultDynamicKeyNotEqual", testNodeQueryMultipleArray(".(-!=0).name", []interface{}{
"Jim", "Amelia",
}))
t.Run("MultipleResultSearchKeyNotEqual", testNodeQueryMultipleArray(".[*].(?:-!=name)", []interface{}{
"27", "27", "25",
}))

View File

@@ -46,6 +46,66 @@ func ParseSelector(selector string) (Selector, error) {
return sel, err
}
func getCondition(parts DynamicSelectorParts) (Condition, error) {
switch parts.Key {
case "-", "keyValue":
switch parts.Comparison {
case "=":
return &KeyEqualCondition{
Value: parts.Value,
}, nil
case "!=":
return &KeyEqualCondition{
Value: parts.Value,
Not: true,
}, nil
default:
return nil, &UnknownComparisonOperatorErr{Operator: parts.Comparison}
}
default:
switch parts.Comparison {
case "=":
return &EqualCondition{
Key: parts.Key,
Value: parts.Value,
}, nil
case "!=":
return &EqualCondition{
Key: parts.Key,
Value: parts.Value,
Not: true,
}, nil
case ">=":
return &SortedComparisonCondition{
Key: parts.Key,
Value: parts.Value,
Equal: true,
After: true,
}, nil
case ">":
return &SortedComparisonCondition{
Key: parts.Key,
Value: parts.Value,
After: true,
}, nil
case "<=":
return &SortedComparisonCondition{
Key: parts.Key,
Value: parts.Value,
Equal: true,
}, nil
case "<":
return &SortedComparisonCondition{
Key: parts.Key,
Value: parts.Value,
}, nil
default:
return nil, &UnknownComparisonOperatorErr{Operator: parts.Comparison}
}
}
}
func processParseSelectorDynamic(selector string, sel Selector) (Selector, error) {
sel.Type = "DYNAMIC"
dynamicGroups, err := DynamicSelectorToGroups(selector)
@@ -54,61 +114,14 @@ func processParseSelectorDynamic(selector string, sel Selector) (Selector, error
}
for _, g := range dynamicGroups {
// evaluable, err := gvalInstance.NewEvaluable(g)
// if err != nil {
// return sel, fmt.Errorf("could not parse dynamic expression: %w", err)
// }
//
// todo : how do we execute sub queries?
// sel.Conditions = append(sel.Conditions, &GvalCondition{
// Evaluable: evaluable,
// })
m := FindDynamicSelectorParts(g)
var cond Condition
switch m.Comparison {
case "=":
cond = &EqualCondition{
Key: m.Key,
Value: m.Value,
}
case "!=":
cond = &EqualCondition{
Key: m.Key,
Value: m.Value,
Not: true,
}
case ">=":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
Equal: true,
After: true,
}
case ">":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
After: true,
}
case "<=":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
Equal: true,
}
case "<":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
}
default:
return sel, &UnknownComparisonOperatorErr{Operator: m.Comparison}
parts := FindDynamicSelectorParts(g)
cond, err := getCondition(parts)
if err != nil {
return sel, err
}
if cond != nil {
sel.Conditions = append(sel.Conditions, cond)
}
sel.Conditions = append(sel.Conditions, cond)
}
return sel, nil
@@ -126,69 +139,15 @@ func processParseSelectorSearch(selector string, sel Selector) (Selector, error)
}
for _, g := range dynamicGroups {
m := FindDynamicSelectorParts(g)
m.Key = strings.TrimPrefix(m.Key, "?:")
var cond Condition
switch m.Key {
case "-", "keyValue":
switch m.Comparison {
case "=":
cond = &KeyEqualCondition{
Value: m.Value,
}
case "!=":
cond = &KeyEqualCondition{
Value: m.Value,
Not: true,
}
default:
return sel, &UnknownComparisonOperatorErr{Operator: m.Comparison}
}
default:
switch m.Comparison {
case "=":
cond = &EqualCondition{
Key: m.Key,
Value: m.Value,
}
case "!=":
cond = &EqualCondition{
Key: m.Key,
Value: m.Value,
Not: true,
}
case ">=":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
Equal: true,
After: true,
}
case ">":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
After: true,
}
case "<=":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
Equal: true,
}
case "<":
cond = &SortedComparisonCondition{
Key: m.Key,
Value: m.Value,
}
default:
return sel, &UnknownComparisonOperatorErr{Operator: m.Comparison}
}
parts := FindDynamicSelectorParts(g)
parts.Key = strings.TrimPrefix(parts.Key, "?:")
cond, err := getCondition(parts)
if err != nil {
return sel, err
}
if cond != nil {
sel.Conditions = append(sel.Conditions, cond)
}
sel.Conditions = append(sel.Conditions, cond)
}
return sel, nil