filtering

package
v0.0.0-...-c824f4b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2024 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package filtering provides a parser for the AIP-160 filtering language, that matches protocol buffer messages based on the protoreflection and blocky api annotations. Read more at https://google.aip.dev/160.

An Interpreter is used to parse a filter expression and return an implementation of the expr.Expr interface. This implementation supports custom function calls, that can be either direct or abstract call. An abstract call results in returning of expr.FunctionCall expression, that can be handled by the caller. A direct call works like a macro that converts input arguments to a concrete expression. This implementation supports extensions to the standard AIP-160 filtering language:

  • IN operator - checks if a value is in a list of values etc.
  • Struct value expression - allows to compose a proto.Message or a map field from a syntax like: pkg.MyType{field1: value1, field2: value2} or map{key1: value1, key2: value2}
  • Array value expression - allows to use repeated value expression like: [1, 2, 3]

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoHandlerFound is a standard error that is returned when no handler is found for an expression.
	ErrNoHandlerFound = errors.New("no handler found")

	// ErrInvalidField is a standard error that is returned when a field is invalid.
	ErrInvalidField = errors.New("invalid field")

	// ErrInvalidValue is a standard error that is returned when a value is invalid.
	ErrInvalidValue = errors.New("invalid value")

	// ErrFieldNotFound is a standard error that is returned when a field is not found.
	ErrFieldNotFound = errors.New("field not found")

	// ErrInvalidAST is an error that is returned when the AST is invalid.
	ErrInvalidAST = errors.New("invalid AST")

	// ErrInternal is an internal error done during interpretation.
	ErrInternal = errors.New("internal error")

	// ErrAmbiguousField is an error that is returned when a field is ambiguous.
	ErrAmbiguousField = errors.New("ambiguous field selector")
)

Functions

func IsFieldFilteringForbidden

func IsFieldFilteringForbidden(field protoreflect.FieldDescriptor) bool

IsFieldFilteringForbidden returns true if the field filtering is forbidden.

Types

type FieldDescriptor

type FieldDescriptor interface {
	// Kind returns the field kind.
	Kind() protoreflect.Kind

	// Message returns the message descriptor.
	// If the field is not a message, it returns nil.
	Message() protoreflect.MessageDescriptor

	// Enum returns the enum descriptor.
	// If the field is not an enum, it returns nil.
	Enum() protoreflect.EnumDescriptor

	// IsMap returns true if the field is a map.
	IsMap() bool

	// MapKey returns the map key field descriptor.
	// If the field is not a map, it returns nil.
	MapKey() protoreflect.FieldDescriptor

	// MapValue returns the map value field descriptor.
	// If the field is not a map, it returns nil.
	MapValue() protoreflect.FieldDescriptor

	// Cardinality returns the cardinality of the field.
	Cardinality() protoreflect.Cardinality
}

FieldDescriptor is an interface that describes a field. It can either be a protoreflect.FieldDescriptor or a function argument field descriptor.

type FunctionCallArgument

type FunctionCallArgument struct {
	// Expr is the expression of the argument.
	Expr expr.FilterExpr

	// IsIndirect specifies if the argument is indirect.
	// If the argument is indirect the value provided to the argument depends on value of the filtered message.
	// This means that the function call should result in an abstract expr.FunctionCall expression,
	// and does not result with a value expression.
	IsIndirect bool
}

FunctionCallArgument is an argument of the function call. It specifies the expression injected into the function, and shows information if the value depends on the resource message.

type FunctionCallArgumentDeclaration

type FunctionCallArgumentDeclaration struct {
	// Indirect is true if the argument might take a non value
	// indirect form of the filtered message field.
	// The function call with indirect argument returns
	// an expr.FunctionCall expression.
	Indirect bool

	// ArgName is the name of the field.
	ArgName string

	// IsRepeated is true if the argument is a repeated field.
	IsRepeated bool

	// IsNullable is true if the argument is a nullable field.
	IsNullable bool

	// AllowedServiceCallFuncs is a list of function names that can be used as indirect argument.
	// This is used to allow a function call to be used as an indirect argument.
	AllowedServiceCallFuncs []FunctionName

	// FieldKind is the kind of the argument.
	FieldKind protoreflect.Kind

	// EnumDescriptor is the enum descriptor of the argument.
	EnumDescriptor protoreflect.EnumDescriptor

	// If FieldKind is MessageKind, then this is the message descriptor.
	MessageDescriptor protoreflect.MessageDescriptor

	// MapKeyDesc is the map key descriptor of the value returned by the function call.
	// This must be set if the resulting value is a map.
	MapKeyDesc protoreflect.FieldDescriptor

	// MapValueDesc is the map value descriptor of the value returned by the function call.
	// This must be set if the resulting value is a map.
	MapValueDesc protoreflect.FieldDescriptor
}

