Skip to content

Latest commit

 

History

History
279 lines (198 loc) · 7.6 KB

File metadata and controls

279 lines (198 loc) · 7.6 KB

CEL-Go Examples

This directory contains executable Go examples showcasing the CEL-Go APIs and language features. All examples correspond to topics on CEL by Example and are implemented as Go Example...() functions runnable via go test and viewable via godoc.


1. Quickstart & Compilation (cel.Compile)

Compile and evaluate expressions using cel.Compile():

package main

import (
	"fmt"
	"log"

	"github.com/google/cel-go/cel"
)

func main() {
	prg, err := cel.Compile(`"Hello world! I'm " + name + "."`,
		cel.Variable("name", cel.StringType),
	)
	if err != nil {
		log.Fatalln(err)
	}
	out, _, err := prg.Eval(map[string]any{
		"name": "CEL",
	})
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(out)
	// Output: Hello world! I'm CEL.
}

For custom options and extensions:

prg, err := cel.Compile(`"%s! I'm %s.".format([greeting, name])`,
	ext.Strings(),
	cel.Variable("greeting", cel.StringType),
	cel.Variable("name", cel.StringType),
)
out, _, err := prg.Eval(map[string]any{
	"greeting": "Hello world",
	"name":     "CEL",
})

Source code: example_cel_compile_test.go | Source code: example_cel_context_eval_test.go


2. Strings & Numbers

Covers string functions (endsWith, contains, startsWith, matches, size), string concatenation (+), numeric comparisons, and ext.Strings() extensions:

prg, _ := cel.Compile(`"hello world".replace("world", "CEL")`, ext.Strings())
out, _, _ := prg.Eval(cel.NoVars())
fmt.Println(out) // hello CEL

Source code: example_cel_strings_and_numbers_test.go


3. Collections (Lists & Maps)

Membership (in), size (size()), indexing ([0]), quantifier macros (exists(), all()), and filtering (filter()):

prg, _ := cel.Compile(`tags.exists(t, t.startsWith("ex"))`, cel.Variable("tags", cel.DynType))
out, _, _ := prg.Eval(map[string]any{
	"tags": []string{"express", "gift-wrapped"},
})
fmt.Println(out) // true

Source code: example_cel_collections_test.go


4. Timestamps & Durations

Time component extraction (getFullYear(), getHours()), timezones, timestamp arithmetic, and epoch conversions:

prg, _ := cel.Compile(`timestamp("2024-01-15T10:30:45Z") + duration("1h")`)
out, _, _ := prg.Eval(cel.NoVars())
fmt.Println(out) // 2024-01-15 11:30:45 +0000 UTC

Source code: example_cel_time_test.go


5. Logic & Conditions

Logical operators (!, &&, ||), short-circuiting, and conditional (ternary) operators:

prg, _ := cel.Compile(`age >= 18 ? "adult" : "minor"`, cel.Variable("age", cel.IntType))
out, _, _ := prg.Eval(map[string]any{"age": 20})
fmt.Println(out) // adult

Source code: example_cel_logic_and_conditions_test.go


6. Transforming Data

Building maps, list transformation with map(), and filtering before transformation:

prg, _ := cel.Compile(`nums.map(x, x % 2 == 0, x * 10)`, cel.Variable("nums", cel.ListType(cel.IntType)))
out, _, _ := prg.Eval(map[string]any{
	"nums": []int64{1, 2, 3, 4, 5},
})
fmt.Println(out) // [20, 40]

Source code: example_cel_transforming_data_test.go


7. Type Conversions & Introspection

Type casting (int(), uint(), double(), string(), bytes(), dyn()) and type inspection (type(x)):

prg, _ := cel.Compile(`type(42) == int`)
out, _, _ := prg.Eval(cel.NoVars())
fmt.Println(out) // true

Source code: example_cel_type_conversions_test.go


8. Protocol Buffers & Well-Known Types

Protobuf message construction, enums, field presence has(), default values, wrappers (StringValue, BoolValue), and google.protobuf.Struct:

