{-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE DeriveGeneric #-} -- Legend: -- A CRUD-like API for table of users. -- Due to backward compatibility requirements some of legacy types must be -- preserved. -- -- This is an example of using custom types. module ExUsers ( specUsers ) where import Common (bindOptions, include) import Data.Text (Text) import Database.PostgreSQL.Simple (Connection) import Database.PostgreSQL.Simple.FromRow (FromRow) import Database.PostgreSQL.Simple.Bind (bindFunction, PostgresType) import Database.PostgreSQL.Simple.Bind.Types() import GHC.Generics (Generic) import Test.Hspec (Spec, describe, it, shouldBe) concat <$> mapM (bindFunction bindOptions) [ "function get_users(p_filter varchar2 default '') returns setof t_user" , "function add_user(p_name varchar2, p_age bigint) returns bigint" , "function del_user(p_user_id bigint) returns void" ] type instance PostgresType "varchar2" = Text data User = User { userId :: Int , userName :: String , userAge :: Int } deriving (Eq, Show, Generic) instance FromRow User type instance PostgresType "t_user" = User specUsers :: Connection -> Spec specUsers conn = describe "Users example" $ it "works" $ do include conn "./examples/sql/users.sql" mrFooId <- sqlAddUser conn "Mr. Foo" 42 mrBarId <- sqlAddUser conn "Mr. Bar" 53 mrBazId <- sqlAddUser conn "Mr. Baz" 64 sqlGetUsers conn (Just "Mr. Foo") >>= \[u] -> (u { userId = 1 }) `shouldBe` (User { userId = 1 , userName = "Mr. Foo" , userAge = 42 }) sqlGetUsers conn Nothing >>= shouldBe [mrFooId, mrBarId, mrBazId] . map userId sqlGetUsers conn (Just "Mr. Ba_") >>= shouldBe [mrBarId, mrBazId] . map userId sqlDelUser conn mrBarId sqlGetUsers conn Nothing >>= shouldBe [mrFooId, mrBazId] . map userId