Skip to content

Commit fb590a9

Browse files
authored
Merge pull request #8 from sidhant92/nested_key
Nested Field Support
2 parents 512a0ed + 6324782 commit fb590a9

File tree

6 files changed

+60
-24
lines changed

6 files changed

+60
-24
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Parentheses, `(` and `)`, can be used for grouping.
4747
#### Usage Notes
4848
* Phrases that includes quotes, like `content = "It's a wonderful day"`
4949
* Phrases that includes quotes, like `attribute = 'She said "Hello World"'`
50+
* For nested keys in data map you can use the dot notation, like `person.age`
5051

5152
## Usage
5253
```
@@ -127,7 +128,7 @@ res, err := evaluator.Evaluate("name = sid AND (age = 25 OR num = 44)", data)
127128
assert.Nil(t, err)
128129
assert.True(t, res)
129130
```
130-
App Version Comparison
131+
Semantic Version Comparison
131132
```
132133
data := map[string]interface{}{
133134
"app_version": "1.5.9",

internal/parser/antlr/antlr_parser_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ func TestStringList2(t *testing.T) {
254254
assert.Equal(t, res.(domain.InNode).Items[2].Value, "ab\"c")
255255
}
256256

257-
258257
func TestInvalidExpression(t *testing.T) {
259258
_, err := parser.Parse("a")
260259
assert.NotNil(t, err)

internal/util/value_utils.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,30 @@ package util
33
import (
44
"github.com/hashicorp/go-version"
55
"github.com/sidhant92/bool-parser-go/pkg/constant"
6+
"log"
67
"strconv"
78
"strings"
89
)
910

11+
func GetValueFromMap(key string, data map[string]interface{}) interface{} {
12+
keys := strings.Split(key, ".")
13+
size := len(keys)
14+
value, ok := data[keys[0]]
15+
if size == 1 {
16+
if ok {
17+
return value
18+
} else {
19+
return nil
20+
}
21+
}
22+
nestedMap, ok := value.(map[string]interface{})
23+
if ok {
24+
return GetValueFromMap(keys[1], nestedMap)
25+
}
26+
log.Printf("could not find key %s for the data %s", key, data)
27+
return nil
28+
}
29+
1030
func ConvertValue(value string, dataType constant.DataType) (interface{}, error) {
1131
switch dataType {
1232
case constant.INTEGER:

pkg/application/boolean_expression_evaluator.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package application
33
import (
44
"errors"
55
"github.com/sidhant92/bool-parser-go/internal/service"
6+
"github.com/sidhant92/bool-parser-go/internal/util"
67
"github.com/sidhant92/bool-parser-go/pkg/constant"
78
"github.com/sidhant92/bool-parser-go/pkg/domain"
89
errors2 "github.com/sidhant92/bool-parser-go/pkg/error"
910
"github.com/sidhant92/bool-parser-go/pkg/parser"
10-
"log"
1111
)
1212

1313
type BooleanExpressionEvaluator struct {
@@ -41,18 +41,18 @@ func (b *BooleanExpressionEvaluator) evaluateNode(node domain.Node, data map[str
4141
}
4242

4343
func (b *BooleanExpressionEvaluator) evaluateComparisonNode(node domain.ComparisonNode, data map[string]interface{}) (bool, error) {
44-
if b.checkFieldDataMissing(node.Field, data) {
45-
return false, nil
44+
fieldData := util.GetValueFromMap(node.Field, data)
45+
if fieldData == nil {
46+
return false, errors2.KEY_DATA_NOT_PRESENT
4647
}
47-
fieldData := data[node.Field]
4848
return b.OperatorService.Evaluate(node.Operator, node.DataType, fieldData, node.Value)
4949
}
5050

5151
func (b *BooleanExpressionEvaluator) evaluateNumericRangeNode(node domain.NumericRangeNode, data map[string]interface{}) (bool, error) {
52-
if b.checkFieldDataMissing(node.Field, data) {
53-
return false, nil
52+
fieldData := util.GetValueFromMap(node.Field, data)
53+
if fieldData == nil {
54+
return false, errors2.KEY_DATA_NOT_PRESENT
5455
}
55-
fieldData := data[node.Field]
5656
leftRes, err := b.OperatorService.Evaluate(constant.GREATER_THAN_EQUAL, node.FromDataType, fieldData, node.FromValue)
5757
if err != nil {
5858
return false, err
@@ -65,10 +65,10 @@ func (b *BooleanExpressionEvaluator) evaluateNumericRangeNode(node domain.Numeri
6565
}
6666

6767
func (b *BooleanExpressionEvaluator) evaluateInNode(node domain.InNode, data map[string]interface{}) (bool, error) {
68-
if b.checkFieldDataMissing(node.Field, data) {
69-
return false, nil
68+
fieldData := util.GetValueFromMap(node.Field, data)
69+
if fieldData == nil {
70+
return false, errors2.KEY_DATA_NOT_PRESENT
7071
}
71-
fieldData := data[node.Field]
7272
dataType := node.Items[0].DataType
7373
var values []interface{}
7474
for _, item := range node.Items {
@@ -85,10 +85,10 @@ func (b *BooleanExpressionEvaluator) evaluateUnaryNode(node domain.UnaryNode, da
8585
if node.DataType == constant.BOOLEAN {
8686
return node.Value.(bool), nil
8787
}
88-
if b.checkFieldDataMissing(node.Value.(string), data) {
89-
return false, nil
88+
fieldData := util.GetValueFromMap(node.Value.(string), data)
89+
if fieldData == nil {
90+
return false, errors2.KEY_DATA_NOT_PRESENT
9091
}
91-
fieldData := data[node.Value.(string)]
9292
val, ok := fieldData.(bool)
9393
if ok {
9494
return val, nil
@@ -127,14 +127,6 @@ func (b *BooleanExpressionEvaluator) evaluateBooleanNode(node domain.BooleanNode
127127
}
128128
}
129129

130-
func (b *BooleanExpressionEvaluator) checkFieldDataMissing(field string, data map[string]interface{}) bool {
131-
if _, ok := data[field]; ok {
132-
return false
133-
}
134-
log.Println("required field data is missing")
135-
return true
136-
}
137-
138130
func NewBooleanExpressionEvaluator(parser parser.Parser) BooleanExpressionEvaluator {
139131
return BooleanExpressionEvaluator{parser, service.NewOperatorService()}
140132
}

pkg/application/boolean_expression_evaluator_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,28 @@ func TestNumericGreaterThanCorrectExpression(t *testing.T) {
9999
assert.True(t, res)
100100
}
101101

102+
func TestNestedField(t *testing.T) {
103+
data := map[string]interface{}{
104+
"person": map[string]interface{}{
105+
"age": 24,
106+
},
107+
}
108+
res, err := evaluator.Evaluate("person.age > 20", data)
109+
assert.Nil(t, err)
110+
assert.True(t, res)
111+
}
112+
113+
func TestMissingNestedField(t *testing.T) {
114+
data := map[string]interface{}{
115+
"person": map[string]interface{}{
116+
"age": 24,
117+
},
118+
}
119+
res, err := evaluator.Evaluate("person.agee > 20", data)
120+
assert.ErrorIs(t, err, errors2.KEY_DATA_NOT_PRESENT)
121+
assert.False(t, res)
122+
}
123+
102124
func TestNumericGreaterThanIncorrectExpression(t *testing.T) {
103125
data := map[string]interface{}{
104126
"age": 26,
@@ -321,7 +343,7 @@ func TestKeyMissing(t *testing.T) {
321343
"agee": 34,
322344
}
323345
res, err := evaluator.Evaluate("age = 24", data)
324-
assert.Nil(t, err)
346+
assert.ErrorIs(t, err, errors2.KEY_DATA_NOT_PRESENT)
325347
assert.False(t, res)
326348
}
327349

pkg/error/errors.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ import "errors"
55
var INVALID_DATA_TYPE = errors.New("invalid data type")
66

77
var INVALID_UNARY_OPERAND = errors.New("invalid unary operand")
8+
9+
var KEY_DATA_NOT_PRESENT = errors.New("key data not present")

0 commit comments

Comments
 (0)