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  }