@@ -12,31 +12,85 @@
12 , TypeSynonymInstances
12 , TypeSynonymInstances
15−module Main (main,col1,col2) where
15+module Main (main) where
17import Control.Category ((>>>))
17import Control.Category ((>>>))
18import Control.Monad.Base
18import Control.Monad.Base
19import Data.Function ((&))
19import Data.Function ((&))
20import Data.Int
20import Data.Int
21import Data.Monoid
21import Data.Monoid
22−import Generics.SOP hiding (from)
22+import Data.Text hiding (zip)
23import Squeal.PostgreSQL
23import Squeal.PostgreSQL
25import qualified Data.ByteString.Char8 as Char8
25import qualified Data.ByteString.Char8 as Char8
26+import qualified Generics.SOP as SOP
26import qualified GHC.Generics as GHC
27import qualified GHC.Generics as GHC
28type Schema =
29type Schema =
31+ '[ "id" ::: 'Optional ('NotNull 'PGint4)
29− '[ "students" ::: '["name" ::: 'Required ('NotNull 'PGtext)]
32+ , "name" ::: 'Required ('NotNull 'PGtext)
31− '[ "col1" ::: 'Required ('NotNull 'PGint4)
35+ '[ "id" ::: 'Optional ('NotNull 'PGint4)
32− , "col2" ::: 'Required ('NotNull 'PGint4)
36+ , "user_id" ::: 'Required ('NotNull 'PGint4)
37+ , "email" ::: 'Required ('Null 'PGtext)
36−data Row = Row { col1 :: Int32, col2 :: Int32 }
41+setup :: Definition '[] Schema
45+ (text & notNull) `As` #name :* Nil )
46+ [ primaryKey (Column #id :* Nil) ]
50+ (int & notNull) `As` #user_id :*
51+ text `As` #email :* Nil )
52+ [ primaryKey (Column #id :* Nil)
53+ , foreignKey (Column #user_id :* Nil) #users (Column #id :* Nil)
54+ OnDeleteCascade OnUpdateCascade ]
56+teardown :: Definition Schema '[]
57+teardown = dropTable #emails >>> dropTable #users
59+insertUser :: Manipulation Schema
60+ '[ 'Required ('NotNull 'PGtext)]
61+ '[ "fromOnly" ::: 'Required ('NotNull 'PGint4) ]
62+insertUser = insertInto #users
63+ ( Values (def `As` #id :* param @1 `As` #name :* Nil) [] )
64+ OnConflictDoNothing (Returning (#id `As` #fromOnly :* Nil))
66+insertEmail :: Manipulation Schema
67+ '[ 'Required ('NotNull 'PGint4), 'Required ('Null 'PGtext)] '[]
68+insertEmail = insertInto #emails ( Values
70+ param @1 `As` #user_id :*
71+ param @2 `As` #email :* Nil) [] )
72+ OnConflictDoNothing (Returning Nil)
74+getUsers :: Query Schema '[]
75+ '[ "userName" ::: 'Required ('NotNull 'PGtext)
76+ , "userEmail" ::: 'Required ('Null 'PGtext) ]
78+ (#u ! #name `As` #userName :* #e ! #email `As` #userEmail :* Nil)
79+ ( from (Table (#users `As` #u)
80+ & InnerJoin (Table (#emails `As` #e))
81+ (#u ! #id .== #e ! #user_id)) )
83+data User = User { userName :: Text, userEmail :: Maybe Text }
37 deriving (Show, GHC.Generic)
84 deriving (Show, GHC.Generic)
38−instance Generic Row
85+instance SOP.Generic User
39−instance HasDatatypeInfo Row
86+instance SOP.HasDatatypeInfo User
90+ [ User "Alice" (Just "alice@gmail.com")
92+ , User "Carole" (Just "carole@hotmail.com")
41main :: IO ()
95main :: IO ()
@@ -46,42 +100,16 @@ main = do
46 Char8.putStrLn $ "connecting to " <> connectionString
100 Char8.putStrLn $ "connecting to " <> connectionString
47 connection0 <- connectdb connectionString
101 connection0 <- connectdb connectionString
48 Char8.putStrLn "setting up schema"
102 Char8.putStrLn "setting up schema"
49− connection1 <- flip execPQ (connection0 :: Connection '[]) $ define $
103+ connection1 <- execPQ (define setup) connection0
50− createTable #students ((text & notNull) `As` #name :* Nil ) []
53− ((int4 & notNull) `As` #col1 :* (int4 & notNull) `As` #col2 :* Nil) []
54− connection2 <- flip execPQ (connection1 :: Connection Schema) $ do
104+ connection2 <- flip execPQ connection1 $ do
56− insert :: Manipulation Schema '[_,_,_,_] '[]
60− (param @1 `As` #col1 :* param @2 `As` #col2 :* Nil)
61− [param @3 `As` #col1 :* param @4 `As` #col2 :* Nil]
62− ) OnConflictDoNothing (Returning Nil)
63 liftBase $ Char8.putStrLn "manipulating"
105 liftBase $ Char8.putStrLn "manipulating"
64− _insertResult <- manipulateParams insert
106+ idResults <- traversePrepared insertUser (Only . userName <$> users)
65− (1::Int32,2::Int32,3::Int32,4::Int32)
107+ ids <- traverse (fmap fromOnly . getRow (RowNumber 0)) idResults
108+ traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users))
66 liftBase $ Char8.putStrLn "querying"
109 liftBase $ Char8.putStrLn "querying"
67− result <- runQuery $
110+ usersResult <- runQuery getUsers
68− selectStar (from (Table (#table1 `As` #table1)))
111+ usersRows <- getRows usersResult
69− value00 <- getValue (RowNumber 0) (columnNumber @0) result
70− value01 <- getValue (RowNumber 0) (columnNumber @1) result
71− value10 <- getValue (RowNumber 1) (columnNumber @0) result
72− value11 <- getValue (RowNumber 1) (columnNumber @1) result
73− row0 <- getRow (RowNumber 0) result
74− row1 <- getRow (RowNumber 1) result
75− rows <- getRows result
76− liftBase $ do
112+ liftBase $ print (usersRows :: [User])
77− print (value00 :: Int32)
78− print (value01 :: Int32)
79− print (value10 :: Int32)
80− print (value11 :: Int32)
83− print (rows :: [Row])
84 Char8.putStrLn "tearing down schema"
113 Char8.putStrLn "tearing down schema"
85− connection3 <- flip execPQ (connection2 :: Connection Schema) $ define $
114+ connection3 <- execPQ (define teardown) connection2
86− dropTable #table1 >>> dropTable #students
87− finish (connection3 :: Connection '[])
115+ finish connection3