on dev help sign in
work generics and binary through
commit52c66eea9483511daba593165ac6c9555982c1f1 authorEitan Chatav <eitan.chatav@gmail.com> dateSat 12 Aug 2017, 14:12 (9 years ago) parent4d7616e
4 files changed+92−79
squeel-postgresql/exe/Example.hs+38−22 squeel-postgresql/src/Squeel/PostgreSQL.hs+2−2 squeel-postgresql/src/Squeel/PostgreSQL/Binary2.hs+25−2 squeel-postgresql/src/Squeel/PostgreSQL/PQ.hs+27−53
squeel-postgresql/exe/Example.hs+38−22
@@ -1,18 +1,19 @@
11{-# LANGUAGE
22 DataKinds
3+ , DeriveGeneric
4+ , FlexibleInstances
5+ , MultiParamTypeClasses
36 , OverloadedLabels
47 , OverloadedStrings
58 , TypeApplications
69 , TypeOperators
10+ , TypeSynonymInstances
711#-}
812
9−module Main (main) where
13+module Main (main,col1,col2) where
1014
1115import Control.Category ((>>>))
1216import Control.Monad.Base
13−import Control.Monad.Except
14−import Control.Monad.Trans.Maybe
15−import Data.Foldable (for_)
1617import Data.Function ((&))
1718import Data.Int
1819import Data.Monoid
@@ -20,6 +21,7 @@ import Generics.SOP hiding (from)
2021import Squeel.PostgreSQL
2122
2223import qualified Data.ByteString.Char8 as Char8
24+import qualified GHC.Generics as GHC
2325
2426main :: IO ()
2527main = do
@@ -40,26 +42,35 @@ main = do
4042 :* Nil ) []
4143 Char8.putStrLn "querying"
4244 connection2 <- runPQ (connection1 :: Connection Tables) $ do
43− for_ [I i :* I (i+1) :* Nil | i <- [1::Int32,3..9]] $ pqExecParams
44− ( insertInto #table1
45− (Values (param1 `As` #col1 :* param2 `As` #col2 :* Nil) [])
46− Conflict ReturningNil )
45+ let
46+ statement :: Manipulation Tables
47+ '[ 'Required ('NotNull 'PGInt4)
48+ , 'Required ('NotNull 'PGInt4)
49+ , 'Required ('NotNull 'PGInt4)
50+ , 'Required ('NotNull 'PGInt4)
51+ ] '[]
52+ statement =
53+ insertInto #table1
54+ (Values
55+ (param1 `As` #col1 :* param2 `As` #col2 :* Nil)
56+ [param3 `As` #col1 :* param4 `As` #col2 :* Nil] )
57+ Conflict ReturningNil
58+ _ <- pqExecParams statement (1::Int32,2::Int32,3::Int32,4::Int32)
4759 Just result <- pqExecNil . query $
4860 selectStar (from (Table (#table1 `As` #table1)))
49− runMaybeT . runExceptT . flip runValue result $ do
50− value00 <- getValue (RowNumber 0) (columnNumber @0)
51− value01 <- getValue (RowNumber 0) (columnNumber @1)
52− value10 <- getValue (RowNumber 1) (columnNumber @0)
53− value11 <- getValue (RowNumber 1) (columnNumber @1)
54− row0 <- getRow (RowNumber 0)
55− row1 <- getRow (RowNumber 1)
56− liftBase $ do
57− print (value00 :: Int32)
58− print (value01 :: Int32)
59− print (value10 :: Int32)
60− print (value11 :: Int32)
61− print (row0 :: NP I '[Int32,Int32])
62− print (row1 :: NP I '[Int32,Int32])
61+ value00 <- getValue (RowNumber 0) (columnNumber @0) result
62+ value01 <- getValue (RowNumber 0) (columnNumber @1) result
63+ value10 <- getValue (RowNumber 1) (columnNumber @0) result
64+ value11 <- getValue (RowNumber 1) (columnNumber @1) result
65+ row0 <- getRow (RowNumber 0) result
66+ row1 <- getRow (RowNumber 1) result
67+ liftBase $ do
68+ print (value00 :: Int32)
69+ print (value01 :: Int32)
70+ print (value10 :: Int32)
71+ print (value11 :: Int32)
72+ print (row0 :: ColumnsRecord)
73+ print (row1 :: ColumnsRecord)
6374 Char8.putStrLn "tearing down database"
6475 connection3 <- runPQ (connection2 :: Connection Tables) $ pqExec $
6576 dropTable #table1 >>> dropTable #students
@@ -69,5 +80,10 @@ type Columns =
6980 '[ "col1" ::: 'Required ('NotNull 'PGInt4)
7081 , "col2" ::: 'Required ('NotNull 'PGInt4)
7182 ]
83+data ColumnsRecord = ColumnsRecord { col1 :: Int32, col2 :: Int32 }
84+ deriving (Show, GHC.Generic)
85+instance Generic ColumnsRecord
86+instance FromRow Columns ColumnsRecord
87+
7288type StudentsColumns = '["name" ::: 'Required ('NotNull 'PGText)]
7389type Tables = '["students" ::: StudentsColumns, "table1" ::: Columns]
squeel-postgresql/src/Squeel/PostgreSQL.hs+2−2
@@ -1,11 +1,11 @@
11module Squeel.PostgreSQL
2− ( module Squeel.PostgreSQL.Binary
2+ ( module Squeel.PostgreSQL.Binary2
33 , module Squeel.PostgreSQL.PQ
44 , module Squeel.PostgreSQL.Schema
55 , module Squeel.PostgreSQL.Statement
66 ) where
77
8−import Squeel.PostgreSQL.Binary
8+import Squeel.PostgreSQL.Binary2
99import Squeel.PostgreSQL.PQ
1010import Squeel.PostgreSQL.Schema
1111import Squeel.PostgreSQL.Statement
squeel-postgresql/src/Squeel/PostgreSQL/Binary2.hs+25−2
@@ -74,7 +74,7 @@ instance ToParam x pg => ToColumnParam (Maybe x) ('Required ('Null pg)) where
7474instance ToParam x pg => ToColumnParam (Maybe x) ('Optional (nullity pg)) where
7575 toColumnParam = K . fmap (Encoding.encodingBytes . unK . toParam @x @pg)
7676
77−class ToParams x (tys :: [ColumnType]) where
77+class SListI tys => ToParams x (tys :: [ColumnType]) where
7878 toParams :: x -> NP (K (Maybe Strict.ByteString)) tys
7979 default toParams
8080 :: (IsProductType x xs, AllZip ToColumnParam xs tys)
@@ -82,6 +82,26 @@ class ToParams x (tys :: [ColumnType]) where
8282 toParams
8383 = htrans (Proxy @ToColumnParam) (toColumnParam . unI)
8484 . unZ . unSOP . from
85+instance ToParams () '[]
86+instance ToColumnParam x ty => ToParams x '[ty] where
87+ toParams x = toColumnParam x :* Nil
88+instance (ToColumnParam x1 ty1, ToColumnParam x2 ty2)
89+ => ToParams (x1,x2) '[ty1,ty2]
90+instance (ToColumnParam x1 ty1, ToColumnParam x2 ty2, ToColumnParam x3 ty3)
91+ => ToParams (x1,x2,x3) '[ty1,ty2,ty3]
92+instance
93+ ( ToColumnParam x1 ty1
94+ , ToColumnParam x2 ty2
95+ , ToColumnParam x3 ty3
96+ , ToColumnParam x4 ty4
97+ ) => ToParams (x1,x2,x3,x4) '[ty1,ty2,ty3,ty4]
98+instance
99+ ( ToColumnParam x1 ty1
100+ , ToColumnParam x2 ty2
101+ , ToColumnParam x3 ty3
102+ , ToColumnParam x4 ty4
103+ , ToColumnParam x5 ty5
104+ ) => ToParams (x1,x2,x3,x4,x5) '[ty1,ty2,ty3,ty4,ty5]
85105
86106class FromValue (pg :: PGType) y where
87107 fromValue :: proxy pg -> Decoding.Value y
@@ -139,7 +159,7 @@ instance FromValue pg y
139159 where
140160 err str = error $ "fromColumnValue: " ++ Strict.unpack str
141161
142−class FromRow (columns :: [(Symbol,ColumnType)]) y where
162+class SListI columns => FromRow (columns :: [(Symbol,ColumnType)]) y where
143163 fromRow :: NP (K (Maybe Strict.ByteString)) columns -> y
144164 default fromRow
145165 :: (IsProductType y ys, AllZip FromColumnValue columns ys)
@@ -147,3 +167,6 @@ class FromRow (columns :: [(Symbol,ColumnType)]) y where
147167 fromRow
148168 = to . SOP . Z
149169 . htrans (Proxy @FromColumnValue) (I . fromColumnValue)
170+instance FromRow '[] ()
171+instance FromColumnValue ty y => FromRow '[ty] y where
172+ fromRow (y :* Nil) = fromColumnValue y
squeel-postgresql/src/Squeel/PostgreSQL/PQ.hs+27−53
@@ -22,20 +22,16 @@ module Squeel.PostgreSQL.PQ where
2222import Control.Exception.Lifted
2323import Control.Monad.Base
2424import Control.Monad.Except
25−import Control.Monad.Trans.Maybe
2625import Control.Monad.Trans.Control
2726import Data.ByteString (ByteString)
2827import Data.Function ((&))
29−import Data.Maybe
30−import Data.Proxy (Proxy)
31−import Data.Text (Text)
3228import Generics.SOP
3329import GHC.Exts hiding (fromList)
3430import GHC.TypeLits
3531
3632import qualified Database.PostgreSQL.LibPQ as LibPQ
3733
38−import Squeel.PostgreSQL.Binary
34+import Squeel.PostgreSQL.Binary2
3935import Squeel.PostgreSQL.Statement
4036import Squeel.PostgreSQL.Schema
4137
@@ -104,28 +100,24 @@ pqThenExec = pqThen . pqExec
104100class Monad m => MonadPQ schema m | m -> schema where
105101
106102 pqExecParams
107− :: (ToOids ps, AllZip HasEncoding ps xs)
108− => Manipulation schema ps ys -> NP I xs -> m (Maybe (Result ys))
103+ :: ToParams x params
104+ => Manipulation schema params ys -> x -> m (Maybe (Result ys))
109105 default pqExecParams
110106 :: (MonadTrans t, MonadPQ schema m1, m ~ t m1)
111− => (ToOids ps, AllZip HasEncoding ps xs)
112− => Manipulation schema ps ys -> NP I xs -> m (Maybe (Result ys))
107+ => ToParams x params
108+ => Manipulation schema params ys -> x -> m (Maybe (Result ys))
113109 pqExecParams manipulation params = lift $ pqExecParams manipulation params
114110
115111 pqExecNil :: Manipulation schema '[] ys -> m (Maybe (Result ys))
116− pqExecNil statement = pqExecParams statement Nil
112+ pqExecNil statement = pqExecParams statement ()
117113
118114instance MonadBase IO io => MonadPQ schema (PQ schema schema io) where
119115
120− pqExecParams (UnsafeManipulation q :: Manipulation schema ps ys) params =
116+ pqExecParams (UnsafeManipulation q :: Manipulation schema ps ys) (params :: x) =
121117 PQ $ \ (Connection conn) -> do
122118 let
123− paramValues = encodings (Proxy :: Proxy ps) params
124− oids = toOids (proxy# :: Proxy# ps)
125− params' =
126− [ Just (oid, param', LibPQ.Binary)
127− | (oid, param') <- zip oids paramValues
128− ]
119+ toParam' bytes = (LibPQ.invalidOid,bytes,LibPQ.Binary)
120+ params' = fmap (fmap toParam') (hcollapse (toParams @x @ps params))
129121 result <- liftBase $ LibPQ.execParams conn q params' LibPQ.Binary
130122 return (Result <$> result, Connection conn)
131123
@@ -190,43 +182,25 @@ instance {-# OVERLAPPABLE #-}
190182 (KnownNat n, HasColumnNumber (n-1) columns column)
191183 => HasColumnNumber n (column' : columns) column
192184
193−newtype Value pgs m x = Value { runValue :: Result pgs -> m x }
194− deriving (Functor)
195−instance Applicative m => Applicative (Value pgs m) where
196− pure x = Value $ \ _result -> pure x
197− mf <*> mx = Value $ \ result -> runValue mf result <*> runValue mx result
198−instance Monad m => Monad (Value pgs m) where
199− return = pure
200− mx >>= f = Value $ \ result -> do
201− x <- runValue mx result
202− runValue (f x) result
203−instance MonadTrans (Value pgs) where
204− lift m = Value $ \ _result -> m
205−instance MonadBase b m => MonadBase b (Value pgs m) where
206− liftBase = lift . liftBase
207−
208185getValue
209− :: (HasDecoding pg x, MonadBase IO io)
186+ :: (FromColumnValue colty y, MonadBase IO io)
210187 => RowNumber
211− -> ColumnNumber n pgs pg
212− -> Value pgs (ExceptT Text (MaybeT io)) x
213−getValue (RowNumber r) (UnsafeColumnNumber c :: ColumnNumber n pgs pg) =
214− Value $ \ (Result result) -> do
215− maybeBytestring <- liftBase $ LibPQ.getvalue result r c
216− case maybeBytestring of
217− Nothing -> mzero
218− Just bytestring -> case decodeValue (Proxy :: Proxy pg) bytestring of
219− Left err -> throwError err
220− Right val -> return val
188+ -> ColumnNumber n columns colty
189+ -> Result columns
190+ -> io y
191+getValue
192+ (RowNumber r)
193+ (UnsafeColumnNumber c :: ColumnNumber n columns colty)
194+ (Result result)
195+ = fromColumnValue @colty . K <$>
196+ liftBase (LibPQ.getvalue result r c)
221197
222198getRow
223− :: (AllZip HasDecoding pgs xs, MonadBase IO io)
224− => RowNumber -> Value pgs (ExceptT Text (MaybeT io)) (NP I xs)
225−getRow (RowNumber r) = Value $ \ (Result result :: Result pgs) -> do
226− maybeBytestrings <- traverse (liftBase . LibPQ.getvalue result r)
227− [0 .. fromIntegral (lengthSList (Proxy :: Proxy pgs)) - 1]
228− case fromList (catMaybes maybeBytestrings) of
229− Nothing -> mzero
230− Just bytestrings -> case decodings (Proxy :: Proxy pgs) bytestrings of
231− Left err -> throwError err
232− Right row -> return row
199+ :: (FromRow columns y, MonadBase IO io)
200+ => RowNumber -> Result columns -> io y
201+getRow (RowNumber r) (Result result :: Result columns) = do
202+ let len = fromIntegral (lengthSList (Proxy @columns))
203+ row' <- traverse (liftBase . LibPQ.getvalue result r) [0 .. len - 1]
204+ case fromList row' of
205+ Nothing -> error "getRow: found unexpected length"
206+ Just row -> return $ fromRow @columns row