Edited at

Excelから関数型言語マスター3回目:WebにDBデータ表示【PostgreSQL or MySQL編】

(この記事は、「Elixir or Phoenix Advent Calendar 2017」の11日目です)

昨日は、@takasehideki さんの「ElixirでIoT#2:いろいろ分かるベンチマークを整備してみる」でした


fukuoka.ex代表のpiacereです

今回もご覧いただいて、ありがとうございます:bow:

この連載の、前回までの記事は、以下になります

今回は、Web上にDBデータを表示します


DBのインストール

まずは、DBサーバをインストールします

ここでは、DBサーバとして、「PostgreSQL」か「MySQL」のいずれかをインストールすることとします

image.png

パスワードは、PostgreSQLは「postgres」、MySQLは未設定(空文字列)で設定しておくと、Phoenix PJ作成後に設定変更が不要になります

※下記リンク先コラムの中には、「パスワードの weak 評価はダメ」といった記載ありますが、本番環境の構築をしている訳では無いので構いません


①PostgreSQLのインストール

image.png

下記OS毎のインストール手順を実施してください

Windows:https://eng-entrance.com/postgresql-download-install

macOS:https://qiita.com/okame_qiita/items/ac7b6a7d96d07ecbc50b

Ubuntu:https://qiita.com/eighty8/items/82063beab09ab9e41692

CentOS 7:https://weblabo.oscasierra.net/postgresql10-centos7-install/

CentOS 6:https://weblabo.oscasierra.net/postgresql-installing-postgresql9-centos6-1/


②MySQLのインストール

image.png

下記OS毎のインストール手順を実施してください

Windows:https://qiita.com/KeisyaRinco/items/c3074d8450cad96f7e4f

macOS:https://qiita.com/griffin3104/items/c7908359a3e3e18cd269

Ubuntu:https://www.server-world.info/query?os=Ubuntu_16.04&p=mysql

CentOS 7:https://enomotodev.hatenablog.com/entry/2016/09/01/225200

CentOS 6:https://qiita.com/UmedaTakefumi/items/924cdce7cfff083bf492


DBを使うPhoenixのPJ作成、DB作成、起動

DBを使うPhoenixプロジェクトを作成する際は、前回のPhoenix PJ作成時に指定していた、「--no-ecto」の指定は行いません

あと、PostgreSQLの場合は、DB指定不要ですが、MySQLの場合は、DB指定が必要です


※PostgreSQLの場合

mix phx.new sample_db --no-webpack

Fetch and install dependencies? [Yn] (←n、Enterを入力)



※MySQLの場合

mix phx.new sample_db --no-webpack --database=mysql

Fetch and install dependencies? [Yn] (←n、Enterを入力)


パスワードを、以下以外で設定している場合は、config/dev.exsの「password」項目の修正が必要です


  • PostgreSQL:postgres

  • MySQL:未設定(空文字列)


config/dev.exs ※PostgreSQLの場合



# Configure your database
config :sample_db, SampleDb.Repo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "sample_db_dev",
hostname: "localhost",
pool_size: 10


config/dev.exs MySQLの場合



# Configure your database
config :sample_db, SampleDb.Repo,
adapter: Ecto.Adapters.MySQL,
username: "root",
password: "",
database: "sample_db_dev",
hostname: "localhost",
pool_size: 10

PJフォルダに入り、DBを作成します ※作成しないとiex内でエラー連発となるのでお忘れなく

cd sample_db

mix ecto.create

Phoenixを起動します

iex -S mix phx.server

ブラウザで「http://localhost:4000」にアクセスすると、Phoenixで作られたWebページが見れます

image.png


複数列データと同じ構造のテーブル作成、データ投入

テーブル作成のため、各DBクライアントを実行します

PostgreSQLクライアントの場合、「psql」コマンドを入力し、パスワード入力します


※PostgreSQLの場合

psql -U postgres

Password for user postgres:
psql (10.1)
Type "help" for help.

postgres=#


MySQLクライアントの場合は、「mysql」コマンドを入力し、パスワード入力します


※MySQLの場合

mysql

Enter password: ********
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.22-log MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>


アクセス先DBを「sample_db_dev」に変更するため、以下を入力します


※PostgreSQLの場合

postgres=# \c sample_db_dev



※MySQLの場合

mysql> use sample_db_dev


前回の複数列データと同じデータ構造のテーブルを作成するため、以下をpsql/mysql内で入力します

create table members

(
id integer,
name varchar( 255 ),
age integer,
team varchar( 255 ),
position varchar( 255 )
);

