Table of Contents
チュートリアル
Note: このチュートリアルは古い内容です。より新しいチュートリアルが プロジェクトサイト にあります。
haskell-relational-record とは
haskell-relational-record は、 Haskell からデータベースにアクセスするためのパッケージ群です。以下のような特徴があります。
- 型安全な SQL を、 Haskell の構文のみで構築できる。
- Template Haskell によって、レコードの型に対応する Haskell の型を自動生成できる。
インストール
Note: プロジェクトサイトにあるインストール方法 - Debian, OpenSUSE, stack, cabal
他のpackageと同様、haskell-relational-recordはhackageで公開されていますので、cabal
コマンドでインストールできます。
リポジトリ名とパッケージ名が異なるのでご注意ください。
$ cabal install relational-record
cabal sandbox 環境を使うときは、以下のようにします。
$ cabal sandbox init
$ cabal install relational-record
簡単な例
haskell-relational-record を使ったデータベースへのアクセスは、以下のようにすると行うことができます。
また、この例を実行するためには haskell-relational-record のパッケージ群に加えて、HDBC-postgresql も必要です。
DBにテーブルを定義する
今回は以下のように定義します。使うデータベースは PostgreSQL とします。
/* create.sql */
create schema TUTORIAL;
create table TUTORIAL.item (
item_id integer not null,
item_name varchar(255) not null,
price integer not null,
primary key (item_id)
);
insert into TUTORIAL.item (item_id, item_name, price) values (1, 'orange', 80);
insert into TUTORIAL.item (item_id, item_name, price) values (2, 'apple', 120);
使うデータベース名は testdb
とします。
$ createdb testdb
$ psql -f create.sql testdb
データベースと接続し、テーブルの型情報を取得する
あるモジュール(ここでは DataSource モジュール)に、データベースとのコネクション(connect
)を作ります。
module DataSource
( connect
) where
import Database.HDBC.PostgreSQL (connectPostgreSQL, Connection)
connect :: IO Connection
connect = connectPostgreSQL "dbname=testdb"
次に、item テーブルの情報を先程作ったコネクションと Template Haskell を使って取得するモジュールを作ります。 Template Haskell のエラーや名前の衝突を避けるため、1テーブル1モジュールにするのが普通です。
{-# LANGUAGE TemplateHaskell, MultiParamTypeClasses, FlexibleInstances #-}
module Item where
import Database.HDBC.Query.TH (defineTableFromDB)
import Database.HDBC.Schema.PostgreSQL (driverPostgreSQL)
import Database.Record.TH (derivingShow)
import DataSource (connect)
$(defineTableFromDB connect driverPostgreSQL "TUTORIAL" "item" [derivingShow])
以上によって、 item テーブルのレコードの型に対応した Haskell の型が自動生成されます。
この場合は、下の Item という型が作られます。
data Item = Item
{ itemId :: !Int32
, itemName :: !String
, price :: !Int32
} deriving (Show)
また、この他にも様々な補助関数が作られます。
クエリを記述する
クエリを構築していきます。
今回は、「100円以下の商品の名前を取得する」というクエリ lessThan100yen
を作ってみます。以下のようになります。
module Query
( lessThan100yen
) where
import Database.Relational.Query
import Item (Item, item)
import qualified Item as I
lessThan100yen :: Relation () String
lessThan100yen = relation $ do
i <- query item
wheres $ i ! I.price' .<. value 100
return (i ! I.itemName')
この Relation p r
型は Show
クラスのインスタンスになっていて、 show
すると作られた SQL を見ることができます。
$ ghci
Prelude> :l Query.hs
*Query> lessThan100yen
SELECT T0.item_name AS f0 FROM TUTORIAL.item AS T0 WHERE (T0.price < 100)
クエリを発行する
作ったクエリを発行するには、以下のようにします。
module Main where
import Database.Relational.Query (relationalQuery)
import Database.HDBC.Session (withConnectionIO, handleSqlError')
import Database.HDBC.Record.Query (runQuery)
import DataSource (connect)
import Query (lessThan100yen)
main :: IO ()
main = handleSqlError' $ withConnectionIO connect $ \conn -> do
names <- runQuery conn (relationalQuery lessThan100yen) ()
print names
先程作った lessThan100yen
は、runQuery
すると IO [String]
型になります。
実行してみます。
$ runghc main.hs
PostgreSQL: getFields: num of columns = 3, not null columns = [0,1,2]
PostgreSQL: getPrimaryKey: primary key = ["item_id"]
["orange"]
["orange"]
と出力されているので、きちんと100円未満の商品を取得できていることがわかります。
# "PostgreSQL: ..." というのは item テーブルの情報を取得したときのログです。