Skip to content
This repository was archived by the owner on Jun 2, 2024. It is now read-only.

Commit

Permalink
#1 add test to filter expression mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
gessnerfl committed Apr 17, 2019
1 parent 5375a08 commit cff680e
Show file tree
Hide file tree
Showing 7 changed files with 485 additions and 99 deletions.
28 changes: 14 additions & 14 deletions instana/filterexpression/filter-expression-parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ func (c *Operator) Capture(values []string) error {
return nil
}

//Function Custom type for a function
type Function string
//UnaryOperator Custom type for a unary operations
type UnaryOperator string

//Capture captures the string representation of a function from the given slice of strings. Interface of participle
func (c *Function) Capture(values []string) error {
*c = Function(strings.ToUpper(strings.Join(values, " ")))
//Capture captures the string representation of a unary operation from the given slice of strings. Interface of participle
func (c *UnaryOperator) Capture(values []string) error {
*c = UnaryOperator(strings.ToUpper(strings.Join(values, " ")))
return nil
}

Expand Down Expand Up @@ -89,16 +89,16 @@ func (e *LogicalAndExpression) Render() string {

//PrimaryExpression wrapper for either a comparision or a unary expression
type PrimaryExpression struct {
Comparision *ComparisionExpression `parser:" @@"`
UnaryExpression *UnaryExpression `parser:"| @@"`
Comparision *ComparisionExpression `parser:" @@"`
UnaryOperation *UnaryOperationExpression `parser:"| @@"`
}

//Render implementation of ExpressionRenderer.Render
func (e *PrimaryExpression) Render() string {
if e.Comparision != nil {
return e.Comparision.Render()
}
return e.UnaryExpression.Render()
return e.UnaryOperation.Render()
}

//ComparisionExpression representation of a comparision expression. Supported types: EQ (Equals), NE (Not Equal), CO (Contains), NC (Not Contain)
Expand All @@ -113,15 +113,15 @@ func (e *ComparisionExpression) Render() string {
return fmt.Sprintf("%s %s '%s'", e.Key, e.Operator, e.Value)
}

//UnaryExpression representation of a unary expression representing a function
type UnaryExpression struct {
Key string `parser:"@Ident"`
Function Function `parser:"@( \"IS\" (\"EMPTY\" | \"BLANK\") | \"NOT\" (\"EMPTY\" | \"BLANK\") )"`
//UnaryOperationExpression representation of a unary expression representing a unary operator
type UnaryOperationExpression struct {
Key string `parser:"@Ident"`
Operator UnaryOperator `parser:"@( \"IS\" (\"EMPTY\" | \"BLANK\") | \"NOT\" (\"EMPTY\" | \"BLANK\") )"`
}

//Render implementation of ExpressionRenderer.Render
func (e *UnaryExpression) Render() string {
return fmt.Sprintf("%s %s", e.Key, e.Function)
func (e *UnaryOperationExpression) Render() string {
return fmt.Sprintf("%s %s", e.Key, e.Operator)
}

var (
Expand Down
14 changes: 7 additions & 7 deletions instana/filterexpression/filter-expression-parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ func TestShouldSuccessfullyParseComplexExpression(t *testing.T) {
Operator: &logicalAnd,
Right: &LogicalAndExpression{
Left: &PrimaryExpression{
UnaryExpression: &UnaryExpression{
UnaryOperation: &UnaryOperationExpression{
Key: "span.name",
Function: "NOT EMPTY",
Operator: "NOT EMPTY",
},
},
},
Expand Down Expand Up @@ -130,9 +130,9 @@ func TestShouldParseUnaryOperationsCaseInsensitive(t *testing.T) {
Expression: &LogicalOrExpression{
Left: &LogicalAndExpression{
Left: &PrimaryExpression{
UnaryExpression: &UnaryExpression{
UnaryOperation: &UnaryOperationExpression{
Key: "entity.name",
Function: "NOT EMPTY",
Operator: "NOT EMPTY",
},
},
},
Expand Down Expand Up @@ -309,13 +309,13 @@ func TestShouldRenderComparisionOnPrimaryExpressionWhenComparsionIsSet(t *testin
}
}

func TestShouldRenderUnaryExpressionOnPrimaryExpressionWhenUnaryExpressionIsSet(t *testing.T) {
func TestShouldRenderUnaryOperationExpressionOnPrimaryExpressionWhenUnaryOperationIsSet(t *testing.T) {
expectedResult := "foo IS EMPTY"

sut := PrimaryExpression{
UnaryExpression: &UnaryExpression{
UnaryOperation: &UnaryOperationExpression{
Key: "foo",
Function: "IS EMPTY",
Operator: "IS EMPTY",
},
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ var OperatorMappingInstanaAPIToFilterExpression = map[string]Operator{
"NOT_CONTAIN": Operator("NC"),
}

//FunctionMappingInstanaAPIToFilterExpression map defining the mapping of the function names of unary operations from instana API to the representation of the Filter Expression
var FunctionMappingInstanaAPIToFilterExpression = map[string]Function{
"IS_EMPTY": Function("IS EMPTY"),
"NOT_EMPTY": Function("NOT EMPTY"),
"IS_BLANK": Function("IS BLANK"),
"NOT_BLANK": Function("NOT BLANK"),
//UnaryOperatorMappingInstanaAPIToFilterExpression map defining the mapping of the unary operator names from instana API to the representation of the Filter Expression
var UnaryOperatorMappingInstanaAPIToFilterExpression = map[string]UnaryOperator{
"IS_EMPTY": UnaryOperator("IS EMPTY"),
"NOT_EMPTY": UnaryOperator("NOT EMPTY"),
"IS_BLANK": UnaryOperator("IS BLANK"),
"NOT_BLANK": UnaryOperator("NOT BLANK"),
}

//FromAPIModel Implementation of the mapping from the Instana API model to the filter expression model
Expand Down Expand Up @@ -84,56 +84,51 @@ func (m *mapperImpl) mapBinaryOperator(operator *restapi.BinaryOperator) (*expre

func (m *mapperImpl) mapLogicalOr(left *expressionHandle, right *expressionHandle) (*expressionHandle, error) {
if left.or != nil {
return nil, fmt.Errorf("invalid logical or expression: logical or is not allowed for the left side")
}

if left.and == nil && left.primary == nil {
return nil, errors.New("invalid logical or expression: left side of logical or is not defined")
}

if right.or == nil && right.and == nil && right.primary == nil {
return nil, errors.New("invalid logical or expression: right side of logical or is not defined")
return nil, fmt.Errorf("invalid logical or expression: logical or is not allowed for left side")
}

operator := Operator("OR")
orExpression := LogicalOrExpression{Operator: &operator}
return &expressionHandle{
or: &LogicalOrExpression{
Left: m.mapLeftOfLogicalOr(left),
Operator: &operator,
Right: m.mapRightOfLogicalOr(right),
},
}, nil
}

func (m *mapperImpl) mapLeftOfLogicalOr(left *expressionHandle) *LogicalAndExpression {
if left.and != nil {
orExpression.Left = left.and
} else {
orExpression.Left = &LogicalAndExpression{
Left: left.primary,
}
return left.and
}
return &LogicalAndExpression{
Left: left.primary,
}
}

func (m *mapperImpl) mapRightOfLogicalOr(right *expressionHandle) *LogicalOrExpression {
if right.or != nil {
orExpression.Right = right.or
return right.or
} else if right.and != nil {
orExpression.Right = &LogicalOrExpression{Left: left.and}
return &LogicalOrExpression{Left: right.and}
} else {
orExpression.Right = &LogicalOrExpression{Left: &LogicalAndExpression{Left: right.primary}}
return &LogicalOrExpression{Left: &LogicalAndExpression{Left: right.primary}}
}

return &expressionHandle{or: &orExpression}, nil
}

func (m *mapperImpl) mapLogicalAnd(left *expressionHandle, right *expressionHandle) (*expressionHandle, error) {
if left.or != nil {
return nil, fmt.Errorf("invalid logical and expression: logical or is not allowed for the left side")
return nil, fmt.Errorf("invalid logical and expression: logical or is not allowed for left side")
}

if right.or != nil {
return nil, fmt.Errorf("invalid logical and expression: logical or is not allowed for the right side")
return nil, fmt.Errorf("invalid logical and expression: logical or is not allowed for right side")
}

if left.and != nil {
return nil, fmt.Errorf("invalid logical and expression: logical and is not allowed for left side")
}

if left.primary == nil {
return nil, errors.New("invalid logical and expression: left side of logical and is not defined")
}

operator := Operator("AND")
if right.and != nil {
return &expressionHandle{
Expand All @@ -145,17 +140,13 @@ func (m *mapperImpl) mapLogicalAnd(left *expressionHandle, right *expressionHand
}, nil
}

if right.primary != nil {
return &expressionHandle{
and: &LogicalAndExpression{
Left: left.primary,
Operator: &operator,
Right: &LogicalAndExpression{Left: right.primary},
},
}, nil
}

return nil, errors.New("invalid logical and expression: right side of logical and is not defined")
return &expressionHandle{
and: &LogicalAndExpression{
Left: left.primary,
Operator: &operator,
Right: &LogicalAndExpression{Left: right.primary},
},
}, nil
}

func (m *mapperImpl) mapPrimaryExpression(matcher *restapi.TagMatcherExpression) (*PrimaryExpression, error) {
Expand All @@ -173,30 +164,30 @@ func (m *mapperImpl) mapPrimaryExpression(matcher *restapi.TagMatcherExpression)
}, nil
}

function, err := m.mapFunction(matcher.Operator)
unaryOperator, err := m.mapUnaryOperator(matcher.Operator)
if err != nil {
return nil, err
}
return &PrimaryExpression{
UnaryExpression: &UnaryExpression{
UnaryOperation: &UnaryOperationExpression{
Key: matcher.Key,
Function: function,
Operator: unaryOperator,
},
}, nil
}

func (m *mapperImpl) mapOperator(apiName string) (Operator, error) {
value := OperatorMappingInstanaAPIToFilterExpression[apiName]
if value == "" {
return value, fmt.Errorf("invalid operation: operation %s not supported", apiName)
return value, fmt.Errorf("invalid operation: operation '%s' not supported", apiName)
}
return value, nil
}

func (m *mapperImpl) mapFunction(apiName string) (Function, error) {
value := FunctionMappingInstanaAPIToFilterExpression[apiName]
func (m *mapperImpl) mapUnaryOperator(apiName string) (UnaryOperator, error) {
value := UnaryOperatorMappingInstanaAPIToFilterExpression[apiName]
if value == "" {
return value, fmt.Errorf("invalid operation: operation %s not supported", apiName)
return value, fmt.Errorf("invalid unary operation: unary operator '%s' not supported", apiName)
}
return value, nil
}
Expand Down
Loading

0 comments on commit cff680e

Please sign in to comment.