6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI で Elixir の Ecto ライブラリを読んでみよう

Last updated at Posted at 2025-09-27

はじめに

@koyo-miyamura と申します。以下の Elixir 合宿でワイワイ自由研究してみました。

AI をコードリーディングに使う。

みなさん AI をどのように使っていますか?コードを書いてもらっている!という方も多いでしょう。
でも実務ではだれかが書いたコードを読む機会も多いです。このような時にも AI は役立ちます。
とはいえ Elixir は他言語に比べて若干マイナーです。うまく読めるのでしょうか?やってみましょう!

実際にやってみる

使用する AI

VsCode 上の GitHub Copilot Chat の Agent モード。Claude Sonnet 4 モデル。

コードリーディングの対象

Phoenix でも使われているデータマッピングライブラリの Ecto を読んでみます。
「Repo.all してから MySQL とやりとりする箇所までを特定して読んでみる」ことを目的にしてみます。

やってみる

まず以下のように clone してみます。

$ git clone git@github.com:elixir-ecto/ecto

まず AI に概要を説明してもらいましょう。


Q. この Ecto というライブラリのコードリーディングをしたいです。まず概要を理解したいです。

A. GitHub Copilot: Ectoライブラリのコードリーディングをお手伝いします。まず、このライブラリの概要を理解するために重要なファイルを調べてみましょう。

Read , lines 1 to 50

Read , lines 51 to 120

Read , lines 1 to 30

Read , lines 1 to 100

Read

Ectoライブラリの概要を理解しました。以下にまとめます:

Ecto とは

Ectoは、Elixir言語のためのデータマッピングと言語統合クエリのためのツールキットです。主にデータベースとの連携で使用されますが、任意のデータソースをElixirの構造体にマッピングすることも可能です。

4つの主要コンポーネント

Ectoは以下の4つの核となるコンポーネントで構成されています:

1. Ecto.Repo - データがどこにあるか

  • データストアのラッパー
  • データの作成、更新、削除、クエリを実行
  • アダプターと認証情報が必要

2. Ecto.Schema - データが何であるか

  • 外部データをElixir構造体にマッピング
  • データベーステーブルの定義によく使用される

3. Ecto.Query - データをどう読むか

  • Elixir構文で書かれたクエリ
  • 安全で組み合わせ可能なクエリシステム

4. Ecto.Changeset - データをどう変更するか

  • データに適用する前の変更の追跡とバリデーション

サポートするデータベース

データベース Ectoアダプター 依存関係
PostgreSQL Ecto.Adapters.Postgres ecto_sql + postgrex
MySQL Ecto.Adapters.MyXQL ecto_sql + myxql
MSSQL Ecto.Adapters.Tds ecto_sql + tds
SQLite3 Ecto.Adapters.SQLite3 ecto_sqlite3
ClickHouse Ecto.Adapters.ClickHouse ecto_ch
ETS Etso etso

基本的な使用例

# スキーマ定義
defmodule Weather do
  use Ecto.Schema

  schema "weather" do
    field :city,    :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp,    :float, default: 0.0
  end
end

# クエリ例
query = from w in Weather,
        where: w.prcp > 0 or is_nil(w.prcp),
        select: w

# パイプ演算子を使ったクエリ
Weather
|> where(city: "Kraków")
|> order_by(:temp_lo)
|> limit(10)
|> Repo.all

プロジェクト構造の特徴

  • 現在のバージョン: 3.13.3
  • Elixir要件: ~> 1.14
  • 主要な機能:
    • 型システム(type.ex)
    • アソシエーション(association.ex)
    • 埋め込みスキーマ(embedded.ex)
    • マルチ操作(multi.ex)
    • JSON サポート(json.ex)

Ectoは非常に体系的に設計されており、データベース操作を安全で効率的に行うための包括的なソリューションを提供しています。さらに詳しく調べたい特定のコンポーネントはありますか?


...のような形でかなり十分にコードリーディングができるようです。
しかも疑問に応じて対話的に進められます!

例えばこのようなプロンプトを投げました。

  • どこから読めばいいかな?
  • ecto.ex について教えて
  • put_meta の説明をして

寄り道して知らない文法を聞いてみる

また、以下のように自分の知らない文法が出てきた時に、スッと聞くことができます。


