Haskellでのデータベースアクセス
PostgresqlのHDBCを利用しました。
HDBC: Haskell Database Connectivity
作業場所の作成
$ mkdir haskelldatabase $ cd haskelldatabase
サンドボックスの作成
$ cabal sandbox init Writing a default package environment file to /Users/bar/work03/haskelldatabase/cabal.sandbox.config Creating a new sandbox at /Users/bar/work03/haskelldatabase/.cabal-sandbox
HDBCのインストール
$ cabal install hdbc Resolving dependencies... Notice: installing into a sandbox located at /Users/bar/work03/haskelldatabase/.cabal-sandbox Configuring mtl-2.2.1... Configuring old-locale-1.0.0.7... Downloading utf8-string-1.0.1.1... Configuring text-1.2.2.1... Configuring utf8-string-1.0.1.1... Building old-locale-1.0.0.7... Building mtl-2.2.1... Building text-1.2.2.1... Building utf8-string-1.0.1.1... Installed old-locale-1.0.0.7 Configuring old-time-1.1.0.3... Building old-time-1.1.0.3... Installed mtl-2.2.1 Installed utf8-string-1.0.1.1 Installed old-time-1.1.0.3 Installed text-1.2.2.1 Downloading convertible-1.1.1.0... Configuring convertible-1.1.1.0... Building convertible-1.1.1.0... Installed convertible-1.1.1.0 Downloading HDBC-2.4.0.1... Configuring HDBC-2.4.0.1... Building HDBC-2.4.0.1... Installed HDBC-2.4.0.1 Updating documentation index /Users/bar/work03/haskelldatabase/.cabal-sandbox/share/doc/x86_64-osx-ghc-8.0.1/index.html
postgresqlドライバのインストール
$ cabal install hdbc-postgresql Resolving dependencies... Notice: installing into a sandbox located at /Users/bar/work03/haskelldatabase/.cabal-sandbox Configuring parsec-3.1.11... Building parsec-3.1.11... Installed parsec-3.1.11 Downloading HDBC-postgresql-2.3.2.4... Configuring HDBC-postgresql-2.3.2.4... Building HDBC-postgresql-2.3.2.4... Installed HDBC-postgresql-2.3.2.4 Updating documentation index /Users/bar/work03/haskelldatabase/.cabal-sandbox/share/doc/x86_64-osx-ghc-8.0.1/index.html $
データベースの準備
$ createuser -a -d -U bar -P user03 Enter password for new role: Enter it again: $ createdb -E UTF8 -O user03 -U user03 testdb03
データベスの確認
$ psql -l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+------------+----------+-------------+-------------+--------------------------- testdb03 | user03 | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 |
テーブルの作成
$ psql -d testdb03 psql (9.6.1) Type "help" for help. testdb03=# testdb03=# create table foo(name varchar(50)); testdb03=# \dt; List of relations Schema | Name | Type | Owner --------+------+-------+------------ public | foo | table | bar (1 row)
テーブル情報の確認
> :t connectPostgreSQL connectPostgreSQL :: String -> IO Connection > :t getTables getTables :: IConnection conn => conn -> IO [String] > connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= (\x -> getTables x) ["foo"] >
データ挿入、オートコミットはされない。
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= (\x -> run x "insert into foo values('abc')" []) 1 >
データ挿入+コミット
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= (\x -> run x "insert into foo values('ghi')" [] >>= (\_ -> commit x)) >
検索(prepare -> execute -> fetch->結果はMaybeというパターン)
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchRow y) Just [SqlByteString "abc"]
列名付き検索
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchRowAL y) Just [("name",SqlByteString "abc")]
列名付き検索をMapで取得
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchRowMap y) Just (fromList [("name",SqlByteString "abc")])
複数行取得
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchAllRows y) [[SqlByteString "abc"],[SqlByteString "def"],[SqlByteString "ghi"]]
検索結果をMapで取得
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchAllRowsMap y) [fromList [("name",SqlByteString "abc")],fromList [("name",SqlByteString "def")],fromList [("name",SqlByteString "ghi")]]
日本語の取り扱い
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= (\x -> run x "insert into foo values('あいうえお')" [] >>= (\_ -> commit x)) > connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo" >>= (\y -> execute y [] >>= \_ -> fetchAllRowsMap y) [fromList [("name",SqlByteString "abc")],fromList [("name",SqlByteString "def")],fromList [("name",SqlByteString "ghi")],fromList [("name",SqlByteString "\227\129\130\227\129\132\227\129\134\227\129\136\227\129\138")]]
NULLの取り扱い SqlNullというデータがある
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> prepare x "select * from foo where name is null" >>= (\y -> execute y [] >>= \_ -> fetchAllRowsMap y) [fromList [("name",SqlNull)]]
トランザクションを使う
> connectPostgreSQL "host=localhost dbname=testdb03 user=user03" >>= \x -> withTransaction x (\y -> run y "insert into foo values('klm')" []) 1
do記法
import Database.HDBC import Database.HDBC.PostgreSQL main = do con <- connectPostgreSQL "host=localhost dbname=testdb03 user=user03" run con "insert into foo values('qwerty')" [] commit con
HaskellのMonoidの情報
Blenderで立方体を床に落とすサンプル
Cubeが床に落ちることをやります。
1: キューブを追加する(Shift+A -> Mesh -> Cube)。
2: Cubeを上に動かす。
3: Physics -> Rigid Body -> Type : Active とする。
4: 床を追加する(Shift+A -> Mesh -> Plane)。
5: Planeの位置と大きさを調整する。
6: Physics -> Rigid Body -> Type : Passive とする。
7: 再生する
8: キューブが床に落ちる
waiでのrequestの処理
waiでrequestの基本的な使い方を確認するサンプル。
*Main> main start app function ==================================== requestMethod : GET secure : False rawPathInfo : /cgi.php rawQueryString : ?foo=1111 requestHeaders : host : 127.0.0.1:3030 accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 accept-language : ja-jp connection : keep-alive accept-encoding : gzip, deflate user-agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4 queryString : foo : 1111 start app function ==================================== requestMethod : POST secure : False rawPathInfo : /cgi.php rawQueryString : ?foo=111&bar=222 requestHeaders : host : 127.0.0.1:3030 content-type : application/x-www-form-urlencoded origin : file:// connection : keep-alive accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 user-agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4 accept-language : ja-jp accept-encoding : gzip, deflate content-length : 7 queryString : foo : 111 bar : 222
map, map, liftM
> :t map map :: (a -> b) -> [a] -> [b] > :t fmap fmap :: Functor f => (a -> b) -> f a -> f b > :t liftM liftM :: Monad m => (a1 -> r) -> m a1 -> m r > :t (<*>) . pure (<*>) . pure :: Applicative f => (a -> b) -> f a -> f b > map (+1) [1,2,3] [2,3,4] > fmap (+1) [1,2,3] [2,3,4] > liftM (+1) [1,2,3] [2,3,4] > ((<*>) . pure) (+1) [1,2,3] [2,3,4] >
Monadのfail関数について思ったこと(2)
3分でHaskellのWebアプリ
のサンプルを動かします。但し、待ち時間を除きます。
Beginning Haskell - A Project-Based Approach | Alejandro Serrano Mena | ApressのWebアプリの説明では、フレームワークとしてscottyを使っているので、導入してみました。
バージョンの確認
webapp $ cabal -version cabal: unrecognised command: -version (try --help) webapp $ cabal --version cabal-install version 1.24.0.0 compiled using version 1.24.0.0 of the Cabal library webapp $ cabal repl GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help Prelude> :q Leaving GHCi.
作業場所の作成
webapp $ mkdir scotty02 webapp $ cd scotty02 scotty02 $ ls scotty02 $ cabal sandbox init Writing a default package environment file to /Users//work03/webapp/scotty02/cabal.sandbox.config Creating a new sandbox at /Users//work03/webapp/scotty02/.cabal-sandbox
scottyのインストール
scotty02 $ cabal install scotty Resolving dependencies... Notice: installing into a sandbox located at /Users//work03/webapp/scotty02/.cabal-sandbox Downloading ansi-terminal-0.6.2.3... Downloading appar-0.1.4... Configuring base64-bytestring-1.0.0.1... Configuring base-compat-0.9.1... 途中省略 Installed wai-extra-3.0.19 Downloading scotty-0.11.0... Configuring scotty-0.11.0... Building scotty-0.11.0... Installed scotty-0.11.0 Updating documentation index
サンプルアプリケーションの作成
scotty02 $ cat hello.hs {-# LANGUAGE OverloadedStrings #-} import Web.Scotty main :: IO () main = scotty 3010 $ do get "/" $ do html "Hello, Scotty World!"
起動
scotty02 $ cabal exec runghc hello.hs Setting phasers to stun... (port 3010) (ctrl-c to quit)
Webアクセス
client$ curl http://localhost:3010/
Hello, Scotty World!
client$