Upgrade to Pro — share decks privately, control downloads, hide ads and more …

go-sqletch

Avatar for moznion moznion
October 09, 2026

 go-sqletch

kamakura.go #10 の資料です
#kamakurago

Avatar for moznion

moznion

October 09, 2026

More Decks by moznion

Other Decks in Technology

Transcript

  1. moznion/go-sqletch sqletch (スケッチ / skétʃ) SQL (的なテンプレート) を書くことでGoのコードを⽣成するライブラリ 特徴 1:

    静的検証 特徴 2: 動的クエリ⽣成 特徴 3: 型機構 静的に検証が可能 ダイナミックなSQL構築 ⼿厚い型のサポート コンパイル時‧事前チェックにより、 構⽂‧識別⼦‧型の正当性を検証 できる。 その動的な仕組みを、⽣成されるGo コード上でもそのまま取り扱い可能。 パラメータ型と結果型は実 DB の oracle から取得する。 non-nullable columnにはNULLが混⼊ しない。 誤解を恐れずざっくり⾔うと: 動的なsqlc + 様々な付随機能 © Timeleap Inc. 4
  2. 参考: 使える制御構⽂ 構文 用途 @if-present(p, …) … @endif 指定したパラメータがすべて渡されたときだけ中の断片を含める @choose(p)

    / @case(value) / @default / @end 閉じた enum パラメータで、どれか一つの case を選ぶ @when(p op literal) … @end 値が条件に合うときだけ中の断片を含める @filter-tree(p) / @predicate(name) … @end 閉じた述語の集合を AND/OR で自由に組み合わせた条件木 @order-by(p) / @key(name) … (@default) … @end 複数キーのソート expr @in(:p) 要素数が可変の IN © Timeleap Inc. 7
  3. SQLテンプレートの記法にダイナミックさが欲しい 例: クエリに与えるパラメータに応じてクエリを変更したい場合 よくあるイディオム👇 悪くはないが…… • 実⾏計画が悪くなりがち ◦ $1 IS

    NULL OR col = $1 が前提となるのでindexを使いにくい • 可読性が落ちる (イディオムのほうが占める⽂量が多い……) † あと原理的に書けない‧性能が出ないものが⾊々ある (「組織IDが指定されたときだけ JOIN する」とか「ソート順の選択 (CASEを使うやつ)」など) © Timeleap Inc. 11
  4. クエリの静的検証 よって⽣成器はそれぞれのノードを独⽴して検証するようにしている 検証モデル 独⽴検証結果の合成メカニズム 前提条件 各ノードの結果を合成することで、全体検証が可能 性能メリット 計算コストの増加を線形(O(N))に担保 ※ 今回の検証ノード数

    = 4 この検証機構は構造ルールと少数のレンダリング検証の 組み合わせで静的に保証している TIPS: --exhaustiveオプションを使うと全組合せをtest DB上で PREPAREとPLANを実⾏し、検証することが可能 © Timeleap Inc. 26
  5. Goコードから適切な型とともにクエリを操作したい 01 SQLテンプレートから全ノードを有効にしたクエリをレンダリング Type Oracle: 実⾏するクエリをベースとして型情 報を取得する仕組み test DB (実DB)

    に対し1のクエリを prepare/describe して以下を取得: • • • 02 実際の DB 接続と静的解析を組み合わせ、型 安全な Go コードの⾃動⽣成を実現する。 ⽬的 動的な SQL テンプレートから厳密な型情報を抽 出‧検証する (DDL分析器を書かずに済ませるために実DBを使 うようにしている) パラメータの型 / 結果列の名前と型 各列のテーブル上定義(nullability判定に使⽤) ※ MySQL / SQLite はパラメータ型⾮返却のためテンプレート注釈で付与 03 EXPLAIN を実⾏し、prepare では検出できないプランナ段階のエラーを検出 04 スキーマのスナップショット(テーブル、列、NOT NULL等)を⼀度だけ取得† 05 全レンダリングでの型の⼀致を確認し、⽣成コードへ埋め込み † nullabilityについてもここで検証する。機構についてのドキュメント: https://github.com/moznion/go-sqletch/blob/main/docs/design/05-nullability.md © Timeleap Inc. 28
  6. Type Oracleを⽣成するためのtest DB (実DB) の利⽤ • 基本的にはコンテナで動作するDBをsqletchが⾃動的に利⽤する • コンテナ以外の選択肢 ◦

    sqliteは簡単にDBを⽤意できるのでそれを使う ◦ postgresはWASMで動くランタイム†がありそれが利⽤できる (……はずなのだが⾊々問題があり未達††) ◦ MySQLにはそういったものが無いので実DBを使わず、 DDLで簡潔する機能が制限されたType Oracleも⽤意 (native oracleと呼称している) † https://github.com/electric-sql/pglite †† issueは上げており、パッチもある: https://github.com/electric-sql/pglite/issues/1071 © Timeleap Inc. 29
  7. go-sqletchの開発について 01 LLM + 仕様駆動開発 開発のベースに設定 コンセプトとspecは徹底して⽭盾が起こらない ように制御 03 実DBを使ったE2E

    プロパティテスト 列挙できるすべての形を PREPARE/EXPLAIN し て検証 02 テストファースト徹底 厳格な検証 拒否すべき⼊⼒は診断コード単位まで assert を 徹底 04 CIでのFuzzing実⾏ 回帰テストの⾃動蓄積 ⾒つかったクラッシャーはそのまま回帰テスト として残す AI時代って感じがしますね (全部⼿で実装してたら多分完成していない……) © Timeleap Inc. 31
  8. go-sqletchの裏モチベーションと検証したいこと 01 SQL軸の開発体験 02 テナント越境の防⽌ 03 LLM親和性の仮説 SQLを書いて開発したい レイヤーでの防御検証 推論のしやすさ検証

    • SQLからボイラープレートが ⽣成されてほしい • このレイヤーでテナント越境 を防げるか • 「SQL+テンプレートエンジ ン」のコンセプト実証 • Policy Weaving のコンセプト が有効かどうか パフォーマンスとの両⽴ • ◦ Alternative: Row Level Security の⽐較‧検討 • コード内のランタイムクエリ ビルダーによる⽣成クエリの 推論は⾼難度 • SQL-ishなテンプレートの⽅が LLMにとって推論しやすいの では?という仮説 💡 このあたりがどうなのかというところを実戦で検証していきたい © Timeleap Inc. 32
  9. まとめ ⾊々と便利な ⼩難しい 機構はあるものの、 • SQLに便利なテンプレート機構が⼊っており • パフォーマンスとしても担保されており • 型のサポートもある

    SQLテンプレートから、実クエリを実⾏するGoコードを⽣成するツー ルというふうに認識いただければ良いと思います © Timeleap Inc. 33
  10. Query Performance Lint SQLテンプレートに対して静的解析をし、クエリのパフォーマンスに 関するLintを適⽤できる機能 検出する書き方 例 WHERE / JOIN

    … ONの比較でカラムを関 数やキャストで包んでいる lower(u.email) = :email u.created_at::date = :day LIKE / ILIKE のパターンが % か _ で始ま ることが確定している u.email LIKE '%' || :q :many のSELECTで、LIMIT / FETCH FIRST の無い形が1つでも組み立てられる SELECT u.id FROM users AS u OFFSET の値を引数から受け取っている LIMIT :limit OFFSET :offset 引数の型が原因で、 DBが行ごとにカラムの 方を変換する u.id = :p::numeric © Timeleap Inc. 39