FunctionCallArgumentDeclaration is a declaration of a function call argument.

func (*FunctionCallArgumentDeclaration) Cardinality

Cardinality returns the cardinality of the argument. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) Enum

Enum returns the enum descriptor of the argument. If returning value is not an enum, then it returns nil. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) IsMap

IsMap returns true if the argument is a map.

func (*FunctionCallArgumentDeclaration) Kind

Kind returns the kind of returing value. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) MapKey

MapKey returns the map key descriptor of the argument. Returns nil if the argument is not a map. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) MapValue

MapValue returns the map value descriptor of the argument. Returns nil if the argument is not a map. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) Message

Message returns the message descriptor of the argument. If returning value is not a message, then it returns nil. Implements FieldDescriptor interface.

func (*FunctionCallArgumentDeclaration) Name

Name returns the name of the argument.

func (*FunctionCallArgumentDeclaration) Validate

func (f *FunctionCallArgumentDeclaration) Validate() error

Validate validates the function call argument declaration.

type FunctionCallDeclaration

type FunctionCallDeclaration struct {
	// Name is a unique identifier of the function call.
	Name FunctionName

	// Arguments is a list of arguments of the function call.
	// If empty then the function call has no arguments.
	Arguments []*FunctionCallArgumentDeclaration

	// Returning is an optional returning declaration of the function call.
	// If this field is undefined, this function always returns an expr.FunctionCall expression.
	// This is then named as a service called function call.
	// It can be used for any purpose of the filter, but needs to be validated on the service side.
	// A function call declaration without a returning declaration cannot be used as an argument of another function call.
	Returning *FunctionCallReturningDeclaration

	// CallFn is the execution function of the function call.
	// It is called when the function call is executed.
	CallFn FunctionCallFn
	// Complexity is the complexity of the function call.
	Complexity int64
}

FunctionCallDeclaration is a declaration of a function call. It is used to register a function call handler. A function call may either return a value or an indirect value. If it returns an indirect value, then it returns an expr.FunctionCall or expr.FieldSelector expression.

i.e. a function call geo.Distance(pt1, pt2) might return either a direct value if both pt1 and pt2 are direct values, or indirect value (expr.FunctionCall) if at least one of them is indirect. I.e.

  • geo.Distance(loc, geo.Point(1, 2)) returns an indirect value., as the first argument is field selector, and the second is a direct value.
  • geo.Distance(geo.Point(1, 2), geo.Point(3, 4)) returns a direct value, as both arguments are direct values, this would result in returning value defined by the geo.Distance function.
  • geo.Point(x, y) - returns an indirect value, as both arguments are indirect.
  • geo.Point(1, 2) - returns a direct value, as both arguments are direct.

If the function call expected result type is a boolean, then it could be used as a sole comparable expression in the restriction expression. i.e.:

  • geo.InArea(loc, area) - returns an indirect value, as both arguments are indirect, but it can be used as a comparable expression in the restriction expression. this function needs to define its returning declaration to be of kind boolean.

If the function does not contain a returning declaration, then it is service called function expression, and it needs to be validated by the service.

func (*FunctionCallDeclaration) ServiceCall

func (f *FunctionCallDeclaration) ServiceCall() bool

ServiceCall returns true if the function call is a service call.

func (*FunctionCallDeclaration) Validate

func (f *FunctionCallDeclaration) Validate() error

Validate validates the function call declaration.

type FunctionCallFn

type FunctionCallFn func(args ...expr.FilterExpr) (FunctionCallArgument, error)

