google / cel-go

Fast, portable, non-Turing complete expression evaluation with gradual typing (Go)
https://cel.dev
Apache License 2.0
2.31k stars 225 forks source link

Using native Go struct for variable declaration #1065

Closed danlinxie closed 2 weeks ago

danlinxie commented 2 weeks ago

Hi folks! I'm new to the library and curious if there's any way to make CEL support a native Go struct in program environment?

Here's my use case in mind:

type UserAgent struct {
    DeviceAppLanguage string
    DeviceOs          string
        // other fields...
}

// evaluate: `UserAgent.DeviceOs == "ios" && UserAgent.DeviceAppLanguage == "en"`

From my understand, I'd have to generate protobuf go struct from something like:

syntax = "proto3";

package main;

option go_package = ".;main";

message UserAgent {
  string DeviceAppLanguage = 1;
  string DeviceOs = 2;
}

And apply it to program env:

env, err := cel.NewEnv(
    cel.Types(&UserAgent{}),
    cel.Variable("UserAgent", cel.ObjectType("main.UserAgent")),
)

Is this the expected setup for using a strongly typed object with CEL? or there is something simpler (e.g. not involving protobuf)?

TristonianJones commented 2 weeks ago

Hi @danlinxie,

You may want to consider using ext/native.go as a way of enabling the use of Go structs in CEL which is ext.NativeTypes(&UserAgent{}) where the UserAgent refers to your Go struct.

You may find this test setup useful:

https://github.com/google/cel-go/blob/f8ecaa2a9a5ec4e9585e92794e66bef7cceb41b8/ext/native_test.go#L947-L955

-Tristan

danlinxie commented 2 weeks ago

Thank you @TristonianJones! This is working great:

env, err := cel.NewEnv(
    ext.NativeTypes(reflect.TypeOf(&UserAgent{})),
    cel.Variable("UserAgent", cel.ObjectType("main.UserAgent")),
)