blob: 2598b38d65085e3f6467723ca661eb99b3408816 [file] [edit]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ext
import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
)
// NativeTypesOption is a functional interface for configuring handling of native types.
type NativeTypesOption = types.NativeTypeOption
// NativeTypesFieldNameHandler is a handler for mapping a reflect.StructField to a CEL field name.
// This can be used to override the default Go struct field to CEL field name mapping.
type NativeTypesFieldNameHandler = types.NativeTypesFieldNameHandler
var (
// ParseStructTags configures if native types field names should be overridable by CEL struct tags.
// This is equivalent to ParseStructTag("cel")
ParseStructTags = types.ParseStructTags
// ParseStructTag configures the struct tag to parse. The 0th item in the tag is used as the name of the CEL field.
ParseStructTag = types.ParseStructTag
// ParseStructField configures how to parse Go struct fields. It can be used to customize struct field parsing.
ParseStructField = types.ParseStructField
)
// NativeTypesVersion sets the native types version support for native extensions functions.
//
// Deprecated: NativeTypesVersion is a no-op and will be removed in a future release.
func NativeTypesVersion(version uint32) NativeTypesOption {
return func(*types.NativeTypeOptions) error {
return nil
}
}
// NativeTypes creates a type provider which uses reflect.Type and reflect.Value instances
// to produce type definitions that can be used within CEL.
//
// All struct types in Go are exposed to CEL via their simple package name and struct type name:
//
// ```go
// package identity
//
// type Account struct {
// ID int
// }
//
// ```
//
// The type `identity.Account` would be exported to CEL using the same qualified name, e.g.
// `identity.Account{ID: 1234}` would create a new `Account` instance with the `ID` field
// populated.
//
// Only exported fields are exposed via NativeTypes, and the type-mapping between Go and CEL
// is as follows:
//
// | Go type | CEL type |
// |-------------------------------------|-----------|
// | bool | bool |
// | []byte | bytes |
// | float32, float64 | double |
// | int, int8, int16, int32, int64 | int |
// | string | string |
// | uint, uint8, uint16, uint32, uint64 | uint |
// | time.Duration | duration |
// | time.Time | timestamp |
// | array, slice | list |
// | map | map |
//
// Please note, if you intend to configure support for proto messages in addition to native
// types, you will need to provide the protobuf types before the golang native types. The
// same advice holds if you are using custom type adapters and type providers. The native type
// provider composes over whichever type adapter and provider is configured in the cel.Env at
// the time that it is invoked.
//
// There is also the possibility to rename the fields of native structs by setting the `cel` tag
// for fields you want to override. In order to enable this feature, pass in the `ParseStructTags(true)`
// option. Here is an example to see it in action:
//
// ```go
// package identity
//
// type Account struct {
// ID int
// OwnerName string `cel:"owner"`
// }
//
// ```
//
// The `OwnerName` field is now accessible in CEL via `owner`, e.g. `identity.Account{owner: 'bob'}`.
// In case there are duplicated field names in the struct, an error will be returned.
func NativeTypes(args ...any) cel.EnvOption {
return func(env *cel.Env) (*cel.Env, error) {
p, a, err := types.ComposeTypes(env.CELTypeProvider(), env.CELTypeAdapter(), args...)
if err != nil {
return nil, err
}
env, err = cel.CustomTypeAdapter(a)(env)
if err != nil {
return nil, err
}
return cel.CustomTypeProvider(p)(env)
}
}