FunctionCallFn is a function call handler function. It is used to handle a function call ast node, and return an expression. It either can return indirect expr.FunctionCall expression (in case of indirect argument), or a value expression. An indirect call might be used to perform a function call on a service directly outside of the filtering layer.

type FunctionCallReturningDeclaration

type FunctionCallReturningDeclaration struct {
	// ServiceCalled is true if the function call returns a expr.FunctionCall expression.
	// This enforces the function call to return an expr.FunctionCall expression.
	// A service called boolean excludes the possibility to return a direct value.
	ServiceCalled bool

	// FieldKind determines the kind of direct value returned by direct the function call.
	FieldKind protoreflect.Kind

	// EnumDescriptor is the enum descriptor of the direct value returned by the function call.
	EnumDescriptor protoreflect.EnumDescriptor

	// MessageDescriptor is the message descriptor of the direct value returned by the function call.
	MessageDescriptor protoreflect.MessageDescriptor

	// MapKeyDesc is the map key descriptor of the value returned by the function call.
	// This must be set if the resulting value is a map.
	MapKeyDesc protoreflect.FieldDescriptor

	// MapValueDesc is the map value descriptor of the value returned by the function call.
	// This must be set if the resulting value is a map.
	MapValueDesc protoreflect.FieldDescriptor

	// IsNullable is true if the function call returns a nullable value.
	IsNullable bool

	// IsRepeated is true if the function call returns a repeated value.
	IsRepeated bool
}

FunctionCallReturningDeclaration is a declaration of a function call returning value. It either tell if the function is a Service Called abstract function call, or it specifies the kind of the returning value. The returning value implements the FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) Cardinality

Cardinality returns the cardinality of the returning value. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) Enum

Enum returns the enum descriptor of the returning value. If the returning value is not an enum, then it returns nil. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) IsMap

IsMap returns true if the returning value is a map. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) Kind

Kind returns the kind of the returning value. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) MapKey

MapKey returns the map key descriptor of the returning value. It returns nil if the returning value is not a map. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) MapValue

MapValue returns the map value descriptor of the returning value. It returns nil if the returning value is not a map. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) Message

Message returns the message descriptor of the returning value. If the returning value is not a message, then it returns nil. Implements FieldDescriptor interface.

func (*FunctionCallReturningDeclaration) Validate

type FunctionName

type FunctionName struct {
	// PkgName is the name of the package where the function is defined.
	PkgName string
	// Name is the name of the function call.
	Name string
}

FunctionName is the name of the function call.

func (FunctionName) String

func (n FunctionName) String() string

type HandledExpr

type HandledExpr struct {
	Expr     expr.FilterExpr
	Consumed bool
}

HandledExpr is a struct that contains an expression and a flag that indicates if the expression was consumed.

type Interpreter

type Interpreter struct {
	// contains filtered or unexported fields
}

Interpreter is an interpreter that can parse a query string and return an expression.

func NewInterpreter

func NewInterpreter(msg protoreflect.MessageDescriptor, opts ...Option) (*Interpreter, error)

NewInterpreter returns a new interpreter.

func (*Interpreter) HandleCompositeExpr

func (b *Interpreter) HandleCompositeExpr(ctx *ParseContext, x *ast.CompositeExpr) (TryParseValueResult, error)

HandleCompositeExpr handles an ast.CompositeExpr and returns an expression.

func (*Interpreter) HandleExpr

func (b *Interpreter) HandleExpr(ctx *ParseContext, x *ast.Expr) (TryParseValueResult, error)

HandleExpr handles an ast.FilterExpr and returns an handled expression.

func (*Interpreter) HandleFactorExpr

func (b *Interpreter) HandleFactorExpr(ctx *ParseContext, factor *ast.FactorExpr) (TryParseValueResult, error)

HandleFactorExpr handles an ast.FactorExpr and returns resulting expression. If there is only one term, the term is handled directly. If there are multiple terms, they are handled as an OR expression.

func (*Interpreter) HandleRestrictionExpr

func (b *Interpreter) HandleRestrictionExpr(ctx *ParseContext, x *ast.RestrictionExpr) (TryParseValueResult, error)

HandleRestrictionExpr handles an ast.Restriction expression and returns resulting expr.FilterExpr.

