{"id":50812742,"url":"https://github.com/pgx-contrib/pgxcel","last_synced_at":"2026-06-13T06:33:43.281Z","repository":{"id":353894042,"uuid":"1221299053","full_name":"pgx-contrib/pgxcel","owner":"pgx-contrib","description":"CEL → PostgreSQL WHERE clause transpiler for pgx. Fail-closed column allow-list, parameterized $N placeholders.","archived":false,"fork":false,"pushed_at":"2026-06-08T02:40:50.000Z","size":48,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T04:21:41.699Z","etag":null,"topics":["cel","cel-go","filtering","go","golang","google-cel","pgx","postgres","postgresql","sql","transpiler","where-clause"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/pgx-contrib/pgxcel","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/pgx-contrib.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-04-26T02:32:57.000Z","updated_at":"2026-06-08T02:40:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pgx-contrib/pgxcel","commit_stats":null,"previous_names":["pgx-contrib/pgxcel"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pgx-contrib/pgxcel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgx-contrib%2Fpgxcel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgx-contrib%2Fpgxcel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgx-contrib%2Fpgxcel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgx-contrib%2Fpgxcel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pgx-contrib","download_url":"https://codeload.github.com/pgx-contrib/pgxcel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pgx-contrib%2Fpgxcel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34275068,"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-13T02:00:06.617Z","response_time":62,"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","cel-go","filtering","go","golang","google-cel","pgx","postgres","postgresql","sql","transpiler","where-clause"],"created_at":"2026-06-13T06:33:42.652Z","updated_at":"2026-06-13T06:33:43.276Z","avatar_url":"https://github.com/pgx-contrib.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pgxcel\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/pgx-contrib/pgxcel.svg)](https://pkg.go.dev/github.com/pgx-contrib/pgxcel)\n[![License](https://img.shields.io/github/license/pgx-contrib/pgxcel)](LICENSE)\n[![Go](https://img.shields.io/badge/Go-1.25-00ADD8?logo=go\u0026logoColor=white)](https://go.dev)\n\n`pgxcel` converts a checked [CEL](https://github.com/google/cel-go) AST into\na Postgres `WHERE` fragment with positional bind placeholders. It is\ndeliberately small: one walker over the standard CEL expression\nprotobuf, a fail-closed identifier allow-list, and `time.Time` /\n`time.Duration` bindings for the `timestamp(...)` / `duration(...)`\nliterals.\n\nThe package accepts any `*cel.Ast` regardless of how it was produced.\nThat includes ASTs translated back from an [AIP-160](https://google.aip.dev/160)\nfilter via `cel.CheckedExprToAst`, so the same transpiler powers both\ndirect CEL and AIP filtering on top of Postgres.\n\n## Installation\n\n```bash\ngo get github.com/pgx-contrib/pgxcel\n```\n\n## Usage\n\n```go\nenv, _ := cel.NewEnv(\n    cel.Variable(\"name\", cel.StringType),\n    cel.Variable(\"age\", cel.IntType),\n)\nast, iss := env.Compile(`name == \"Alice\" \u0026\u0026 age \u003e 30`)\nif iss.Err() != nil {\n    return iss.Err()\n}\n\ncolumns := map[string]string{\n    \"name\": \"users.name\",\n    \"age\":  \"users.age\",\n}\nwhere, args, err := pgxcel.Transpile(ast, pgxcel.WithColumns(columns))\n// where: (\"users\".\"name\" = $1 AND \"users\".\"age\" \u003e $2)\n// args:  []any{\"Alice\", int64(30)}\n```\n\n### Options\n\n- `pgxcel.WithColumns(map[string]string)` — the path → DB-column\n  allow-list. Lookup is **fail-closed**: any identifier the AST\n  references that is not in the map causes `Transpile` to return an\n  error. When omitted, every ident in the AST errors. **Never feed\n  user input as a column name**; the value of each map entry is\n  emitted into the SQL after only identifier quoting.\n- `pgxcel.WithFunctions(map[string]string)` — alias → canonical\n  function-name map applied before dispatch. Use it to feed in ASTs\n  produced by parsers other than cel-go (for example einride/aip-go\n  emits `\"=\"` / `\"AND\"` / `\"NOT\"` instead of the cel-go operator\n  names). Unknown aliases pass through unchanged.\n- `pgxcel.WithParamOffset(int)` — the first placeholder number.\n  Defaults to `1`. Use a higher value when splicing the fragment into\n  a query that already has bound values.\n\nA nil ast returns `(\"\", nil, nil)`. An unchecked ast\n(`ast.IsChecked() == false`) returns an error.\n\n## Operator coverage\n\n| CEL                                  | Postgres fragment                       |\n| ------------------------------------ | --------------------------------------- |\n| `==`, `!=`, `\u003c`, `\u003c=`, `\u003e`, `\u003e=`     | `col op $N` (or `col op col`)           |\n| `\u0026\u0026`, `\\|\\|`                         | `(lhs AND rhs)` / `(lhs OR rhs)`        |\n| `!`                                  | `(NOT expr)`                            |\n| `x in [a, b, c]`                     | `x IN ($1, $2, $3)` (empty → `FALSE`)   |\n| `s.contains(x)`                      | `s LIKE '%' \\|\\| $N \\|\\| '%'`           |\n| `s.startsWith(x)`                    | `s LIKE $N \\|\\| '%'`                    |\n| `s.endsWith(x)`                      | `s LIKE '%' \\|\\| $N`                    |\n| `s.matches(re)`                      | `s ~ $N` (POSIX regex)                  |\n| `timestamp(\"2025-01-02T03:04:05Z\")`  | `$N` bound as `time.Time`               |\n| `duration(\"1h30m\")`                  | `$N` bound as `time.Duration`           |\n| unary `-\u003cliteral\u003e`                   | bound as signed numeric literal         |\n\n## Development\n\n```bash\ngo test ./...\ngo vet ./...\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgx-contrib%2Fpgxcel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpgx-contrib%2Fpgxcel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpgx-contrib%2Fpgxcel/lists"}