Documentation
¶
Overview ¶
Package regobrick provides high-level functions for applying RegoBrick transformations and adding modules to OPA rego.Rego objects.
Custom builtin type conversion ¶
The Go types in a RegisterBuiltinX signature determine the Rego types the builtin is declared with, and every argument and return value is converted at the boundary through JSON.
Go type Rego type Round-trip characteristics
string string verbatim, except for control characters (see below)
bool boolean verbatim
int, int64, ... number exact within the Go type's range, except uint64
return values above 2^63-1 (see below); a number
with a fractional part is rejected, not truncated
float64 number rounded to float64 precision; large magnitudes
serialize in exponent notation (see below)
float32 number rounded to float32 precision; serialized in plain
decimal notation
json.Number, Number number digits preserved exactly in both directions;
declare these when precision matters
time.Time string RFC3339 in both directions
struct object keys are the JSON tags
[]T array a nil slice returns null, an empty slice returns []
map[string]T object a nil map returns null
pointer pointed-to a nil pointer returns null
any any any Rego value representable as JSON, which excludes sets
Every scalar row above is declared to OPA with its concrete Rego type — including time.Time, which is declared as string — so a mismatched call is rejected at compile time, before evaluation. The composite rows (struct, []T, map[string]T, pointer, any) are declared as any, so their shape is checked only while converting, at evaluation time.
Custom builtin conversion limits ¶
Argument conversion decodes each argument's Rego representation as JSON, so a Rego value whose representation is not JSON cannot reach a builtin at all. The declared Go parameter type does not change this: the failure happens before the Go type is involved.
- Sets cannot be passed as arguments. A set's representation ({1, 2, 3}) is not valid JSON, so the call fails — default mode: no result; rego.StrictBuiltinErrors(true): eval_builtin_error with "invalid character '1' looking for beginning of object key string". This also applies to a set nested inside an object or array argument. Convert the set to an array before passing it.
- Strings containing control characters cannot be passed as arguments. Rego string representations are Go-quoted, so U+0001 becomes \x01 and U+0007 becomes \a — escapes JSON does not have. The call fails the same way, with "invalid character 'x' in string escape code". Escapes shared with JSON (\n, \t, ...) and printable non-ASCII text are unaffected.
On the return side, two numeric conversions do not preserve what the Go value held:
- Returned float64 values are formatted with Go's shortest round-trip float formatting, so a builtin returning float64(9007199254740993) yields 9.007199254740992e+15: the lost digit is float64's own precision limit, the notation is the formatting.
- Returned uint64 values above 2^63-1 come back negative. OPA narrows a returned uint64 to a signed int before building the Rego number (v1.11.0, ast/interning.go), so uint64(1 << 63) reaches the policy as -9223372036854775808 and uint64(math.MaxUint64) as -1, with no error raised anywhere. Arguments are not affected — a uint64 parameter receives 18446744073709551615 intact — and neither is uint, which takes a different conversion route.
Declare json.Number or Number to get exact decimal digits in both cases.
Index ¶
- func FilterCapabilities(allowedNames []string, allowedCats []string) *ast.Capabilities
- func Module(filename, src string, imports []string) func(*rego.Rego)
- func Modules(opts ...ModuleOption) func(*rego.Rego)
- func ParseModule(filename, src string, imports []string) (*ast.Module, error)
- func RegisterBuiltin0[R any](name string, fn func(rego.BuiltinContext) (R, error), ...)
- func RegisterBuiltin0_(name string, fn func(rego.BuiltinContext) error, opts ...BuiltinRegisterOption)
- func RegisterBuiltin1[T1 any, R any](name string, fn func(rego.BuiltinContext, T1) (R, error), ...)
- func RegisterBuiltin1_[T1 any](name string, fn func(rego.BuiltinContext, T1) error, ...)
- func RegisterBuiltin2[T1 any, T2 any, R any](name string, fn func(rego.BuiltinContext, T1, T2) (R, error), ...)
- func RegisterBuiltin2_[T1 any, T2 any](name string, fn func(rego.BuiltinContext, T1, T2) error, ...)
- func RegisterBuiltin3[T1 any, T2 any, T3 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3) (R, error), ...)
- func RegisterBuiltin3_[T1 any, T2 any, T3 any](name string, fn func(rego.BuiltinContext, T1, T2, T3) error, ...)
- func RegisterBuiltin4[T1 any, T2 any, T3 any, T4 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4) (R, error), ...)
- func RegisterBuiltin4_[T1 any, T2 any, T3 any, T4 any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4) error, ...)
- func RegisterBuiltin5[T1 any, T2 any, T3 any, T4 any, T5 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4, T5) (R, error), ...)
- func RegisterBuiltin5_[T1 any, T2 any, T3 any, T4 any, T5 any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4, T5) error, ...)
- func UseDecimalArithmetic(opts ...DecimalArithmeticOption)
- type BuiltinRegisterOption
- type DecimalArithmeticOption
- type ModuleOption
- type Number
- type RegoDecimaldeprecated
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FilterCapabilities ¶ added in v0.3.0
func FilterCapabilities(allowedNames []string, allowedCats []string) *ast.Capabilities
FilterCapabilities filters OPA built-in functions based on a list of allowed names and categories, along with built-ins whose infix is in coreInfixes.
- If a built-in's infix is one of the core infixes, it is kept.
- Otherwise, if the built-in name is in allowedNames or any of its categories are in allowedCats, it is kept.
- If a built-in has custom category mappings, those are also checked against allowedCats.
The resulting capabilities object contains only the filtered built-ins.
Call order contract: custom builtins registered via RegisterBuiltinX must be registered (typically from init) before FilterCapabilities is called, so that their category mappings are already recorded. Only then can those custom builtins be matched and included by their categories.
func Module ¶
Module returns a rego.Rego option that adds a single Rego module from the given filename, source, and optional imports.
Fail-fast contract: if the module cannot be processed, Module panics with a message like `regobrick: cannot process module "<filename>": <cause>` UNLESS the caller requested nothing regobrick-specific (imports is empty AND the source does not reference any "data.regobrick." feature). In that case Module falls back to rego.Module(filename, src), preserving plain (including v0) workflows. If you want to handle errors yourself instead of risking a panic, call ParseModule and pass the resulting *ast.Module to rego.ParsedModule(...).
func Modules ¶ added in v0.5.0
func Modules(opts ...ModuleOption) func(*rego.Rego)
Modules returns a rego.Rego option that adds multiple Rego modules in one call, each specified via a ModuleOption. It follows the same fail-fast contract as Module: a module that requested regobrick behavior but failed to parse causes a panic, while a fully plain module falls back to rego.Module.
func ParseModule ¶
ParseModule parses a Rego source file into an AST module, optionally appending additional imports. If the module includes "import data.regobrick.default_false", it applies the default_false transform. METADATA annotations are preserved.
Any "data.regobrick.*" marker import is stripped from the returned module: it only triggers transforms and would otherwise be an unused import. This is observable to callers using rego.Strict(true), which rejects unused imports.
ParseModule never panics; it returns an error for parse failures, invalid injected import paths, import name conflicts, or unknown regobrick features.
func RegisterBuiltin0 ¶ added in v0.2.0
func RegisterBuiltin0[R any](name string, fn func(rego.BuiltinContext) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin0 registers a builtin with no arguments. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin0_ ¶ added in v0.2.0
func RegisterBuiltin0_(name string, fn func(rego.BuiltinContext) error, opts ...BuiltinRegisterOption)
RegisterBuiltin0_ registers a builtin with no arguments that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin1 ¶ added in v0.2.0
func RegisterBuiltin1[T1 any, R any](name string, fn func(rego.BuiltinContext, T1) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin1 registers a builtin with 1 argument. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
For how argument and return types map to Rego types, and which Rego values cannot be converted, see the package documentation: "Custom builtin type conversion" and "Custom builtin conversion limits". The same rules apply to every RegisterBuiltinX arity.
func RegisterBuiltin1_ ¶ added in v0.2.0
func RegisterBuiltin1_[T1 any](name string, fn func(rego.BuiltinContext, T1) error, opts ...BuiltinRegisterOption)
RegisterBuiltin1_ registers a builtin with 1 argument that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
For how argument types map to Rego types, and which Rego values cannot be converted, see the package documentation: "Custom builtin type conversion" and "Custom builtin conversion limits". The same rules apply to every RegisterBuiltinX_ arity.
func RegisterBuiltin2 ¶ added in v0.2.0
func RegisterBuiltin2[T1 any, T2 any, R any](name string, fn func(rego.BuiltinContext, T1, T2) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin2 registers a builtin with 2 arguments. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin2_ ¶ added in v0.2.0
func RegisterBuiltin2_[T1 any, T2 any](name string, fn func(rego.BuiltinContext, T1, T2) error, opts ...BuiltinRegisterOption)
RegisterBuiltin2_ registers a builtin with 2 arguments that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin3 ¶ added in v0.2.0
func RegisterBuiltin3[T1 any, T2 any, T3 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin3 registers a builtin with 3 arguments. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin3_ ¶ added in v0.2.0
func RegisterBuiltin3_[T1 any, T2 any, T3 any](name string, fn func(rego.BuiltinContext, T1, T2, T3) error, opts ...BuiltinRegisterOption)
RegisterBuiltin3_ registers a builtin with 3 arguments that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin4 ¶ added in v0.2.0
func RegisterBuiltin4[T1 any, T2 any, T3 any, T4 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin4 registers a builtin with 4 arguments. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin4_ ¶ added in v0.2.0
func RegisterBuiltin4_[T1 any, T2 any, T3 any, T4 any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4) error, opts ...BuiltinRegisterOption)
RegisterBuiltin4_ registers a builtin with 4 arguments that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin5 ¶ added in v0.2.0
func RegisterBuiltin5[T1 any, T2 any, T3 any, T4 any, T5 any, R any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4, T5) (R, error), opts ...BuiltinRegisterOption)
RegisterBuiltin5 registers a builtin with 5 arguments. Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func RegisterBuiltin5_ ¶ added in v0.2.0
func RegisterBuiltin5_[T1 any, T2 any, T3 any, T4 any, T5 any](name string, fn func(rego.BuiltinContext, T1, T2, T3, T4, T5) error, opts ...BuiltinRegisterOption)
RegisterBuiltin5_ registers a builtin with 5 arguments that returns only an error (null to Rego). Must be called during package initialization (init function). Calling after initialization may cause race conditions.
func UseDecimalArithmetic ¶ added in v0.7.0
func UseDecimalArithmetic(opts ...DecimalArithmeticOption)
UseDecimalArithmetic replaces Rego's numeric operations with precision decimal operations.
Overloaded operators ¶
- Arithmetic: +, -, *, /, %
- Comparison: >, >=, <, <=, ==, !=
- Unary: abs(), round(), ceil(), floor()
- Aggregates: sum(), product(), max(), min()
Standard OPA differences ¶
Standard OPA comparison operators (>, <, >=, <=) support all types using type ordering (null < bool < number < string < ...). With UseDecimalArithmetic, comparison operators become numeric-only, and non-numeric string comparisons ("a" < "b") will not work.
The % (rem) operator accepts decimal operands (e.g. 10.5 % 3), whereas standard OPA restricts modulo to integers.
Precision limits (udecimal) ¶
- Maximum 19 decimal places; values with more fail to parse (default mode: no result; StrictBuiltinErrors: eval error). Truncation (not rounding) applies only to operation results, e.g. 100/3.
- Magnitude: coefficients up to 128 bits (±34,028,236,692,093,846,346.3374607431768211455 at the full 19 decimal places) stay on udecimal's zero-allocation fast path; larger plain-notation values fall back to udecimal's exact big.Int arithmetic instead of failing, up to udecimal's input hard cap of 200 characters per number string, beyond which parsing fails.
- Exponent notation is expanded to plain notation before parsing under a 64-character (≈62-digit) budget: 1e61 parses, 1e62 and beyond (e.g. 1e100) fail, while the same magnitude written out in plain notation parses fine.
Error handling ¶
- Default mode: operation failure results in rule not satisfied (no result)
- StrictBuiltinErrors(true): returns eval_builtin_error
Options ¶
- WithStringCoercion(): auto-convert numeric strings to numbers
Usage ¶
// Basic precision arithmetic regobrick.UseDecimalArithmetic() // With string-to-number coercion regobrick.UseDecimalArithmetic(regobrick.WithStringCoercion())
Concurrency ¶
Call this once at application startup, before any evaluation begins.
It writes two pieces of process-global state, with different guarantees. The coercion setting is stored atomically, so a late call cannot corrupt the flag reads on the evaluation path. OPA's builtin function registry, however, is rewritten without synchronization. Calling this concurrently with evaluation therefore remains unsafe, and "once at startup" is the contract rather than just a recommendation.
Fail-fast on changed udecimal defaults ¶
The parsing contract documented above relies on udecimal's default global settings. This function verifies them on entry: a 19-decimal-place value must parse, and a 20-decimal-place value must fail to parse. If either check fails — as it would after a udecimal.SetDefaultPrecision or udecimal.SetDefaultParseMode call elsewhere in the process — it panics with a message starting "regobrick: udecimal default settings have been changed", rather than silently degrading precision or truncating.
The check is a snapshot taken at call time. Changing udecimal's defaults after this function returns cannot be detected, and would silently change the contract.
Types ¶
type BuiltinRegisterOption ¶ added in v0.4.0
type BuiltinRegisterOption func(*builtinRegisterConfig)
BuiltinRegisterOption configures how a builtin is registered by the RegisterBuiltinX / RegisterBuiltinX_ functions. Pass any number of these options to attach categories or customize the underlying rego.Function.
func ConfigureFunction ¶ added in v0.7.0
func ConfigureFunction(configurator func(*rego.Function)) BuiltinRegisterOption
ConfigureFunction allows direct configuration of the rego.Function before registration. Use this for advanced options not directly supported by other options. Passing nil is a no-op.
func WithCategories ¶ added in v0.4.0
func WithCategories(cats ...string) BuiltinRegisterOption
WithCategories assigns one or more categories to the registered builtin. These categories are stored per builtin name and consulted by FilterCapabilities: a filtered capabilities set keeps a custom builtin when one of its categories is in the allowed category list.
func WithMemoize ¶ added in v0.7.0
func WithMemoize() BuiltinRegisterOption
WithMemoize enables memoization for the builtin. Memoized builtins cache results for the same inputs within a single evaluation.
func WithNondeterministic ¶ added in v0.4.0
func WithNondeterministic() BuiltinRegisterOption
WithNondeterministic marks the builtin as nondeterministic. Nondeterministic builtins may return different results for the same inputs.
type DecimalArithmeticOption ¶ added in v0.8.0
type DecimalArithmeticOption func(*decimalArithmeticConfig)
DecimalArithmeticOption configures UseDecimalArithmetic behavior.
func WithStringCoercion ¶ added in v0.8.0
func WithStringCoercion() DecimalArithmeticOption
WithStringCoercion enables automatic string-to-number coercion.
Numeric strings (e.g., "0.73", "100") from input or data are automatically converted to numbers in arithmetic, comparison, unary, and aggregate operations.
- Applied to: +, -, *, /, %, >, >=, <, <=, abs, round, ceil, floor, sum, product, max, min
- NOT applied to: ==, != (different types are always unequal — standard OPA behavior)
- Non-numeric strings ("abc"): operation fails (undefined or eval error)
String coercion is primarily intended for runtime values from input/data. Arithmetic, unary, and the sum/product aggregates declare numeric operand types, so string literals in Rego source code (e.g., "0.73" + 1, sum(["0.1"])) are rejected by OPA's compile-time type checker before our runtime coercion logic runs. This does not apply to max/min, whose operand is an Any collection: such literals reach runtime, where non-numeric or mixed collections fall back to the default comparison ordering.
type ModuleOption ¶ added in v0.5.0
type ModuleOption = module.ModuleOption
ModuleOption is an alias for module.ModuleOption, used for specifying Rego module parameters or configuration.
type Number ¶ added in v0.7.0
Number is a numeric representation passed to Rego. It is emitted as a numeric literal during JSON serialization and integrates directly with numeric DB columns.
Contract:
- Exponent notation (e/E) is supported. In UseDecimalArithmetic() operations it is expanded to plain decimal notation before parsing (e.g. "1e-8" → "0.00000001"), so it behaves the same as standard OPA. However, if the expanded result exceeds udecimal's precision (19 decimal places, e.g. "1e-25"), evaluation still fails with a parse error.
- Input validity is the provider's responsibility; regobrick validates only at operation time.
- DB Scan accepts string, []byte, int64, and float64.
- Preserving the precision of DECIMAL columns is the driver's responsibility (it must return string/[]byte). Verifying this up front with a driver integrity test is recommended.
NULL/empty handling (json.Number and decimal library conventions):
- JSON: null → empty string, empty string → emitted as 0 (Go zero-value convention)
- DB: NULL/empty → error (decimal library convention)
Example:
input := map[string]any{
"price": regobrick.Number("123.45"),
}
func (Number) MarshalJSON ¶ added in v0.7.1
MarshalJSON emits a JSON numeric literal (without quotes). json.Number emits an empty string ("") as 0 (Go convention: the zero value is valid).
func (*Number) Scan ¶ added in v0.7.1
Scan implements sql.Scanner, reading a numeric column from the DB. NULL/empty values return an error (a convention of decimal libraries such as udecimal and shopspring).
func (*Number) UnmarshalJSON ¶ added in v0.7.1
UnmarshalJSON parses a JSON number. json.Number treats null as an empty string (""). An empty string is emitted as 0 by MarshalJSON.
type RegoDecimal
deprecated
added in
v0.6.0
type RegoDecimal = types.RegoDecimal
RegoDecimal is an alias for types.RegoDecimal. It represents a numeric value that serializes to JSON as a numeric literal (e.g., 123.456) rather than a string (e.g., "123.456").
Deprecated: Use Number instead. RegoDecimal will be removed in a future version.
func NewRegoDecimal
deprecated
added in
v0.6.0
func NewRegoDecimal(d decimal.Decimal) RegoDecimal
NewRegoDecimal creates a RegoDecimal from an existing decimal.Decimal value. The resulting RegoDecimal retains the same precision and scale.
Deprecated: Use Number(d.String()) instead.
func NewRegoDecimalFromInt
deprecated
added in
v0.6.0
func NewRegoDecimalFromInt(i int64) RegoDecimal
NewRegoDecimalFromInt creates a RegoDecimal from an int64. This is a shortcut for decimal.NewFromInt(...) wrapped in a RegoDecimal.
Deprecated: Use Number(strconv.FormatInt(i, 10)) instead.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
bench/benchcommon
Package benchcommon holds the policy sources, inputs and runner shared by the standard-OPA and decimal-mode benchmark packages.
|
Package benchcommon holds the policy sources, inputs and runner shared by the standard-OPA and decimal-mode benchmark packages. |
|
module
Package module provides utilities for parsing and transforming Rego modules, particularly for detecting and applying regobrick features like "default_false".
|
Package module provides utilities for parsing and transforming Rego modules, particularly for detecting and applying regobrick features like "default_false". |
|
types
Package types provides wrappers around shopspring/decimal.
|
Package types provides wrappers around shopspring/decimal. |