func (*Interpreter) HandleSequenceExpr

func (b *Interpreter) HandleSequenceExpr(ctx *ParseContext, seq *ast.SequenceExpr) (TryParseValueResult, error)

HandleSequenceExpr handles an ast.SequenceExpr and returns resulting expression. A sequence might be composed of single or multiple factors. If it is composed of a single factor, the factor is handled directly. If it is composed of multiple factors, they are handled as an AND expression. This is called a 'fuzzy' AND expression, because it is not a strict AND expression. Read more at https://google.aip.dev/160#literals for more information.

func (*Interpreter) HandleSimpleExpr

func (b *Interpreter) HandleSimpleExpr(ctx *ParseContext, x ast.SimpleExpr) (TryParseValueResult, error)

HandleSimpleExpr handles an ast.SimpleExpr and returns an handled expression. The handled expression can be a composite expression or a restriction expression.

func (*Interpreter) HandleTermExpr

func (b *Interpreter) HandleTermExpr(ctx *ParseContext, term *ast.TermExpr) (TryParseValueResult, error)

HandleTermExpr handles an ast.TermExpr and returns resulting expression. If Unary operator is defined

func (*Interpreter) Parse

func (b *Interpreter) Parse(filter string) (expr.FilterExpr, error)

Parse input filter into an expression. Implements filtering.Interpreter interface. By default, interpreter is returning a non-precise error if the parsing fails. For detailed error handling, provide an error handler function during initialization of the interpreter.

Example
package main

import (
	"fmt"
	"os"

	"github.com/blockysource/blocky-aip/filtering"
	"github.com/blockysource/blocky-aip/internal/testpb"
	"github.com/blockysource/blocky-aip/token"
)

func main() {
	var i filtering.Interpreter

	msg := new(testpb.Message)

	err := i.Reset(msg.ProtoReflect().Descriptor(), filtering.ErrHandlerOpt(func(pos token.Position, msg string) {
		fmt.Printf("Error: %v at: %d\n", msg, pos)
	}))
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}

	// Parse a filter.
	filter := `name = "value" AND (age > 18 OR age < 10)`
	pf, err := i.Parse(filter)
	if err != nil {
		// Handle the error on request.
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}
	// Always Free the memory of allocated filter expressions.
	// It is safe to call Free multiple times, or on nil pointer expressions.
	defer pf.Free()

	// Evaluate the filter.
	
Output:

func (*Interpreter) Reset

func (b *Interpreter) Reset(msg protoreflect.MessageDescriptor, opts ...Option) error

func (*Interpreter) TryParseBooleanField

func (b *Interpreter) TryParseBooleanField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseBooleanField tries to parse a boolean field. It can be a single boolean value or a repeated boolean value.

func (*Interpreter) TryParseBytesField

func (b *Interpreter) TryParseBytesField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseBytesField tries to parse a bytes field. It can be a single bytes value or a repeated bytes value.

func (*Interpreter) TryParseDurationField

func (b *Interpreter) TryParseDurationField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseDurationField tries to parse the provided value as a duration. It returns an error if the value is not a valid duration.

func (*Interpreter) TryParseEnumField

func (b *Interpreter) TryParseEnumField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseEnumField tries to parse an enum field. It can be a single enum value or a repeated enum value.

func (*Interpreter) TryParseFloatField

func (b *Interpreter) TryParseFloatField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseFloatField tries to parse a float field. It can be a single float value or a repeated float value.

func (*Interpreter) TryParseFunctionCall

