{"id":26822814,"url":"https://github.com/sky93/go-rule","last_synced_at":"2025-03-30T08:28:24.558Z","repository":{"id":284063944,"uuid":"953603296","full_name":"sky93/go-rule","owner":"sky93","description":"Advanced rule engine in go","archived":false,"fork":false,"pushed_at":"2025-03-25T00:22:56.000Z","size":45,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T01:25:10.163Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sky93.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-23T18:28:28.000Z","updated_at":"2025-03-25T00:23:00.000Z","dependencies_parsed_at":"2025-03-25T01:25:12.855Z","dependency_job_id":"f8a8862e-c991-4a70-9fc2-ea6aa8747eda","html_url":"https://github.com/sky93/go-rule","commit_stats":null,"previous_names":["sky93/gorule","sky93/go-rule"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sky93%2Fgo-rule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sky93%2Fgo-rule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sky93%2Fgo-rule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sky93%2Fgo-rule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sky93","download_url":"https://codeload.github.com/sky93/go-rule/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246294686,"owners_count":20754493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-30T08:28:24.039Z","updated_at":"2025-03-30T08:28:24.545Z","avatar_url":"https://github.com/sky93.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"![go-rule logo](/logo.png)\n\n\n# go-rule\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/sky93/go-rule)](https://goreportcard.com/report/github.com/sky93/go-rule)\n![Go Version](https://img.shields.io/badge/go_version-1.23+-green)\n[![Coverage Status](https://coveralls.io/repos/github/sky93/go-rule/badge.svg)](https://coveralls.io/github/sky93/go-rule)\n[![Go Reference](https://pkg.go.dev/badge/github.com/sky93/go-rule.svg)](https://pkg.go.dev/github.com/sky93/go-rule)\n\nA **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.\n\n\u003e **Key features**\n\u003e - Simple query language (operators like `eq`, `gt`, `lt`, `pr`, `in`, `co`, `sw`, `ew`, etc.).\n\u003e - Built on [ANTLR4](https://github.com/antlr4-go/antlr) grammar.\n\u003e - Support for typed values (`[i64]\"123\"`, `[f64]\"123.45\"`, `[d]\"12.34\"`) and typed comparisons (strict type checks).\n\u003e - Handle decimals via [shopspring/decimal](https://github.com/shopspring/decimal).\n\u003e - Evaluate queries with dynamic data (like JSON objects, struct fields, or custom function results).\n\u003e - Easily embed in your own projects and run rule-based filtering or validations.\n\n---\n\n## Table of Contents\n\n1. [Installation](#installation)\n2. [Quick Start Example](#quick-start-example)\n3. [Usage](#usage)\n    - [Parsing Queries](#parsing-queries)\n    - [Evaluating a Parsed Rule](#evaluating-a-parsed-rule)\n    - [Working with Typed Values](#working-with-typed-values)\n    - [Function Calls](#function-calls)\n    - [Supported Operators](#supported-operators)\n    - [Debug/Logging](#debuglogging)\n4. [Advanced Examples](#advanced-examples)\n5. [Testing](#testing)\n6. [Full API Documentation](#full-api-documentation)\n7. [License](#license)\n\n---\n\n## Installation\n\n```bash\ngo get github.com/sky93/go-rule\n```\n\n---\n\n## Quick Start Example\n\nThere's a self-contained example in [`_example/simple/main.go`](./_example/simple/main.go).\n\nBelow is a short version:\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n\n    \"github.com/sky93/go-rule\"\n)\n\nfunc main() {\n    // A simple query\n    input := `book_pages gt 100 and (language eq \"en\" or language eq \"fr\") and price pr and in_stock eq true`\n\n    // Parse the query\n    parsedRule, err := rule.ParseQuery(input, nil)\n    if err != nil {\n        log.Fatalf(\"Parse error: %v\", err)\n    }\n\n    fmt.Println(\"Discovered parameters:\")\n    // Prepare evaluations with actual data\n    values := []rule.Evaluation{\n        {\n            Param:  parsedRule.Params[0], // e.g. \"book_pages\"\n            Result: 150,\n        },\n        {\n            Param:  parsedRule.Params[1], // e.g. \"language\"\n            Result: \"en\",\n        },\n        {\n            Param:  parsedRule.Params[2], // e.g. \"price\"\n            Result: 10.0,\n        },\n        {\n            Param:  parsedRule.Params[3], // e.g. \"in_stock\"\n            Result: true,\n        },\n    }\n\n    // Evaluate\n    ok, err := parsedRule.Evaluate(values)\n    if err != nil {\n        log.Fatalf(\"Evaluation error: %v\", err)\n    }\n    fmt.Printf(\"Evaluation =\u003e %v\\n\", ok)\n}\n```\n\n**Output**:\n```\nDiscovered parameters:\n ... (various parameter info) ...\nEvaluation =\u003e true\n```\n\n---\n\n## Usage\n\n### Parsing Queries\n\nUse `rule.ParseQuery(queryString, config)` to parse a textual rule:\n\n```go\nimport \"github.com/sky93/go-rule\"\n\nruleSet, err := rule.ParseQuery(\n    `(usr_id eq 100 or usr_id eq 101) and amount gt [d]\"12.34\"`, \n    nil,\n)\n// ruleSet is a `Rule` struct with an internal expression tree + discovered Params.\n```\n\n- **`queryString`** can contain:\n    - **Comparison**: `attrName operator value`\n    - **Logical**: `( ... ) and/or ( ... )`, plus `not`\n    - **Type annotation**: `[i64]\"123\"`, `[f64]\"123.45\"`, `[d]\"12.34\"`, `[ui]` (and more)\n    - **Presence**: `someField pr` (true if field is present)\n    - **String operators**: `co` (contains), `sw` (starts with), `ew` (ends with), `in`\n\n**Parsing Errors**  \nIf the syntax is invalid, `ParseQuery` returns an error. For example, unbalanced parentheses or unknown tokens.\n\n### Evaluating a Parsed Rule\n\nOnce parsed, you get a `rule.Rule` that contains:\n\n- `Params`: The discovered parameters (name, operator, typed expression, etc.).\n\nTo evaluate:\n\n1. **Identify each parameter** in `ruleSet.Params`.\n2. Construct a slice of `rule.Evaluation` items, each linking a **Param** from `ruleSet.Params` to an actual **Result** from your data.\n3. Call `ruleSet.Evaluate(evals []Evaluation)` =\u003e returns `(bool, error)`.\n\n```go\nok, err := ruleSet.Evaluate([]rule.Evaluation{\n    {\n        Param:  ruleSet.Params[0], // param with Name=\"age\"\n        Result: 20,\n    },\n    {\n        Param:  ruleSet.Params[1], // param with Name=\"can_drive\"\n        Result: true,\n    },\n})\nfmt.Println(ok)   // =\u003e true\nfmt.Println(err)  // =\u003e nil\n```\n\n### Working with Typed Values\n\nYou can specify a type annotation in the query, for example `[i64]\"123\"`, `[f64]\"123.45\"`, `[d]\"12.34\"`.\n\n**Strict Type Checking**:  \nIf a query param is `[f64]\"123.45\"`, the library enforces that your provided `Result` is `float64`, otherwise you'll get a type mismatch error.\n\n**Supported type annotations**:\n\n| Annotation | Meaning / Go Type                                          |\n|------------|------------------------------------------------------------|\n| `[i64]`    | `int64`                                                    |\n| `[ui64]`   | `uint64`                                                   |\n| `[i]`      | `int`                                                      |\n| `[ui]`     | `uint`                                                     |\n| `[i32]`    | `int32`                                                    |\n| `[ui32]`   | `uint32`                                                   |\n| `[f64]`    | `float64`                                                  |\n| `[f32]`    | `float32`                                                  |\n| `[d]`      | [`decimal.Decimal`](https://github.com/shopspring/decimal) |\n| `[s]`      | `string`                                                   |\n\n### Function Calls\n\nYou can have queries like:\n```\nget_author(\"Song of Myself\") eq \"Walt Whitman\"\n```\nHere:\n- `get_author` is the function name.\n- `\"Song of Myself\"` is function argument.\n- `eq` is equal operator.\n- `\"Walt Whitman\"` is the compare value.\n\n`ParseQuery` sets `Parameter.InputType = FunctionCall` with `Parameter.FunctionArguments`.  \nFor final evaluation, you must supply a single numeric/string/boolean (etc.) `Result` for `Param`:\n\n```go\n// If we have: get_author(\"Song of Myself\") eq \"Walt Whitman\"\nparam := ruleSet.Params[0]\n// param.FunctionArguments =\u003e e.g. [ {ArgTypeString, Value: \"Song of Myself\"} ]\n\nok, err := ruleSet.Evaluate([]rule.Evaluation{\n  {\n    Param:  param,\n    Result: \"Walt Whitman\", // the real function result\n  },\n})\n// =\u003e true\n```\n\n### Supported Operators\n\n| Operator | Meaning                  |\n|----------|--------------------------|\n| `eq`     | equals                   |\n| `ne`     | not equals               |\n| `gt`     | greater than             |\n| `lt`     | less than                |\n| `ge`     | greater or equal         |\n| `le`     | less or equal            |\n| `co`     | contains (substring)     |\n| `sw`     | starts with              |\n| `ew`     | ends with                |\n| `in`     | \"in\" check (substring)   |\n| `pr`     | present (non-nil check)  |\n\n**Logical**: `and`, `or`, plus optional `not` prefix.  \n**Parentheses**: `( expr )`\n\n### Debug/Logging\n\nYou can pass a config with `DebugMode=true`:\n\n```go\nruleSet, err := rule.ParseQuery(`age gt 18`, \u0026rule.Config{DebugMode: true})\nif err != nil {\n    log.Fatal(err)\n}\n// Evaluate =\u003e will print debug messages to stdout\n```\n\n---\n\n## Advanced Examples\n\nSee [`ruleEngine_test.go`](./ruleEngine_test.go) for in-depth test scenarios:\n- Decimal usage\n- Complex boolean logic\n- Strict type checking\n- Absent parameters vs. `pr`\n- Nested parentheses\n- Function calls with arguments\n- Error handling\n\nAlso, `_example/simple/main.go` shows a small command-line usage.\n\n---\n\n## Testing\n\nThis repository includes unit tests in `ruleEngine_test.go`. Run them with:\n\n```bash\ngo test ./...\n```\n\nYou’ll see coverage for query parsing, expression evaluation, typed operators, error handling, etc.\n\n---\n\n## Full API Documentation\n\nBrowse all public functions, types, and methods on **[pkg.go.dev](https://pkg.go.dev/github.com/sky93/go-rule)** or read the doc comments in the source code.\n\n---\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).  \nCopyright \u0026copy; 2025 [Sepehr Mohaghegh](https://github.com/sky93).\n\n\u003e Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ... [full MIT license text](./LICENSE).\n\n**Logo Attribution \u0026 Dependencies**\n- The “goopher” logo is copied from [avivcarmi.com](https://avivcarmi.com/we-need-to-talk-about-the-bad-sides-of-go/).\n- This library uses [shopspring/decimal](https://github.com/shopspring/decimal) and [ANTLR4 for Go](https://github.com/antlr4-go/antlr).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsky93%2Fgo-rule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsky93%2Fgo-rule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsky93%2Fgo-rule/lists"}