Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What are the problem?
Organization

Phoenix1.6でDBにSQLite3を指定した際のコード差異を調べてみた

日本時間の2021年9月25日、ElixirのWebフレームワーク「Phoenix」のバージョン1.6が、に正式リリースされました。1

1.6からの機能2の中で、正式サポートされるデータベースに「SQLite3」が追加されています。3
正確には、データベース接続で利用されるライブラリ「Ecto45が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を扱うライブラリ「postgrex7のディレクトリ
  • sqlite3の時にだけ生成されている
    • deps/ecto_sqlite3/ ・・・ SQLite3を扱うライブラリ「ecto_sqlite38のディレクトリ
    • deps/exqlite/ ・・・ ecto_sqlite3が必要としているライブラリ「exqlite9のディレクトリ
    • deps/elixir_make/ ・・・ exqliteのruntime時に必要としているライブラリ「elixir_make10のディレクトリ
  • 両方に生成されて、かつ差分があるファイル
    • .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になります。
その設定の中で、アダプター(adapter)の設定が、利用するデータベースによって違いが出ています。

$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. なお、1.6.0-rc.0版は、2021年8月26日に公開されています。 

  2. https://github.com/phoenixframework/phoenix/blob/master/CHANGELOG.md#160-rc0-2021-08-26 

  3. Phoenix 1.2より前のバージョンではSQLiteも扱えていたようですが、Ecto側でsqlite_ectoがEcto 2.x系以降でNGになって以降、Phoenixでも正式サポートはしていなかったよらしい、とのこと。: https://twitter.com/piacere_ex/status/1447419385304420360?s=20 

  4. https://hexdocs.pm/phoenix/1.6.0/ecto.html#content 

  5. https://github.com/elixir-ecto/ecto#usage 

  6. Phoenixでは、データベースの指定はデフォルトでPostgreSQLが指定されるので、実はこのオプションを指定する必要はないのですが。 

  7. https://github.com/elixir-ecto/postgrex 

  8. https://github.com/elixir-sqlite/ecto_sqlite3 

  9. https://github.com/elixir-sqlite/exqlite 

  10. https://github.com/elixir-lang/elixir_make 

  11. Repoは「Repositories」からきているようです。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?