Skip to content

Commit bb6c284

Browse files
Simple session
1 parent 2682d6a commit bb6c284

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

Session.hs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
{-# language ApplicativeDo #-}
2+
{-# language OverloadedLists #-}
3+
{-# language OverloadedStrings #-}
4+
{-# language ExistentialQuantification #-}
5+
{-# language TypeSynonymInstances #-}
6+
{-# language FlexibleInstances #-}
7+
module Database.PostgreSQL.Session where
8+
9+
import Control.Monad
10+
import Control.Applicative
11+
import Data.Monoid
12+
import Data.Int
13+
import Data.ByteString (ByteString)
14+
import Data.Either
15+
import qualified Data.Vector as V
16+
17+
import PostgreSQL.Binary.Encoder (int8_int64, run)
18+
import qualified PostgreSQL.Binary.Decoder as D(int, run)
19+
20+
import Database.PostgreSQL.Protocol.Types
21+
import Database.PostgreSQL.Connection
22+
import Database.PostgreSQL.Settings
23+
24+
data Count = One | Many
25+
deriving (Eq, Show)
26+
27+
data Session a
28+
= Done a
29+
| forall r . Decode r => Receive (r -> Session a)
30+
| Send Count [Query] (Session a)
31+
32+
instance Functor Session where
33+
f `fmap` (Done a) = Done $ f a
34+
f `fmap` (Receive g) = Receive $ fmap f . g
35+
f `fmap` (Send n br c) = Send n br (f <$> c)
36+
37+
instance Applicative Session where
38+
pure = Done
39+
40+
f <*> x = case (f, x) of
41+
(Done g, Done y) -> Done (g y)
42+
(Done g, Receive next) -> Receive $ fmap g . next
43+
(Done g, Send n br c) -> Send n br (g <$> c)
44+
45+
(Send n br c, Done y) -> Send n br (c <*> pure y)
46+
(Send n br c, Receive next)
47+
-> Send n br $ c <*> Receive next
48+
(Send n1 br1 c1, Send n2 br2 c2)
49+
-> if n1 == One
50+
then Send n2 (br1 <> br2) (c1 <*> c2)
51+
else Send n1 br1 (c1 <*> Send n2 br2 c2)
52+
53+
(Receive next1, Receive next2) ->
54+
Receive $ (\g -> Receive $ (g <*> ) . next2) . next1
55+
(Receive next, Done y) -> Receive $ (<*> Done y) . next
56+
(Receive next, Send n br c)
57+
-> Receive $ (<*> Send n br c) . next
58+
59+
instance Monad Session where
60+
return = pure
61+
62+
m >>= f = case m of
63+
Done a -> f a
64+
Receive g -> Receive $ (>>=f) . g
65+
Send _n br c -> Send Many br (c >>= f)
66+
67+
(>>) = (*>)
68+
69+
class Encode a where
70+
encode :: a -> ByteString
71+
getOid :: a -> Oid
72+
73+
class Decode a where
74+
decode :: ByteString -> a
75+
76+
instance Encode Int64 where
77+
encode = run int8_int64
78+
getOid _ = Oid 20
79+
80+
instance Decode Int64 where
81+
decode = fromRight . D.run D.int
82+
where
83+
fromRight (Right v) = v
84+
fromRight _ = error "bad fromRight"
85+
86+
data SessionQuery a b = SessionQuery { sqStatement :: ByteString }
87+
deriving (Show)
88+
89+
query :: (Encode a, Decode b) => SessionQuery a b -> a -> Session b
90+
query sq val =
91+
let q = Query { qStatement = sqStatement sq
92+
, qOids = [getOid val]
93+
, qValues = [encode val]
94+
, qParamsFormat = Binary
95+
, qResultFormat = Binary }
96+
in Send One [q] $ Receive Done
97+
98+
runSession :: Show a => Connection -> Session a -> IO (Either Error a)
99+
runSession conn = go 0
100+
where
101+
go n (Done x) = do
102+
putStrLn $ "Return " ++ show x
103+
when (n > 0) $ void $ sendSync conn >> readReadyForQuery conn
104+
pure $ Right x
105+
go n (Receive f) = do
106+
putStrLn "Receiving"
107+
r <- readNextData conn
108+
case r of
109+
Left e -> pure $ Left e
110+
Right (DataMessage rows) -> go n (f $ decode $ V.head $ head rows)
111+
go n (Send _ qs c) = do
112+
putStrLn "Sending requests "
113+
sendBatch conn qs
114+
sendFlush conn
115+
go (n + 1) c
116+
117+
q1 :: SessionQuery Int64 Int64
118+
q1 = SessionQuery "SELECT $1"
119+
120+
q2 :: SessionQuery Int64 Int64
121+
q2 = SessionQuery "SELECT count(*) from a where v < $1"
122+
123+
q3 :: SessionQuery Int64 Int64
124+
q3 = SessionQuery "SELECT 5 + $1"
125+
126+
testSession :: IO ()
127+
testSession = do
128+
c <- connect defaultConnectionSettings
129+
r <- runSession c $ do
130+
b <- query q1 10
131+
a <- query q2 b
132+
query q3 a
133+
print r
134+
close c
135+

0 commit comments

Comments
 (0)