cel2sql - CEL から安全に複数 DB 向け SQL 条件を作る
Backend API を作っていると、結局いつも同じ問題にぶつかります。管理画面や internal tool から柔軟な filter 条件を渡したい。でも、毎回 if/else で SQL を組み立てるのはつらいし、生の SQL を受け付けるのはもっと危ない。欲しいのは、表現力はそこそこ高いのに、型と境界が崩れにくい条件表現です。
今日紹介したい SPANDigital/cel2sql は、その問題にかなり素直に答える project です。CEL(Common Expression Language) の式を SQL 条件へ変換し、PostgreSQL、MySQL、SQLite、DuckDB、BigQuery、Apache Spark SQL をサポートします。つまり、上位の system は CEL で filter を記述し、実際の database 向け SQL はこの library に任せる、という分離ができます。
公開時点の GitHub page では、project は約 37 stars、3 forks。主言語は Go、license は Apache-2.0 です。Repository の作成日は 2025-07-10、最新 release は v3.8.6、公開日は 2026-06-15 でした。
Project overview
| 項目 | 内容 |
|---|---|
| Repository | SPANDigital/cel2sql |
| 位置づけ | CEL 式を複数 SQL dialect の条件へ変換する library |
| Stars | 約 37 |
| Forks | 3 |
| 主要言語 | Go |
| License | Apache-2.0 |
| 対応 dialect | PostgreSQL、MySQL、SQLite、DuckDB、BigQuery、Spark SQL |
| Latest release | v3.8.6 |
解いているのは SQL 生成そのものより、制御された filter 公開
多くの service は SQL を書けないわけではありません。本当に困るのは、「柔軟な filter 条件をどう安全に外へ開くか」です。
ありがちな方法は、だいたい次のどれかです。
- filter 項目ごとに backend 側で分岐を増やし続ける。
- 独自 DSL を作るが、型も tooling も弱い。
- ひどい場合は SQL 断片を受け取ってしまう。
cel2sql はもっと筋の良い中間層を置きます。条件表現には CEL を使い、まず AST まで compile してから SQL に変換します。つまり、適当な文字列変換ではなく、構文と型の確認を先に通したうえで database dialect へ落とす設計です。
README の基本例も分かりやすいです。表 schema を定義し、CEL environment を作り、user.age >= 18 && user.active のような式を compile し、その結果を user.age >= 18 AND user.active IS TRUE のような SQL 条件に変えます。管理画面の filter、report API、rule engine、検索条件 API にはかなり相性がよさそうです。
一つの式から複数 dialect を出せるのが実務的
この project の実用性は、単に CEL を SQL にすることだけではなく、それを 複数 dialect に対してそろえているところにあります。
現時点での対応先は:
- PostgreSQL
- MySQL
- SQLite
- DuckDB
- BigQuery
- Apache Spark SQL
現実の system は、見た目以上に複数の database をまたぎます。主系は PostgreSQL でも、分析用に BigQuery、local test に SQLite や DuckDB、data processing に Spark を使うことは珍しくありません。そのたびに query layer を分岐させるのは面倒です。
cel2sql は filter expression を先に固定し、差分を dialect 実装側へ押し込めます。しかも最新の v3.8.6 では Spark SQL dialect が追加され、regex、JSON、array literal、一部の comprehension 相当まで含めて広げています。小さな utility に見えて、意外と本気で方言差分に向き合っています。
schema と type provider があるので文字列テンプレートで終わらない
こういう tool で一番不安なのは、結局 string template の延長なのではないか、という点です。
cel2sql はそこを schema と type provider で支えています。典型的な流れは:
- table schema を定義する。
- それを type provider に渡す。
- CEL environment に variable と object type を登録する。
- compile 段階で field や type を検査する。
これにより、少なくとも次のような問題を早い段階で見つけやすくなります。
- 存在しない field を参照している。
- 型の合わない比較をしている。
- 式の構文がおかしい。
さらに良いのは、schema を全部手で持たなくてもよい点です。docs/getting-started.md では NewTypeProviderWithConnection と LoadTableSchema が紹介されていて、database 接続から schema を読み込めます。実運用では schema の手書き同期はすぐ崩れるので、この方向はかなり助かります。
security boundary が最初から明文化されている
動的 filter を扱う tool で大事なのは、何が安全で何が利用者の責任かを曖昧にしないことです。
cel2sql の docs はこの点が比較的はっきりしています。標準で入っている防御として、たとえば:
- field name validation
- JSON field 名の escape
- regex ReDoS 防止
- expression depth の制限
contexttimeout の利用
が挙げられています。
つまり、ただ AST を SQL 文字列に展開するだけではなく、「user input 由来の式を production で扱う」前提で防御を積んでいます。
その一方で、docs は過剰に万能感を出していません。引き続き:
- 入力 validation を行うこと
- 実行時は prepared statement を使うこと
- 公開 field を絞ること
- 自分の edge case をテストすること
を勧めています。このバランスは好印象です。security tool というより、filter layer の安全性を底上げする部品として正直です。
JSON、配列、timestamp、logging まで含めて現実寄り
もしこの種の library が a > b 程度しか扱えないなら、実案件ではすぐ詰まります。
cel2sql の docs では、かなり現実寄りの例が並んでいます。
startsWithやcontains- timestamp 比較
- 配列の membership と長さ判定
- JSON/JSONB の扱い
- structured logging
- context による timeout と cancel
このあたりを見ると、作者は単なる parser ではなく、実際の query-facing component として育てています。
特に logging と timeout があるのは良いです。複雑な filter 条件は「なぜこういう SQL になったのか」を追いたくなるので、schema lookup や JSON path の判断が見える設計は運用上助かります。
向いている場面
cel2sql は次のような場面で特に合いそうです。
第一に、管理画面や internal platform で custom filter を提供したい backend API。項目追加のたびに endpoint を増やしたくない時に向いています。
第二に、rule engine や alert 条件、data 配信条件のような「表現式が必要な SaaS 機能」です。CEL を中間層にすると、完全に自由な SQL を渡すよりずっと扱いやすくなります。
第三に、同じ service が複数の database dialect をまたぐ場合です。OLTP は PostgreSQL、分析は BigQuery、local test は DuckDB や SQLite、という構成なら、一つの expression から出し分けられる価値は大きいです。
境界は理解して使うべき
もちろん、cel2sql は万能な query builder ではありません。
主に解くのは 条件式から SQL 条件への変換 です。最終的な SELECT 全体、JOIN 戦略、アクセス制御、どの table/field を許可するか、といった設計は依然として application 側の責任です。
また、CEL は生 SQL よりは安全に扱いやすいですが、一般ユーザーがそのまま素で書く UI が最適とは限りません。現実には form builder、preset、rule editor と組み合わせる方が自然だと思います。
まとめ
SPANDigital/cel2sql が良いのは、CEL を SQL に変えるという一点だけでなく、それを多方言、型認識、schema introspection、安全防御、logging、timeout を含む形でまとめているところです。
「柔軟な filter は欲しいが、SQL をそのまま表へ出したくない」という backend には、かなり実用的な小さめの project だと思います。