Skip to content

Commit

Permalink
Merge pull request #7 from sonda2208/add-duration-literal
Browse files Browse the repository at this point in the history
Add duration literal
  • Loading branch information
sonda2208 authored Jun 13, 2019
2 parents fb4afd7 + aa219d1 commit 81e957c
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 0 deletions.
12 changes: 12 additions & 0 deletions ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ func (l *StringSliceLiteral) Type() string {
return "string slice"
}

type DurationLiteral struct {
Val time.Duration
}

func (l *DurationLiteral) String() string {
return l.Val.String()
}

func (l *DurationLiteral) Type() string {
return "duration"
}

type WalkFunc func(expr Expr, err error) error

func Walk(expr Expr, fn WalkFunc) error {
Expand Down
60 changes: 60 additions & 0 deletions evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ func computeEQ(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: (l.Val == dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val == v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down Expand Up @@ -175,6 +185,16 @@ func computeNEQ(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: (l.Val != dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val != v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down Expand Up @@ -207,6 +227,16 @@ func computeLT(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: l.Val.Before(dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val < v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down Expand Up @@ -239,6 +269,16 @@ func computeLTE(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: l.Val.Before(dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val <= v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down Expand Up @@ -271,6 +311,16 @@ func computeGT(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: l.Val.After(dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val > v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down Expand Up @@ -303,6 +353,16 @@ func computeGTE(lhs, rhs Expr) (*BoolLiteral, error) {

return &BoolLiteral{Val: l.Val.After(dt)}, nil
}
case *DurationLiteral:
rv, ok := rhs.(*StringLiteral)
if ok {
v, err := time.ParseDuration(rv.Val)
if err != nil {
return nil, err
}

return &BoolLiteral{Val: l.Val >= v}, nil
}
}

return nil, fmt.Errorf(`cannot convert "%s" to %s`, rhs.String(), lhs.Type())
Expand Down
130 changes: 130 additions & 0 deletions evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ func TestEvaluator(t *testing.T) {
dt, err := time.Parse(time.RFC3339, "2019-03-28T11:39:43+07:00")
require.NoError(t, err)

dur2m, err := time.ParseDuration("2m")
require.NoError(t, err)

dur1m30s, err := time.ParseDuration("1m30s")
require.NoError(t, err)

dur45s, err := time.ParseDuration("45s")
require.NoError(t, err)

tests := []TestCase{
{
`{ "comparator": "||", "rules": [ { "comparator": "&&", "rules": [ { "var": "a", "op": "==", "val": 1 }, { "var": "b", "op": "==", "val": 2 } ] }, { "comparator": "&&", "rules": [ { "var": "c", "op": "==", "val": 3 }, { "var": "d", "op": "==", "val": 4 } ] } ] }`,
Expand Down Expand Up @@ -342,6 +351,127 @@ func TestEvaluator(t *testing.T) {
},
},
},
{
`{ "var": "a", "op": "==", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur2m,
},
false,
false,
},
{
map[string]interface{}{
"a": dur1m30s,
},
true,
false,
},
{
map[string]interface{}{
"a": 1,
},
false,
true,
},
},
},
{
`{ "var": "a", "op": "!=", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur2m,
},
true,
false,
},
{
map[string]interface{}{
"a": dur1m30s,
},
false,
false,
},
},
},
{
`{ "var": "a", "op": ">", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur2m,
},
true,
false,
},
{
map[string]interface{}{
"a": dur1m30s,
},
false,
false,
},
},
},
{
`{ "var": "a", "op": ">=", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur2m,
},
true,
false,
},
{
map[string]interface{}{
"a": dur1m30s,
},
true,
false,
},
},
},
{
`{ "var": "a", "op": "<", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur45s,
},
true,
false,
},
{
map[string]interface{}{
"a": dur2m,
},
false,
false,
},
},
},
{
`{ "var": "a", "op": "<=", "val": "1m30s" }`,
[]Evaluation{
{
map[string]interface{}{
"a": dur1m30s,
},
true,
false,
},
{
map[string]interface{}{
"a": dur2m,
},
false,
false,
},
},
},
}

for _, test := range tests {
Expand Down
5 changes: 5 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ func toLiteral(i interface{}) (Expr, error) {
case reflect.Int32:
return &NumberLiteral{Val: float64(i.(int32))}, nil
case reflect.Int64:
dur, isDuration := i.(time.Duration)
if isDuration {
return &DurationLiteral{Val: dur}, nil
}

return &NumberLiteral{Val: float64(i.(int64))}, nil
case reflect.Float32:
return &NumberLiteral{Val: float64(i.(float32))}, nil
Expand Down

0 comments on commit 81e957c

Please sign in to comment.