prg, _ := cel.Compile(`has(user.single_string)`,
	cel.Types(&proto3pb.TestAllTypes{}),
	cel.Variable("user", cel.ObjectType("google.expr.proto3.test.TestAllTypes")),
)
out, _, _ := prg.Eval(map[string]any{
	"user": &proto3pb.TestAllTypes{SingleString: "Alice"},
})
fmt.Println(out) // true

Source code: example_cel_protocol_buffers_test.go


9. Operators

Arithmetic, ordering, equality, and null handling:

prg, _ := cel.Compile(`(2 + 3) * 4`)
out, _, _ := prg.Eval(cel.NoVars())
fmt.Println(out) // 20

Source code: example_cel_operators_test.go


10. Custom Functions

Extend CEL with global functions (cel.Overload) or member functions (cel.MemberOverload):

prg, _ := cel.Compile(`shake_hands(i, you)`,
	cel.Variable("i", cel.StringType),
	cel.Variable("you", cel.StringType),
	cel.Function("shake_hands",
		cel.Overload("shake_hands_string_string",
			[]*cel.Type{cel.StringType, cel.StringType},
			cel.StringType,
			cel.BinaryBinding(func(lhs, rhs ref.Val) ref.Val {
				return types.String(fmt.Sprintf("%s and %s are shaking hands.", lhs, rhs))
			}),
		),
	),
)
out, _, _ := prg.Eval(map[string]any{"i": "CEL", "you": "world"})
fmt.Println(out) // CEL and world are shaking hands.

Source code: example_cel_custom_functions_test.go


11. Custom Macros

Define AST transformation macros using parser.NewGlobalMacro or parser.NewReceiverMacro:

joinMacro := parser.NewGlobalMacro("join_str", 2, func(eh parser.ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) {
    space := eh.NewLiteral(types.String(" "))
    first := eh.NewCall(operators.Add, args[0], space)
    return eh.NewCall(operators.Add, first, args[1]), nil
})
prg, _ := cel.Compile(`join_str("Hello", "World")`, cel.Macros(joinMacro))
out, _, _ := prg.Eval(cel.NoVars())
fmt.Println(out) // Hello World

Source code: example_cel_custom_macros_test.go


12. Execution Cost Analysis

Static cost estimation with env.EstimateCost() and dynamic limit enforcement with cel.CostTracking() & cel.CostLimit():

env, _ := cel.NewEnv(cel.Variable("items", cel.ListType(cel.IntType)))
ast, _ := env.Compile(`items.map(x, x * x).size()`)
cost, _ := env.EstimateCost(ast, costEstimator{hints: map[string]uint64{"items": 5, "items.@items": 10}})
prg, _ := env.Program(ast, cel.CostTracking(runtimeEstimator{}), cel.CostLimit(1000))
out, details, _ := prg.Eval(map[string]any{"items": []int64{1, 2, 3}})
fmt.Println(out, *details.ActualCost())

Source code: example_cel_execution_cost_test.go


13. Advanced Topics: Error Handling & Name Resolution

Handling runtime errors and variable shadowing rules in macros:

Source code: example_cel_advanced_test.go


14. Go Native Structs (ext.NativeTypes)

Export Go structs into CEL and map struct field names using json, yaml, or cel struct tags:

type User struct {
	Name  string   `json:"name"`
	Age   int      `json:"age"`
	Roles []string `json:"roles"`
}

prg, _ := cel.Compile(`user.name == "Alice" && user.age >= 18`,
	cel.Variable("user", cel.ObjectType("examples.User")),
	ext.NativeTypes(reflect.TypeOf(User{}), ext.ParseStructTag("json")),
)
out, _, _ := prg.Eval(map[string]any{"user": User{Name: "Alice", Age: 30, Roles: []string{"admin"}}})
fmt.Println(out) // true

Source code: example_cel_native_structs_test.go


Running the Examples

Run all examples locally with go test:

go test -v ./examples/...

For interactive online examples, visit CEL by Example.