0 (旧) チュートリアル
日比野 啓 (Kei Hibino) edited this page 2017-03-06 10:16:24 +09:00

チュートリアル

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 テーブルの情報を取得したときのログです。