func (b *Interpreter) TryParseFunctionCall(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseFunctionCall handles an ast.FunctionCall by interpreting the function call, and executing the function call handler. It returns either resulting expression value, an expr.FunctionCall expression, or an error.

func (*Interpreter) TryParseMapField

func (b *Interpreter) TryParseMapField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseMapField tries to parse a map field.

func (*Interpreter) TryParseMessageField

func (b *Interpreter) TryParseMessageField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseMessageField tries to parse a message field.

func (*Interpreter) TryParseMessageStructField

func (b *Interpreter) TryParseMessageStructField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

func (*Interpreter) TryParseSelectorExpr

func (b *Interpreter) TryParseSelectorExpr(ctx *ParseContext, value ast.ValueExpr, args ...ast.FieldExpr) (TryParseValueResult, error)

TryParseSelectorExpr handles an ast.MemberExpr and returns an expression.

func (*Interpreter) TryParseSignedIntField

func (b *Interpreter) TryParseSignedIntField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseSignedIntField tries to parse a signed int field. It can be a single signed int value or a repeated signed int value.

func (*Interpreter) TryParseStringField

func (b *Interpreter) TryParseStringField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseStringField tries to parse a string field. It can be a single string value or a repeated string value.

func (*Interpreter) TryParseStructPb

func (b *Interpreter) TryParseStructPb(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseStructPb tries to parse a well-known structpb.Value field.

func (*Interpreter) TryParseTimestampField

func (b *Interpreter) TryParseTimestampField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseTimestampField tries parsing a timestamp field value. The result depending on the input, could be a ValueExpr, ArrayExpr or if it accepts indirect values, a FunctionCallExpr or FieldSelectorExpr.

func (*Interpreter) TryParseUnsignedIntField

func (b *Interpreter) TryParseUnsignedIntField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error)

TryParseUnsignedIntField tries to parse an unsigned int field. It can be a single unsigned int value or a repeated unsigned int value.

func (*Interpreter) TryParseValue

TryParseValue tries to parse a value expression.

type Option

type Option func(*Interpreter) error

Option is an option that can be passed to the interpreter.

func ErrHandlerOpt

func ErrHandlerOpt(errorHandler scanner.ErrorHandler) Option

ErrHandlerOpt is an option that sets the error handler of the interpreter.

func RegisterFunction

func RegisterFunction(fn *FunctionCallDeclaration) Option

RegisterFunction is an Option that registers a function call declaration within the interpreter. Once registered, the function can be used in the filter.

type ParseContext

type ParseContext struct {
	// Message is the message descriptor of the current expression.
	Message protoreflect.MessageDescriptor

	// ErrHandler is the error handler function.
	ErrHandler func(pos token.Position, msg string)

	// Interpreter is the reference to the interpreter that parses the expression.
	// It can be used by custom handlers to reuse standard handlers for sub-expressions.
	Interpreter *Interpreter
	// contains filtered or unexported fields
}

ParseContext is a struct that contains the context of the expression.

func (*ParseContext) Free

func (c *ParseContext) Free()

Free frees the context.

type TryParseValueInput

type TryParseValueInput struct {
	// Field is a required field descriptor of the value.
	Field FieldDescriptor

	// Value is a required value expression.
	Value ast.AnyExpr

	// AllowIndirect is a flag that indicates whether the value can be indirect.
	// An indirect call is defined either by the function call or the field selector expression.
	AllowIndirect bool

	// IsOptional is a flag that indicates whether the value can be null.
	IsOptional bool

	// Args are the optional arguments of the value.
	// Used mostly by the member expression fields.
	Args []ast.FieldExpr

	// Complexity defines the complexity of a field.
	Complexity int64
}

TryParseValueInput is an input for the TryParseValue function. It is used to parse a value expression either directly or indirectly.

type TryParseValueResult

type TryParseValueResult struct {
	// Expr is the parsed expression.
	Expr expr.FilterExpr

	// ErrPos is the detailed error position.
	ErrPos token.Position

	// ErrMsg is the detailed error message.
	ErrMsg string

	// ArgsUsed is the number of arguments used by the value from the Args input.
	ArgsUsed int

	// IsIndirect is a flag that indicates whether the value is indirect.
	// An indirect value means it depends on the field selector.
	IsIndirect bool
}

TryParseValueResult is a result of the TryParseValue function. It either contains an expression or an error with the error position and message. ArgsUsed is the number of arguments used by the value from the Args input.

Directories

Path Synopsis
Package ast provides Abstract Syntax Tree (AST) for filtering expressions that satisfies Google's AIP-160 (https://google.aip.dev/160).
Package ast provides Abstract Syntax Tree (AST) for filtering expressions that satisfies Google's AIP-160 (https://google.aip.dev/160).
Package parser provides AIP-160 compliant parser for filtering expressions.
Package parser provides AIP-160 compliant parser for filtering expressions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL