日本時間の2021年9月25日、ElixirのWebフレームワーク「Phoenix」の__バージョン1.6__が、に正式リリースされました。1
1.6からの機能2の中で、正式サポートされるデータベースに「SQLite3」が追加されています。3
正確には、データベース接続で利用されるライブラリ「Ecto」45がSQLite3をサポートできるようになったから、というものです。
コードの差分が気になった
さて、ここからが本題です。
Phoenixでは、データベースの指定はプロジェクトを作成するコマンドmix phx.new
を実行するタイミングで行います。
たとえば、データベースにPostgreSQLを指定する場合、以下のように--database
オプションの後にpostgres
と入力6します。
mix phx.new <アプリケーション名> --database postgres
そして、その時に指定したデータベースの種類によって、指定したデータベースを扱うために必要なライブラリや設定のスケルトンコードが生成されます。
今回、あらたに「SQLite3」を指定できるようになったので、どこに差分があるかが気になったので調べてみました。
各種バージョン
ソース生成に利用した各種バージョンは以下の通りです。
また、コード作成日時は__2021年10月10日__です。
- erlang: 24.1.2
- elixir: 1.12.3-otp-24
- Phoenix: 1.6.2
比較対象
デフォルト指定のPostgreSQLとSQLite3のコードを比較してみました。
postgresql
ディレクトリとsqlite3
ディレクトリに同一アプリケーション名のプロジェクトを生成。
--database
オプションの差異で、コードのどこに差異が出るかをdiff
コマンドで比較してみました。
それぞれの生成コマンドは以下の通りです。
アプリケーション名はteck_fanzine
としています。
- PostgreSQLの場合:
mix phx.new teck_fanzine --database postgres
- SQLite3の場合:
mix phx.new teck_fanzine --database sqlite3
生成結果の差分
両方のコマンドを実行結果をそのまま比較すると、〜*.beam
や_build
ディレクトリ配下のバイナリファイルも差分として出てきます。
そのため、これらのファイルを除いた形でファイルを比較してみました。
結果、以下の内容となりました。
$diff -qr postgresql/ sqlite3/ | grep -v "beam" | grep -v "_build"
Files postgresql/teck_fanzine/.gitignore and sqlite3/teck_fanzine/.gitignore differ
Files postgresql/teck_fanzine/config/config.exs and sqlite3/teck_fanzine/config/config.exs differ
Files postgresql/teck_fanzine/config/dev.exs and sqlite3/teck_fanzine/config/dev.exs differ
Files postgresql/teck_fanzine/config/runtime.exs and sqlite3/teck_fanzine/config/runtime.exs differ
Files postgresql/teck_fanzine/config/test.exs and sqlite3/teck_fanzine/config/test.exs differ
Only in sqlite3/teck_fanzine/deps: ecto_sqlite3
Only in sqlite3/teck_fanzine/deps: elixir_make
Only in sqlite3/teck_fanzine/deps: exqlite
Only in postgresql/teck_fanzine/deps: postgrex
Files postgresql/teck_fanzine/lib/teck_fanzine/repo.ex and sqlite3/teck_fanzine/lib/teck_fanzine/repo.ex differ
Files postgresql/teck_fanzine/lib/teck_fanzine_web/endpoint.ex and sqlite3/teck_fanzine/lib/teck_fanzine_web/endpoint.ex differ
Files postgresql/teck_fanzine/mix.exs and sqlite3/teck_fanzine/mix.exs differ
Files postgresql/teck_fanzine/mix.lock and sqlite3/teck_fanzine/mix.lock differ
上記を整理すると、以下のような分類になります。
※アプリケーション名のルートパス名は省略。また、diffの結果とは一部ファイルの並び順を変更しています。
- postgresの時にだけ生成されている
- deps/postgrex/ ・・・ PostgreSQLを扱うライブラリ「postgrex」7のディレクトリ
- sqlite3の時にだけ生成されている
- 両方に生成されて、かつ差分があるファイル
- .gitignore
- mix.exs
- mix.lock
- config/config.exs
- config/dev.exs
- config/test.exs
- config/runtime.exs
- lib/teck_fanzine/repo.ex
- lib/teck_fanzine_web/endpoint.ex
生成結果の差分:詳細
以下、「両方に生成されて、かつ差分があるファイル」の差分を比較してみます。
diffコマンドベースの結果であるので、差分は「<」と「>」で表示されています。
「<」がPostgreSQL、「>」がSQLite3を指定した場合のファイルです。
.gitignore
SQLite3はファイルデータベースなので、「*.db」ファイルをgitリポジトリには保存しないようにしているようです。
$diff postgresql/teck_fanzine/.gitignore sqlite3/teck_fanzine/.gitignore
34a35,38
> # Database files
> *.db
> *.db-*
>
mix.exs
depsで指定するライブラリ名の差分ですね。
MacBook-Air-3:_diff_project $diff postgresql/teck_fanzine/mix.exs sqlite3/teck_fanzine/mix.exs
39c39
< {:postgrex, ">= 0.0.0"},
---
> {:ecto_sqlite3, ">= 0.0.0"},
mix.lock
具体的なライブラリの差分ですね。ここのバージョンは、mix.exs
で指定されたライブラリのバージョンによっても依存して変わってくるので、プロジェクトを生成するタイミングによっても内容は変わってきます。
$ diff postgresql/teck_fanzine/mix.lock sqlite3/teck_fanzine/mix.lock
10a11,12
> "ecto_sqlite3": {:hex, :ecto_sqlite3, "0.7.2", "667338c1e0f7af13f75ab9eec13afcea216eb71dac9daf7897c8f0acc8b5722b", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.6", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "b003804132f183d1d6dc759f6c2ccc60c1fb5d62e1db4aa4fe0d38577096f7c4"},
> "elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
11a14
> "exqlite": {:hex, :exqlite, "0.7.4", "c35308cf6cac5d18451e4c47a96db7bacf3bec8265a8821bce62bb97b8557412", [:make, :mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "15bc5534d404939fe9ecba29517e3d117a6195c04572b9d31a6c7b4bddfe3e51"},
29d31
< "postgrex": {:hex, :postgrex, "0.15.11", "50abbb50f33d22d79af402e549b9a566ba4f0451b4f5fd39b72d9bbd49743d24", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "6f0e5c3ea10f97468f5ff852277cb207f068399eb68b0c06c142ef68a4e82952"},
config/config.exs
ここは、LiveViewで利用するソルトの値の差分でした。
そのため、実質的には、__差分は無い __ことになります。
※ソルトの値にはマスクをかけました。
$diff postgresql/teck_fanzine/config/config.exs sqlite3/teck_fanzine/config/config.exs
18c18
< live_view: [signing_salt: "xxxxxxxx"]
---
> live_view: [signing_salt: "XXXXXXXX"]
config/dev.exs
開発時の設定を記載するファイルです。ここのファイルは差分が大きいですね。
もっとも、DBへの接続に関する情報が書かれているので、差異は大きくはなってしまうのですが。
PostgreSQL側の設定がユーザ名/パスワード名/データベース名/ホスト名などに対して、SQLite3の場合はDBファイル名となっています。
なお、Endpointに対しての「secret_key_base」にも差分がありましたが、これも生成のたびに変わるので、実質的には、__差分は無い __ことになります。
※ソルトの値にはマスクをかけました。
$diff postgresql/teck_fanzine/config/dev.exs sqlite3/teck_fanzine/config/dev.exs
5,10c5,7
< username: "postgres",
< password: "postgres",
< database: "teck_fanzine_dev",
< hostname: "localhost",
< show_sensitive_data_on_connection_error: true,
< pool_size: 10
---
> database: Path.expand("../teck_fanzine_dev.db", Path.dirname(__ENV__.file)),
> pool_size: 5,
> show_sensitive_data_on_connection_error: true
25c22
< secret_key_base: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
---
> secret_key_base: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
config/test.exs
テスト実行時の設定を記載するファイルです。ここのファイルもdev.exs同様に差分が大きいですね。
基本的な差分は、dev.exsの時と同じです。
dev.exsとの違いでは、こちらにはEcto.Adapters.SQL.Sandbox
がありますね。
なお、こちらでもEndpointに対しての「secret_key_base」にも差分がありましたが、これも生成のたびに変わるので、実質的には、__差分は無い __ことになります。
※ソルトの値にはマスクをかけました。
$ diff postgresql/teck_fanzine/config/test.exs sqlite3/teck_fanzine/config/test.exs
9,14c9,11
< username: "postgres",
< password: "postgres",
< database: "teck_fanzine_test#{System.get_env("MIX_TEST_PARTITION")}",
< hostname: "localhost",
< pool: Ecto.Adapters.SQL.Sandbox,
< pool_size: 10
---
> database: Path.expand("../teck_fanzine_test.db", Path.dirname(__ENV__.file)),
> pool_size: 5,
> pool: Ecto.Adapters.SQL.Sandbox
20c17
< secret_key_base: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
---
> secret_key_base: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
config/runtime.exs
起動時に読み込まれるruntime.exs
にも差分がありました。
ここには、DBの本番用設定(=prodの場合の設定)があらかじめ出力されており、読み込むための環境変数の差異が出ているようです。
PostgreSQLの際には、「DATABASE_URL」が、SQLite3の場合は「DATABASE_PATH」を設定することになるようです。
ただし、これはあくまでテンプレートとして出力されている内容なので、環境変数名を変更することもできるでしょう。
$ diff postgresql/teck_fanzine/config/runtime.exs sqlite3/teck_fanzine/config/runtime.exs
10,11c10,11
< database_url =
< System.get_env("DATABASE_URL") ||
---
> database_path =
> System.get_env("DATABASE_PATH") ||
13,14c13,14
< environment variable DATABASE_URL is missing.
< For example: ecto://USER:PASS@HOST/DATABASE
---
> environment variable DATABASE_PATH is missing.
> For example: /etc/teck_fanzine/teck_fanzine.db
18,21c18,19
< # ssl: true,
< # socket_options: [:inet6],
< url: database_url,
< pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
---
> database: database_path,
> pool_size: String.to_integer(System.get_env("POOL_SIZE") || "5")
lib/teck_fanzine/repo.ex
データストアに対するAPIを提供する設定が、「Repo」(Ecto.Repo)11になります。
$diff postgresql/teck_fanzine/lib/teck_fanzine/repo.ex sqlite3/teck_fanzine/lib/teck_fanzine/repo.ex
4c4
< adapter: Ecto.Adapters.Postgres
---
> adapter: Ecto.Adapters.SQLite3
lib/teck_fanzine_web/endpoint.ex
sessionで利用するソルト「signing_salt」にも差分がありましたが、これも生成のたびに変わるので、実質的には、__差分は無い __ことになります。
※ソルトの値にはマスクをかけました。
$diff postgresql/teck_fanzine/lib/teck_fanzine_web/endpoint.ex sqlite3/teck_fanzine/lib/teck_fanzine_web/endpoint.ex
10c10
< signing_salt: "xxxxxxxx"
---
> signing_salt: "XXXXXXXX"
まとめ
調査の結果、実質的な差分があるファイルは以下とわかりました。
- .gitignore
- mix.exs
- mix.lock
- config/dev.exs
- config/test.exs
- config/runtime.exs
- lib/teck_fanzine/repo.ex
今回は、初期生成されたコードに対しての差分を確認してみただけですが、それでも差分からでもわかってくる内容もありました。
SQLite3を本番環境で利用する機会は少ないでしょうが、やはりざっとデータベースを利用するアプリを作る時にはSQLite3を手軽に利用できるのは良いですね。
せっかく差分を調べたので、この勢いでSQLite3を利用したアプリケーションのコードも書いてみようと考えています。
-
なお、1.6.0-rc.0版は、2021年8月26日に公開されています。 ↩
-
https://github.com/phoenixframework/phoenix/blob/master/CHANGELOG.md#160-rc0-2021-08-26 ↩
-
Phoenix 1.2より前のバージョンではSQLiteも扱えていたようですが、Ecto側でsqlite_ectoがEcto 2.x系以降でNGになって以降、Phoenixでも正式サポートはしていなかったよらしい、とのこと。: https://twitter.com/piacere_ex/status/1447419385304420360?s=20 ↩
-
Phoenixでは、データベースの指定はデフォルトでPostgreSQLが指定されるので、実はこのオプションを指定する必要はないのですが。 ↩
-
Repoは「Repositories」からきているようです。
その設定の中で、アダプター(adapter)の設定が、利用するデータベースによって違いが出ています。 ↩