Documentation ¶
Overview ¶
Package topdown provides query evaluation support.
The topdown implementation is a (slightly modified) version of the standard "top-down evaluation" algorithm used in query languages such as Datalog. The main difference in the implementation is in the handling of Rego references.
At a high level, the topdown implementation consists of (1) term evaluation and (2) expression evaluation. Term evaluation involves handling expression terms in isolation whereas expression evaluation involves evaluating the terms in relation to each other.
During the term evaluation phase, the topdown implementation will evaluate references found in the expression to produce bindings for:
- Variables appearing in references
- References to Virtual Documents
- Comprehensions
Once terms have been evaluated in isolation, the overall expression can be evaluated. If the expression is simply a term (e.g., string, reference, variable, etc.) then it is compared against the boolean "false" value. If the value IS NOT "false", evaluation continues. On the other hand, if the expression is defined by a built-in operator (e.g., =, !=, min, max, etc.) then the appropriate built-in function is invoked to determine if evaluation continues and bind variables accordingly.
Index ¶
- Constants
- func Continue(ctx *Context, key, value ast.Value, iter Iterator) error
- func ContinueN(ctx *Context, iter Iterator, x ...ast.Value) error
- func Eval(ctx *Context, iter Iterator) error
- func IsUnboundGlobal(e error) bool
- func PlugExpr(expr *ast.Expr, binding Binding) *ast.Expr
- func PlugHead(head *ast.Head, binding Binding) *ast.Head
- func PlugTerm(term *ast.Term, binding Binding) *ast.Term
- func PlugValue(v ast.Value, binding func(ast.Value) ast.Value) ast.Value
- func PrettyTrace(w io.Writer, trace []*Event)
- func Query(params *QueryParams) (interface{}, error)
- func RegisterBuiltinFunc(name ast.Var, fun BuiltinFunc)
- func ResetQueryIDs()
- func ResolveRefs(v ast.Value, ctx *Context) (ast.Value, error)
- func ValueToFloat64(v ast.Value, ctx *Context) (float64, error)
- func ValueToInterface(v ast.Value, ctx *Context) (interface{}, error)
- func ValueToSlice(v ast.Value, ctx *Context) ([]interface{}, error)
- func ValueToString(v ast.Value, ctx *Context) (string, error)
- func ValueToStrings(v ast.Value, ctx *Context) ([]string, error)
- type Binding
- type BufferTracer
- type BuiltinFunc
- type Context
- func (ctx *Context) Bind(key ast.Value, value ast.Value, prev *Undo) *Undo
- func (ctx *Context) Binding(k ast.Value) ast.Value
- func (ctx *Context) Child(query ast.Body, locals *ast.ValueMap) *Context
- func (ctx *Context) Current() *ast.Expr
- func (ctx *Context) Step() *Context
- func (ctx *Context) Unbind(undo *Undo)
- type Error
- type Event
- type Iterator
- type Op
- type QueryParams
- type Tracer
- type Undefined
- type Undo
Examples ¶
Constants ¶
const ( // InternalErr represents an unknown evaluation error. InternalErr = iota // UnboundGlobalErr indicates a global variable without a binding was // encountered during evaluation. UnboundGlobalErr = iota // ConflictErr indicates multiple (conflicting) values were produced // while generating a virtual document. E.g., given two rules that share // the same name: p = false :- true, p = true :- true, a query "p" would // evaluate p to "true" and "false". ConflictErr = iota // TypeErr indicates evaluation stopped because an expression was applied to // a value of an inappropriate type. TypeErr = iota )
Variables ¶
This section is empty.
Functions ¶
func Continue ¶
Continue binds the key to the value in the current context and invokes the iterator. This is a helper function for simple cases where a single value (e.g., a variable) needs to be bound to a value in order for the evaluation the proceed.
func ContinueN ¶
ContinueN binds N keys to N values. The key/value pairs are passed in as alternating pairs, e.g., key-1, value-1, key-2, value-2, ..., key-N, value-N.
func Eval ¶
Eval runs the evaluation algorithm on the context and calls the iterator for each context that contains bindings that satisfy all of the expressions inside the body.
Example ¶
package main import ( "encoding/json" "fmt" "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/storage" "github.com/open-policy-agent/opa/topdown" ) func main() { // Define a dummy query and some data that the query will execute against. compiler, query, err := ast.CompileQuery("data.a[_] = x, x >= 2") if err != nil { // Handle error. } var data map[string]interface{} if err := json.Unmarshal([]byte(`{"a": [1,2,3,4]}`), &data); err != nil { // Handle error. } // Instantiate the policy engine's storage layer. store := storage.New(storage.InMemoryWithJSONConfig(data)) // Create a new transaction. Transactions allow the policy engine to // evaluate the query over a consistent snapshot fo the storage layer. txn, err := store.NewTransaction() if err != nil { // Handle error. } defer store.Close(txn) // Prepare the evaluation parameters. Evaluation executes against the policy engine's // storage. In this case, we seed the storage with a single array of number. Other parameters // such as globals, tracing configuration, etc. can be set on the context. See the Context // documentation for more details. ctx := topdown.NewContext(query, compiler, store, txn) result := []interface{}{} // Execute the query and provide a callbakc function to accumulate the results. err = topdown.Eval(ctx, func(ctx *topdown.Context) error { // Each variable in the query will have an associated "binding" in the context. x := ctx.Binding(ast.Var("x")) // The bindings are ast.Value types so we will convert to a native Go value here. v, err := topdown.ValueToInterface(x, ctx) if err != nil { return err } result = append(result, v) return nil }) // Inspect the query result. fmt.Println("result:", result) fmt.Println("err:", err) }
Output: result: [2 3 4] err: <nil>
func IsUnboundGlobal ¶
IsUnboundGlobal returns true if the error e is an UnboundGlobalErr
func PlugHead ¶ added in v0.2.0
PlugHead returns a copy of head with bound terms substituted for the binding.
func PrettyTrace ¶ added in v0.2.0
PrettyTrace pretty prints the trace to the writer.
func Query ¶
func Query(params *QueryParams) (interface{}, error)
Query returns the document identified by the path.
Example ¶
package main import ( "fmt" "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/storage" "github.com/open-policy-agent/opa/topdown" ) func main() { // Define a dummy module with rules that produce documents that we will query below. compiler, _, err := ast.CompileModule(` package opa.example p[x] :- q[x], not r[x] q[y] :- a = [1,2,3], y = a[_] r[z] :- b = [2,4], z = b[_] `) if err != nil { // Handle error. } // Instantiate the policy engine's storage layer. store := storage.New(storage.InMemoryConfig()) // Create a new transaction. Transactions allow the policy engine to // evaluate the query over a consistent snapshot fo the storage layer. txn, err := store.NewTransaction() if err != nil { // Handle error. } defer store.Close(txn) // Prepare the query parameters. Queries execute against the policy engine's storage and can // accept additional documents (which are referred to as "globals"). In this case we have no // additional documents. globals := ast.NewValueMap() params := topdown.NewQueryParams(compiler, store, txn, globals, []interface{}{"opa", "example", "p"}) // Execute the query against "p". v1, err1 := topdown.Query(params) // Inspect the result. fmt.Println("v1:", v1) fmt.Println("err1:", err1) }
Output: v1: [1 3] err1: <nil>
func RegisterBuiltinFunc ¶
func RegisterBuiltinFunc(name ast.Var, fun BuiltinFunc)
RegisterBuiltinFunc adds a new built-in function to the evaluation engine.
func ResetQueryIDs ¶ added in v0.2.0
func ResetQueryIDs()
ResetQueryIDs resets the query ID generator. This is only for test purposes.
func ResolveRefs ¶ added in v0.2.0
ResolveRefs returns an AST value obtained by replacing references in v with values from storage.
func ValueToFloat64 ¶
ValueToFloat64 returns the underlying Go value associated with an AST value. If the value is a reference, the reference is fetched from storage.
func ValueToInterface ¶
ValueToInterface returns the underlying Go value associated with an AST value. If the value is a reference, the reference is fetched from storage. Composite AST values such as objects and arrays are converted recursively.
func ValueToSlice ¶
ValueToSlice returns the underlying Go value associated with an AST value. If the value is a reference, the reference is fetched from storage.
func ValueToString ¶
ValueToString returns the underlying Go value associated with an AST value. If the value is a reference, the reference is fetched from storage.
Types ¶
type Binding ¶ added in v0.2.0
Binding defines the interface used to apply term bindings to terms, expressions, etc.
type BufferTracer ¶ added in v0.2.0
type BufferTracer []*Event
BufferTracer implements the Tracer interface by simply buffering all events received.
func NewBufferTracer ¶ added in v0.2.0
func NewBufferTracer() *BufferTracer
NewBufferTracer returns a new BufferTracer.
func (*BufferTracer) Enabled ¶ added in v0.2.0
func (b *BufferTracer) Enabled() bool
Enabled always returns true.
func (*BufferTracer) Trace ¶ added in v0.2.0
func (b *BufferTracer) Trace(ctx *Context, evt *Event)
Trace adds the event to the buffer.
type BuiltinFunc ¶
BuiltinFunc defines the interface that the evaluation engine uses to invoke built-in functions. Users can implement their own built-in functions and register them with the evaluation engine.
Callers are given the current evaluation Context ctx with the expression expr to be evaluated. Callers can assume that the expression has been plugged with bindings from the current context. If the built-in function determines that the expression has evaluated successfully it should bind any output variables and invoke the iterator with the context produced by binding the output variables.
type Context ¶
type Context struct { Query ast.Body Compiler *ast.Compiler Globals *ast.ValueMap Locals *ast.ValueMap Index int Previous *Context Store *storage.Storage Tracer Tracer // contains filtered or unexported fields }
Context contains the state of the evaluation process.
func NewContext ¶
func NewContext(query ast.Body, compiler *ast.Compiler, store *storage.Storage, txn storage.Transaction) *Context
NewContext creates a new Context with no bindings.
func (*Context) Bind ¶
Bind updates the context to include a binding from the key to the value. The return value is used to return the context to the state before the binding was added.
func (*Context) Child ¶
Child returns a new context to evaluate a query that was referenced by this context.
type Error ¶
Error is the error type returned by the Eval and Query functions when an evaluation error occurs.
type Event ¶ added in v0.2.0
type Event struct { Op Op // Identifies type of event. Node interface{} // Contains AST node relevant to the event. QueryID uint64 // Identifies the query this event belongs to. ParentID uint64 // Identifies the parent query this event belongs to. Locals *ast.ValueMap // Contains local variable bindings from the query context. }
Event contains state associated with a tracing event.
type Op ¶ added in v0.2.0
type Op string
Op defines the types of tracing events.
const ( // EnterOp is emitted when a new query is about to be evaluated. EnterOp Op = "Enter" // ExitOp is emitted when a query has evaluated to true. ExitOp Op = "Exit" // EvalOp is emitted when an expression is about to be evaluated. EvalOp Op = "Eval" // RedoOp is emitted when an expression, rule, or query is being re-evaluated. RedoOp Op = "Redo" // FailOp is emitted when an expression evaluates to false. FailOp Op = "Fail" )
type QueryParams ¶
type QueryParams struct { Compiler *ast.Compiler Store *storage.Storage Transaction storage.Transaction Globals *ast.ValueMap Tracer Tracer Path []interface{} }
QueryParams defines input parameters for the query interface.
func NewQueryParams ¶
func NewQueryParams(compiler *ast.Compiler, store *storage.Storage, txn storage.Transaction, globals *ast.ValueMap, path []interface{}) *QueryParams
NewQueryParams returns a new QueryParams.
func (*QueryParams) NewContext ¶ added in v0.2.0
func (q *QueryParams) NewContext(body ast.Body) *Context
NewContext returns a new Context that can be used to do evaluation.