該当の行にフォーカスを当てます。

Q. %_{} って何?

A. 選択されている行の %_{} について説明します。

Read , lines 570 to 585

%_{} の説明

%_{}Elixirの構造体のパターンマッチングで使用される特殊な記法です。

意味

  • %_{} は「どんな構造体でもマッチする」という意味
  • _ はElixirのワイルドカードパターンで、任意の値にマッチし、その値を無視する

この文脈での役割

def assoc_loaded?(%Ecto.Association.NotLoaded{}), do: false  # NotLoadedの場合はfalse
def assoc_loaded?(list) when is_list(list), do: true        # リストの場合はtrue  
def assoc_loaded?(%_{}), do: true                           # 任意の構造体の場合はtrue
def assoc_loaded?(nil), do: true                            # nilの場合はtrue

この関数は関連データ(association)が読み込まれているかどうかをチェックしています:

  1. %Ecto.Association.NotLoaded{} - 明示的に「未読み込み」を表す特別な構造体 → false
  2. list when is_list(list) - リスト(複数の関連データ) → true
  3. %_{} - 任意の構造体(User、Post、Commentなどの実際のデータ) → true
  4. nil - nilの場合 → true

なぜ %_{} を使うのか?

関連データが読み込まれている場合、以下のような様々な構造体が返される可能性があります:

# 単一の関連データ
%Comment{id: 1, text: "Hello"}
%User{id: 2, name: "Alice"} 
%Post{id: 3, title: "My Post"}

# これらすべてに対して true を返したい

%_{} を使うことで、具体的な構造体の型を指定せずに、「何らかの構造体である」ことだけを確認できます。

他の例

# 具体的な構造体のみマッチ
def process(%User{} = user), do: "処理するユーザー: #{user.name}"

# 任意の構造体にマッチ  
def process(%_{} = struct), do: "何らかの構造体: #{struct.__struct__}"

# マップにマッチ(構造体ではない)
def process(%{} = map), do: "普通のマップ"

つまり、%_{} は「どんな種類の構造体でも受け入れるが、構造体でなければならない」という条件を表現する便利な記法です。


知らない文法を知ることができました!

読み進めてみる

読み進めてみると Ecto の具体的な実行部分は Ecto.SQL になっているようで、さらに MySQL の処理は MyXQL ドライバに移譲されているようです。

AI の解答は以下です。


...

EctoとMySQLの関係は階層的な構造になっています。詳しく説明します。

  1. 全体のアーキテクチャ
Ecto Core
    ↓
Ecto.SQL (別パッケージ)
    ↓
Ecto.Adapters.MyXQL
    ↓
MyXQL (MySQL ドライバー)
    ↓
MySQL データベース

実際に読んでみると execute 関数を使っていそうでした。

execute 関数の実体は Ecto.Adapters.MyXQL の実装にあるのでクローンします。

$ git clone git@github.com:elixir-ecto/ecto_sql.git

同じように ecto_sql リポジトリで AI とコードリーディングしていきます。
実装はこのあたりですね。

またここから先を AI と読み解くと、結果的に sql_call 関数に行きつきます。コメントで実際のモジュールを教えてくれるのはうれしいですね。

defp sql_call(adapter_meta, callback, args, params, opts) do
  %{
    pid: pool,
    telemetry: telemetry,
    sql: sql,  # MyXQL.Connectionモジュール
    opts: default_opts,
    log_stacktrace_mfa: log_stacktrace_mfa
  } = adapter_meta

  conn = get_conn_or_pool(pool, adapter_meta)
  opts = with_log(telemetry, log_stacktrace_mfa, params, opts ++ default_opts)
  args = args ++ [params, opts]
  apply(sql, callback, [conn | args])  # 実際のDBドライバー関数呼び出し
end

ということで最終的にはここに行きつきます。MyXQL モジュールという MySQL を Elixir から操作するライブラリを使って操作しているようですね。

これで「Repo.all してから MySQL とやりとりする箇所までを特定して読んでみる」が達成できました。

やってみて

実際にやってみると Elixir でも十分 AI と一緒にコードを読むことができました。
対話的に進められるので、疑問に対してすぐにフィードバックが生まれ、非常に学習が捗りますね。
学習効率が大幅に上がるので、個人的におすすめです。
良き Elixir ライフを。

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?