{"id":50769703,"url":"https://github.com/hbjydev/celdotnet","last_synced_at":"2026-06-11T17:01:30.693Z","repository":{"id":347549808,"uuid":"1194440783","full_name":"hbjydev/celdotnet","owner":"hbjydev","description":"A Common Expression Language (CEL) implementation for .NET that compiles CEL expressions into System.Linq.Expression trees","archived":false,"fork":false,"pushed_at":"2026-03-28T12:51:50.000Z","size":122,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T15:10:35.993Z","etag":null,"topics":["cel","dotnet","efcore","filtering"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hbjydev.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-28T11:08:37.000Z","updated_at":"2026-03-28T12:51:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hbjydev/celdotnet","commit_stats":null,"previous_names":["hbjydev/celdotnet"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/hbjydev/celdotnet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hbjydev%2Fceldotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hbjydev%2Fceldotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hbjydev%2Fceldotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hbjydev%2Fceldotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hbjydev","download_url":"https://codeload.github.com/hbjydev/celdotnet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hbjydev%2Fceldotnet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34208761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cel","dotnet","efcore","filtering"],"created_at":"2026-06-11T17:01:24.682Z","updated_at":"2026-06-11T17:01:30.577Z","avatar_url":"https://github.com/hbjydev.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CelDotNet\n\n[![CI](https://github.com/hbjydev/celdotnet/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/hbjydev/celdotnet/actions/workflows/ci.yml)\n[![NuGet Version](https://img.shields.io/nuget/v/CelDotNet?logo=nuget\u0026label=CelDotNet)](https://www.nuget.org/packages/CelDotNet)\n[![NuGet Version](https://img.shields.io/nuget/v/CelDotNet.EntityFrameworkCore?logo=nuget\u0026label=EntityFrameworkCore)](https://www.nuget.org/packages/CelDotNet.EntityFrameworkCore)\n\nA [Common Expression Language (CEL)](https://cel.dev) implementation for .NET that compiles CEL expressions into `System.Linq.Expression` trees -- making it possible to use CEL filters directly with Entity Framework Core, `IQueryable`, or in-memory evaluation.\n\nUnlike other .NET CEL libraries, CelDotNet doesn't just evaluate expressions -- it produces `Expression\u003cFunc\u003cT, bool\u003e\u003e`, which means your CEL filters can be translated all the way down to SQL. Zero protobuf dependency. Zero runtime dependencies in the core package.\n\n## Features\n\n* **CEL -\u003e Expression Trees** -- the first .NET CEL library to produce `Expression\u003cFunc\u003cT, bool\u003e\u003e`\n* **EF Core integration** -- CEL filters translate to SQL via the `CelDotNet.EntityFrameworkCore` package\n* **Optional type checking** -- catch errors at parse time with `CelEnvironment`\n* **Zero dependencies** -- the core package is entirely self-contained (hand-written lexer and parser)\n* **Full CEL grammar** -- arithmetic, logic, string functions, comprehension macros, ternary, `in`, `has()`, timestamps, durations, and more\n* **Field name resolution** -- automatic `snake_case` to `PascalCase` conversion, or explicit mapping via `[CelField]`\n\n## Installation\n\nInstall the core package from NuGet:\n\n```shell\ndotnet add package CelDotNet\n```\n\nFor EF Core integration:\n\n```shell\ndotnet add package CelDotNet.EntityFrameworkCore\n```\n\n## Quick Start\n\n### Basic Usage\n\nParse a CEL expression, then compile it against a .NET type:\n\n```csharp\nusing CelDotNet;\n\n// Parse a CEL expression\nvar expr = CelExpression.Parse(\"name == 'Alice' \u0026\u0026 age \u003e 21\");\n\n// Compile to an expression tree (for EF Core / IQueryable)\nExpression\u003cFunc\u003cPerson, bool\u003e\u003e predicate = expr.ToExpression\u003cPerson\u003e();\n\n// Or compile to a delegate (for in-memory evaluation)\nFunc\u003cPerson, bool\u003e compiled = expr.Compile\u003cPerson\u003e();\n\nvar result = people.Where(compiled).ToList();\n```\n\n### With Type Checking\n\nDeclare external variables and enable static type checking before compilation:\n\n```csharp\nusing CelDotNet;\nusing CelDotNet.Ast;\n\nvar env = new CelEnvironment()\n    .AddVariable(\"threshold\", CelType.Int)\n    .AddVariable(\"name\", CelType.String);\n\n// Type errors are caught here, not at runtime\nvar expr = CelExpression.Parse(\"age \u003e threshold\", env);\n```\n\nYou can also check types against a specific .NET type:\n\n```csharp\nvar expr = CelExpression.Parse(\"name == 'foo'\");\nvar result = expr.CheckTypes\u003cPerson\u003e();\n\nif (result.HasErrors)\n{\n    foreach (var error in result.Errors)\n        Console.WriteLine(error);\n}\n```\n\nType checking can be disabled if you'd prefer to rely on runtime errors:\n\n```csharp\nvar env = new CelEnvironment()\n    .DisableTypeChecking()\n    .AddVariable(\"threshold\", CelType.Int);\n```\n\n### EF Core Integration\n\nApply CEL filters directly to your `IQueryable` sources -- the expression gets translated to SQL:\n\n```csharp\nusing CelDotNet.EntityFrameworkCore;\n\nvar results = await db.People\n    .WhereCel(\"name == 'Alice' \u0026\u0026 age \u003e 21\")\n    .ToListAsync();\n```\n\nWith an environment for type checking and external variables:\n\n```csharp\nvar env = new CelEnvironment()\n    .AddVariable(\"min_age\", typeof(int));\n\nvar results = await db.People\n    .WhereCel(\"age \u003e min_age\", env)\n    .ToListAsync();\n```\n\n**Note:** Some CEL features (e.g. complex map operations, byte arrays) can't be translated to SQL. The EF Core package will throw a `CelTranslationException` for non-translatable expressions. The full CEL spec is supported for in-memory evaluation via `.Compile\u003cT\u003e()`.\n\n### Field Name Mapping\n\nCelDotNet resolves CEL field names to .NET properties in the following priority order:\n\n1. `[CelField(\"name\")]` attribute on the property\n2. Exact property name match\n3. Automatic `snake_case` to `PascalCase` conversion\n\n```csharp\nusing CelDotNet;\n\npublic class Person\n{\n    [CelField(\"first_name\")]\n    public string FirstName { get; set; }\n\n    public int Age { get; set; }\n}\n\n// Both of these work:\n// \"first_name == 'Alice'\"  -\u003e resolves via [CelField]\n// \"age \u003e 21\"               -\u003e resolves via snake_case -\u003e PascalCase\n```\n\n### Field Visibility Mapping\n\nCelDotNet provides the ability to mark some fields on a class or record as\n'visible' or not, which makes the field get skipped during expression\ncompilation.\n\n```csharp\nusing CelDotNet;\n\npublic class Person\n{\n    // Included in .WhereCel()\n    [CelField(visible: true)]\n    public string Username { get; set; }\n\n    // Excluded from .WhereCel()\n    [CelField(visible: false)]\n    public string PasswordHash { get; set; }\n}\n```\n\n## Supported CEL Features\n\n### Types\n\n| CEL Type | .NET Type |\n|----------|-----------|\n| `int` | `long` / `int` |\n| `uint` | `ulong` |\n| `double` | `double` |\n| `bool` | `bool` |\n| `string` | `string` |\n| `bytes` | `byte[]` |\n| `list` | `IEnumerable\u003cT\u003e` |\n| `map` | `IDictionary\u003cK,V\u003e` |\n| `null_type` | `null` |\n| `timestamp` | `DateTimeOffset` |\n| `duration` | `TimeSpan` |\n\n### Operators\n\nArithmetic (`+`, `-`, `*`, `/`, `%`), comparison (`==`, `!=`, `\u003c`, `\u003c=`, `\u003e`, `\u003e=`), logical (`\u0026\u0026`, `||`, `!`), ternary (`? :`), and membership (`in`).\n\n### String Functions\n\n`contains()`, `startsWith()`, `endsWith()`, `size()`, `matches()` (regex).\n\n### Macros\n\n`has()`, `all()`, `exists()`, `exists_one()`, `filter()`, `map()`.\n\n### Type Conversions\n\n`int()`, `uint()`, `double()`, `string()`, `bool()`.\n\n### Expression Tree Mappings\n\n| CEL | Expression Tree | EF Core SQL |\n|-----|-----------------|-------------|\n| `x.name == \"foo\"` | `Expression.Equal(prop, c)` | `WHERE Name = 'foo'` |\n| `x \u0026\u0026 y` | `Expression.AndAlso()` | `AND` |\n| `x \\|\\| y` | `Expression.OrElse()` | `OR` |\n| `val in [1,2,3]` | `Enumerable.Contains()` | `WHERE val IN (1,2,3)` |\n| `name.contains(\"x\")` | `string.Contains()` | `LIKE '%x%'` |\n| `name.startsWith(\"x\")` | `string.StartsWith()` | `LIKE 'x%'` |\n| `items.exists(x, p)` | `Enumerable.Any(lambda)` | `EXISTS (subquery)` |\n| `items.all(x, p)` | `Enumerable.All(lambda)` | `NOT EXISTS (NOT subquery)` |\n| `has(x.field)` | `x.Field != null` | `IS NOT NULL` |\n| `condition ? a : b` | `Expression.Condition()` | `CASE WHEN ... THEN ... ELSE` |\n\n## Architecture\n\n```\nCEL string\n  -\u003e Lexer -\u003e Token[]\n  -\u003e Parser -\u003e CelExpr (AST)\n  -\u003e [TypeChecker] (optional)\n  -\u003e ExpressionCompiler -\u003e Expression\u003cFunc\u003cT, bool\u003e\u003e\n                        -\u003e .Compile() -\u003e Func\u003cT, bool\u003e\n```\n\nThe pipeline is designed so that each stage is independent and testable. The type checker is optional and can be bypassed entirely if you prefer runtime-only error handling.\n\n## Comparison with Other .NET CEL Libraries\n\n| Library | Expression Trees? | Protobuf Required? | Maturity |\n|---------|-------------------|-------------------|----------|\n| [Cel (TELUS)](https://github.com/telus/cel-net) | No | Yes | Most mature |\n| Cel.NET | No | Yes | Mature |\n| Cel.Compiled | No (delegates) | No | Early |\n| **CelDotNet** | **Yes** | **No** | In development |\n\n## Licence\n\nApache-2.0. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhbjydev%2Fceldotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhbjydev%2Fceldotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhbjydev%2Fceldotnet/lists"}