続けて、以下でデータ投入するため、以下をpsql/mysql内で入力します

insert into members values( 1, 'enぺだーし', 49, '有限会社デライトシステムズ', '代表取締役、性能探求者' );

insert into members values( 2, 'ざっきー', 45, '公立大学法人 北九州市立大学', '准教授、カーネルハッカー' );
insert into members values( 3, 'つちろー', 34, 'カラビナテクノロジー株式会社', 'リードエンジニア、アプリマイスター' );
insert into members values( 4, 'ゆじかわ', 30, 'カラビナテクノロジー株式会社', 'リードエンジニア、グロースハッカー' );
insert into members values( 5, 'piacere', 43, 'カラビナテクノロジー株式会社', 'CTO、福岡Elixirプログラマ、重力プログラマ、技術顧問' );

以下を入力して、各DBクライアントを終了します


※PostgreSQLの場合

postgres=# \q



※MySQLの場合

mysql> exit



DBアクセスモジュールを作る

PJフォルダ内のlibフォルダ配下にutilフォルダを掘り、DBアクセスする以下モジュールを作ります

なお、コード中の「SampleDb.Repo」の部分は、作成するPJ名によって変わるため、「SampleDb」の部分をPJ名と同じにしてください


lib/util/db.ex

defmodule Db do

def query( sql ) when sql != "" do
{ :ok, result } = Ecto.Adapters.SQL.query( SampleDb.Repo, sql, [] )
result
end
def columns_rows( result ) do
result
|> rows
|> Enum.map( fn row -> Enum.into( List.zip( [ columns( result ), row ] ), %{} ) end )
end
def rows( %{ rows: rows } = _result ), do: rows
def columns( %{ columns: columns } = _result ), do: columns
end


DBデータをWeb表示

さて、準備が整いましたので、DBデータをWeb表示してみます

以下のように、Webページの元となるファイルを書き換えます


lib/sample_db_web/templates/page/index.html.eex

<%

result = Db.query( "select * from members" )
data = result |> Db.columns_rows
%>
<table border="1">
<%= for record <- data do %>
<tr>
<td><%= record[ "name" ] %></td>
<td><%= record[ "age" ] %></td>
<td><%= record[ "team" ] %></td>
<td><%= record[ "position" ] %></td>
</tr>
<% end %>
</table>

以下のようなWebページが表示されるようになります

image.png

SQLが分かる方は、DB内のデータをいじって、表示内容が変わることをお楽しみいただいてもOKです

なお、dataの作成以外は、前回のマップリストと全く同じコードです(つまり、Elixir内部のデータ構造が全く同じ、なので、それを処理する側も全く同じ書き方で良い、ということを意味しています)


前回マップリスト版のindex.html.eex

<%

data =
[
%{ "name" => "enぺだーし", "age" => 49, "team" => "有限会社デライトシステムズ", "position" => "代表取締役、性能探求者" },
%{ "name" => "ざっきー", "age" => 45, "team" => "公立大学法人 北九州市立大学", "position" => "准教授、カーネルハッカー" },
%{ "name" => "つちろー", "age" => 34, "team" => "カラビナテクノロジー株式会社", "position" => "リードエンジニア、アプリマイスター" },
%{ "name" => "ゆじかわ", "age" => 30, "team" => "カラビナテクノロジー株式会社", "position" => "リードエンジニア、グロースハッカー" },
%{ "name" => "piacere", "age" => 43, "team" => "カラビナテクノロジー株式会社", "position" => "CTO、福岡Elixirプログラマ、重力プログラマ、技術顧問" }
]
%>
<table border="1">
<%= for record <- data do %>
<tr>
<td><%= record[ "name" ] %></td>
<td><%= record[ "age" ] %></td>
<td><%= record[ "team" ] %></td>
<td><%= record[ "position" ] %></td>
</tr>
<% end %>
</table>


終わり

今回で、DBにあるデータをWeb表示ができるようになりました

関数型言語によるWeb+DBアプリ開発が、こんな位でできちゃうんだ…と感じていただけたら幸いです

データ元がDBに変わっても、画面側のコードが変わらなかったことに着目すると、関数型言語による開発の威力がじょじょに見えてきます

次回は、「Webに外部APIデータ表示」を行い、やはり画面側は、一切手直しがいらないことを更に実感していただきます

あと、Advent Calendarの方、明日は、@tuchiro さんの「ElixirでSI開発入門 #3 主キーがid 出ない既存DBへの接続」です