A lightweight rule parsing and evaluation library for Go. Define human-readable queries (e.g. score gt 100 and active eq true) and evaluate them against real-world data. Supports parentheses, logical operators (and, or, not), type annotations ([i64], [f64], [d], etc.), function calls, and more.
Key features
- Simple query language (operators like
eq,gt,lt,pr,in,co,sw,ew, etc.).- Built on ANTLR4 grammar.
- Support for typed values (
[i64]"123",[f64]"123.45",[d]"12.34") and typed comparisons (strict type checks).- Handle decimals via shopspring/decimal.
- Evaluate queries with dynamic data (like JSON objects, struct fields, or custom function results).
- Easily embed in your own projects and run rule-based filtering or validations.
go get github.com/sky93/go-ruleThere's a self-contained example in _example/simple/main.go.
Below is a short version:
package main
import (
"fmt"
"log"
"github.com/sky93/go-rule"
)
func main() {
// A simple query
input := `book_pages gt 100 and (language eq "en" or language eq "fr") and price pr and in_stock eq true`
// Parse the query
parsedRule, err := rule.ParseQuery(input, nil)
if err != nil {
log.Fatalf("Parse error: %v", err)
}
fmt.Println("Discovered parameters:")
// Prepare evaluations with actual data
values := []rule.Evaluation{
{
Param: parsedRule.Params[0], // e.g. "book_pages"
Result: 150,
},
{
Param: parsedRule.Params[1], // e.g. "language"
Result: "en",
},
{
Param: parsedRule.Params[2], // e.g. "price"
Result: 10.0,
},
{
Param: parsedRule.Params[3], // e.g. "in_stock"
Result: true,
},
}
// Evaluate
ok, err := parsedRule.Evaluate(values)
if err != nil {
log.Fatalf("Evaluation error: %v", err)
}
fmt.Printf("Evaluation => %v\n", ok)
}Output:
Discovered parameters:
... (various parameter info) ...
Evaluation => true
Use rule.ParseQuery(queryString, config) to parse a textual rule:
import "github.com/sky93/go-rule"
ruleSet, err := rule.ParseQuery(
`(usr_id eq 100 or usr_id eq 101) and amount gt [d]"12.34"`,
nil,
)
// ruleSet is a `Rule` struct with an internal expression tree + discovered Params.queryStringcan contain:- Comparison:
attrName operator value - Logical:
( ... ) and/or ( ... ), plusnot - Type annotation:
[i64]"123",[f64]"123.45",[d]"12.34",[ui](and more) - Presence:
someField pr(true if field is present) - String operators:
co(contains),sw(starts with),ew(ends with),in
- Comparison:
Parsing Errors
If the syntax is invalid, ParseQuery returns an error. For example, unbalanced parentheses or unknown tokens.
Once parsed, you get a rule.Rule that contains:
Params: The discovered parameters (name, operator, typed expression, etc.).
To evaluate:
- Identify each parameter in
ruleSet.Params. - Construct a slice of
rule.Evaluationitems, each linking a Param fromruleSet.Paramsto an actual Result from your data. - Call
ruleSet.Evaluate(evals []Evaluation)=> returns(bool, error).
ok, err := ruleSet.Evaluate([]rule.Evaluation{
{
Param: ruleSet.Params[0], // param with Name="age"
Result: 20,
},
{
Param: ruleSet.Params[1], // param with Name="can_drive"
Result: true,
},
})
fmt.Println(ok) // => true
fmt.Println(err) // => nilYou can specify a type annotation in the query, for example [i64]"123", [f64]"123.45", [d]"12.34".
Strict Type Checking:
If a query param is [f64]"123.45", the library enforces that your provided Result is float64, otherwise you'll get a type mismatch error.
Supported type annotations:
| Annotation | Meaning / Go Type |
|---|---|
[i64] |
int64 |
[ui64] |
uint64 |
[i] |
int |
[ui] |
uint |
[i32] |
int32 |
[ui32] |
uint32 |
[f64] |
float64 |
[f32] |
float32 |
[d] |
decimal.Decimal |
[s] |
string |
You can have queries like:
get_author("Song of Myself") eq "Walt Whitman"
Here:
get_authoris the function name."Song of Myself"is function argument.eqis equal operator."Walt Whitman"is the compare value.
ParseQuery sets Parameter.InputType = FunctionCall with Parameter.FunctionArguments.
For final evaluation, you must supply a single numeric/string/boolean (etc.) Result for Param:
// If we have: get_author("Song of Myself") eq "Walt Whitman"
param := ruleSet.Params[0]
// param.FunctionArguments => e.g. [ {ArgTypeString, Value: "Song of Myself"} ]
ok, err := ruleSet.Evaluate([]rule.Evaluation{
{
Param: param,
Result: "Walt Whitman", // the real function result
},
})
// => true| Operator | Meaning |
|---|---|
eq |
equals |
ne |
not equals |
gt |
greater than |
lt |
less than |
ge |
greater or equal |
le |
less or equal |
co |
contains (substring) |
sw |
starts with |
ew |
ends with |
in |
"in" check (substring) |
pr |
present (non-nil check) |
Logical: and, or, plus optional not prefix.
Parentheses: ( expr )
You can pass a config with DebugMode=true:
ruleSet, err := rule.ParseQuery(`age gt 18`, &rule.Config{DebugMode: true})
if err != nil {
log.Fatal(err)
}
// Evaluate => will print debug messages to stdoutSee ruleEngine_test.go for in-depth test scenarios:
- Decimal usage
- Complex boolean logic
- Strict type checking
- Absent parameters vs.
pr - Nested parentheses
- Function calls with arguments
- Error handling
Also, _example/simple/main.go shows a small command-line usage.
This repository includes unit tests in ruleEngine_test.go. Run them with:
go test ./...You’ll see coverage for query parsing, expression evaluation, typed operators, error handling, etc.
Browse all public functions, types, and methods on pkg.go.dev or read the doc comments in the source code.
This project is licensed under the MIT License.
Copyright © 2025 Sepehr Mohaghegh.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ... full MIT license text.
Logo Attribution & Dependencies
- The “goopher” logo is copied from avivcarmi.com.
- This library uses shopspring/decimal and ANTLR4 for Go.
