diff --git a/ast/example_test.go b/ast/example_test.go new file mode 100644 index 0000000000..fa98dac808 --- /dev/null +++ b/ast/example_test.go @@ -0,0 +1,55 @@ +// Copyright 2016 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package ast_test + +import ( + "fmt" + + "github.com/open-policy-agent/opa/ast" +) + +func ExampleCompiler_Compile() { + + // Define an input module that will be compiled. + exampleModule := ` + + package opa.example + + import data.foo + import bar + + p[x] :- foo[x], not bar[x], x < min_x + + min_x = 100 + + ` + + // Parse the input module to obtain the AST representation. + mod, err := ast.ParseModule("my_module", exampleModule) + if err != nil { + fmt.Println("Parse error:", err) + } + + // Create a new compiler instance and compile the module. + c := ast.NewCompiler() + + mods := map[string]*ast.Module{ + "my_module": mod, + } + + if c.Compile(mods); c.Failed() { + fmt.Println("Compile error:", c.FlattenErrors()) + } + + fmt.Println("Expr 1:", mod.Rules[0].Body[0]) + fmt.Println("Expr 2:", mod.Rules[0].Body[1]) + fmt.Println("Expr 3:", mod.Rules[0].Body[2]) + + // Output: + // + // Expr 1: data.foo[x] + // Expr 2: not bar[x] + // Expr 3: lt(x, data.opa.example.min_x) +} diff --git a/repl/example_test.go b/repl/example_test.go new file mode 100644 index 0000000000..a91ff27d30 --- /dev/null +++ b/repl/example_test.go @@ -0,0 +1,42 @@ +// Copyright 2016 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package repl_test + +import ( + "bytes" + "fmt" + + "github.com/open-policy-agent/opa/repl" + "github.com/open-policy-agent/opa/storage" +) + +func ExampleREPL_OneShot() { + + // Setup dummy storage for the policy engine. + ds := storage.NewDataStore() + ps := storage.NewPolicyStore(ds, "") + if err := ps.Open(storage.LoadPolicies); err != nil { + fmt.Println("Open error:", err) + } + + // Create a buffer that will receive REPL output. + var buf bytes.Buffer + + // Create a new REPL. + repl := repl.New(ds, ps, "", &buf, "json") + + // Define a rule inside the REPL. + repl.OneShot("p :- a = [1, 2, 3, 4], a[_] > 3") + + // Query the rule defined above. + repl.OneShot("p") + + // Inspect the output. Defining rules does not produce output so we only expect + // output from the second line of input. + fmt.Println(buf.String()) + + // Output: + // true +} diff --git a/storage/example_test.go b/storage/example_test.go new file mode 100644 index 0000000000..3be28c0ce6 --- /dev/null +++ b/storage/example_test.go @@ -0,0 +1,182 @@ +// Copyright 2016 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package storage_test + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/open-policy-agent/opa/storage" +) + +func ExampleDataStore_Get() { + + // Define some dummy data to initialize the DataStore with. + exampleData := ` + { + "users": [ + { + "name": "alice", + "color": "red", + "likes": ["clouds", "ships"] + }, + { + "name": "burt", + "likes": ["cheese", "wine"] + } + ] + } + ` + + var d map[string]interface{} + + if err := json.Unmarshal([]byte(exampleData), &d); err != nil { + fmt.Println("Unmarshal error:", err) + } + + // Create the new DataStore with the dummy data. + ds := storage.NewDataStoreFromJSONObject(d) + + // Read values out of the DataStore. + v1, err1 := ds.Get([]interface{}{"users", float64(1), "likes", float64(1)}) + v2, err2 := ds.Get([]interface{}{"users", float64(0), "age"}) + + // Inspect the return values. + fmt.Println("v1:", v1) + fmt.Println("err1:", err1) + fmt.Println("v2:", v2) + fmt.Println("err2:", err2) + fmt.Println("err2 is not found:", storage.IsNotFound(err2)) + + // Output: + // v1: wine + // err1: + // v2: + // err2: storage error (code: 1): bad path: [users 0 age], document does not exist + // err2 is not found: true +} + +func ExampleDataStore_Patch() { + + // Define some dummy data to initialize the DataStore with. + exampleData := ` + { + "users": [ + { + "name": "alice", + "color": "red", + "likes": ["clouds", "ships"] + }, + { + "name": "burt", + "likes": ["cheese", "wine"] + } + ] + } + ` + + var d1 map[string]interface{} + + if err := json.Unmarshal([]byte(exampleData), &d1); err != nil { + fmt.Println("Unmarshal error:", err) + } + + // Create the new DataStore with the dummy data. + ds := storage.NewDataStoreFromJSONObject(d1) + + // Define dummy data to add to the DataStore. + exampleAdd := `{ + "longitude": 82.501389, + "latitude": -62.338889 + }` + + var d2 interface{} + + if err := json.Unmarshal([]byte(exampleAdd), &d2); err != nil { + fmt.Println("Unmarshal error:", err) + } + + // Write values into storage and read result. + err0 := ds.Patch(storage.AddOp, []interface{}{"users", float64(0), "location"}, d2) + v1, err1 := ds.Get([]interface{}{"users", float64(0), "location", "latitude"}) + err2 := ds.Patch(storage.ReplaceOp, []interface{}{"users", float64(1), "color"}, "red") + + // Inspect the return values. + fmt.Println("err0:", err0) + fmt.Println("v1:", v1) + fmt.Println("err1:", err1) + fmt.Println("err2:", err2) + + // Output: + // err0: + // v1: -62.338889 + // err1: + // err2: storage error (code: 1): bad path: [users 1 color], document does not exist + +} + +func ExamplePolicyStore_Open() { + + // Define two example modules and write them to disk in a temporary directory. + ex1 := ` + + package opa.example + + p :- q.r != 0 + + ` + + ex2 := ` + + package opa.example + + q = {"r": 100} + + ` + + path, err := ioutil.TempDir("", "") + if err != nil { + fmt.Println("TempDir error:", err) + } + + defer os.RemoveAll(path) + + if err = ioutil.WriteFile(filepath.Join(path, "ex1.rego"), []byte(ex1), 0644); err != nil { + fmt.Println("WriteFile error:", err) + } + + if err = ioutil.WriteFile(filepath.Join(path, "ex2.rego"), []byte(ex2), 0644); err != nil { + fmt.Println("WriteFile error:", err) + } + + // Create a new policy store and use the temporary directory for persistence. + ds := storage.NewDataStore() + ps := storage.NewPolicyStore(ds, path) + + // Open the policy store and load the existing modules. + // + // The LoadPolicies function provides a default implementation of callback + // used to load the modules. If necessary, you can provide your own implementation + // of the callback function to customize the policy store initialization. + err = ps.Open(storage.LoadPolicies) + if err != nil { + fmt.Println("Open error:", err) + } + + // Inspect one of the loaded policies. + mod, err := ps.Get("ex1.rego") + if err != nil { + fmt.Println("Get error:", err) + } + + fmt.Println("Expr:", mod.Rules[0].Body[0]) + + // Output: + // Expr: neq(data.opa.example.q.r, 0) + +} diff --git a/topdown/example_test.go b/topdown/example_test.go new file mode 100644 index 0000000000..f1d32c4797 --- /dev/null +++ b/topdown/example_test.go @@ -0,0 +1,101 @@ +// Copyright 2016 The OPA Authors. All rights reserved. +// Use of this source code is governed by an Apache2 +// license that can be found in the LICENSE file. + +package topdown_test + +import ( + "fmt" + + "github.com/open-policy-agent/opa/ast" + "github.com/open-policy-agent/opa/storage" + "github.com/open-policy-agent/opa/topdown" +) + +func ExampleEval() { + + // Define a dummy query and some data that the query will execute against. + query, err := ast.CompileQuery("data.a[_] = x, x >= 2") + if err != nil { + fmt.Println("Compile error:", err) + } + + ds := storage.NewDataStoreFromJSONObject(map[string]interface{}{ + "a": []interface{}{float64(1), float64(2), float64(3), float64(4)}, + }) + + // 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, ds) + + 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: +} + +func ExampleQuery() { + + // Define a dummy module with rules that produce documents that we will query below. + mod, 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 { + fmt.Println("Compile error:", err) + } + + // Initialize the policy engine's storage. + ds := storage.NewDataStore() + ps := storage.NewPolicyStore(ds, "") + if err := ps.Add("my_module", mod, nil, false); err != nil { + fmt.Println("Add error:", err) + } + + // 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 := storage.NewBindings() + params := topdown.NewQueryParams(ds, 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: + +}