github.com/CiscoM31/godata@v1.0.10/filter_parser.go (about) 1 package godata 2 3 import "context" 4 5 var GlobalFilterTokenizer *Tokenizer 6 var GlobalFilterParser *ExpressionParser 7 8 // ParseFilterString converts an input string from the $filter part of the URL into a parse 9 // tree that can be used by providers to create a response. 10 func ParseFilterString(ctx context.Context, filter string) (*GoDataFilterQuery, error) { 11 tokens, err := GlobalFilterTokenizer.Tokenize(ctx, filter) 12 if err != nil { 13 return nil, err 14 } 15 // TODO: can we do this in one fell swoop? 16 postfix, err := GlobalFilterParser.InfixToPostfix(ctx, tokens) 17 if err != nil { 18 return nil, err 19 } 20 tree, err := GlobalFilterParser.PostfixToTree(ctx, postfix) 21 if err != nil { 22 return nil, err 23 } 24 if tree == nil || tree.Token == nil || 25 (len(tree.Children) == 0 && tree.Token.Type != ExpressionTokenBoolean) { 26 return nil, BadRequestError("Value must be a boolean expression") 27 } 28 return &GoDataFilterQuery{tree, filter}, nil 29 } 30 31 func SemanticizeFilterQuery( 32 filter *GoDataFilterQuery, 33 service *GoDataService, 34 entity *GoDataEntityType, 35 ) error { 36 37 if filter == nil || filter.Tree == nil { 38 return nil 39 } 40 41 var semanticizeFilterNode func(node *ParseNode) error 42 semanticizeFilterNode = func(node *ParseNode) error { 43 44 if node.Token.Type == ExpressionTokenLiteral { 45 prop, ok := service.PropertyLookup[entity][node.Token.Value] 46 if !ok { 47 return BadRequestError("No property found " + node.Token.Value + " on entity " + entity.Name) 48 } 49 node.Token.SemanticType = SemanticTypeProperty 50 node.Token.SemanticReference = prop 51 } else { 52 node.Token.SemanticType = SemanticTypePropertyValue 53 node.Token.SemanticReference = &node.Token.Value 54 } 55 56 for _, child := range node.Children { 57 err := semanticizeFilterNode(child) 58 if err != nil { 59 return err 60 } 61 } 62 63 return nil 64 } 65 66 return semanticizeFilterNode(filter.Tree) 67 }