1414{-# LANGUAGE FlexibleInstances #-}
1515{-# LANGUAGE RecordWildCards #-}
1616{-# LANGUAGE CPP #-}
17+ {-# LANGUAGE LambdaCase #-}
1718
1819{-|
1920 Module: Database.PostgreSQL.Simple.Bind.Implementation
@@ -51,7 +52,7 @@ import Database.PostgreSQL.Simple.FromRow (FromRow(..))
5152import Database.PostgreSQL.Simple.Types (Query (.. ))
5253import GHC.TypeLits (Symbol )
5354import Language.Haskell.TH.Syntax (Q , Dec (.. ), Exp (.. ), Type (.. ), Clause (.. ), Body (.. ), Pat (.. ))
54- import Language.Haskell.TH.Syntax (Name , mkName , newName , Lit (.. ), TyLit (.. ), TyVarBndr (.. ))
55+ import Language.Haskell.TH.Syntax (Name , mkName , newName , Lit (.. ), TyLit (.. ), TyVarBndr (.. ), lift )
5556import qualified Data.ByteString.Char8 as BS
5657
5758-- | Mapping from PostgreSQL types to Haskell types.
@@ -65,41 +66,51 @@ mkFunction :: PostgresBindOptions -> PGFunction -> Q [Dec]
6566mkFunction opt f = sequence $ (($ f) . ($ opt)) <$> [mkFunctionT, mkFunctionE]
6667
6768#ifdef DebugQueries
68- data Argument = forall a . (Show a , ToField a ) => MandatoryArg String a
69- | forall a . (Show a , ToField a ) => OptionalArg String (Maybe a )
69+ data Argument = forall a . (Show a , ToField a ) => MandatoryArg String String a
70+ | forall a . (Show a , ToField a ) => OptionalArg String String (Maybe a )
7071
7172instance Show Argument where
72- show (MandatoryArg name value) = " mandatory: " ++ name ++ " => " ++ show value
73- show (OptionalArg name value) = " optional: " ++ name ++ " => " ++ show value
73+ show (MandatoryArg name atype value) = " mandatory: " ++ name ++ " => " ++ show value ++ " :: " ++ atype
74+ show (OptionalArg name atype value) = " optional: " ++ name ++ " => " ++ show value ++ " :: " ++ atype
7475#else
75- data Argument = forall a . (ToField a ) => MandatoryArg String a
76- | forall a . (ToField a ) => OptionalArg String (Maybe a )
76+ data Argument = forall a . (ToField a ) => MandatoryArg String String a
77+ | forall a . (ToField a ) => OptionalArg String String (Maybe a )
7778#endif
7879
7980instance ToField Argument where
80- toField (MandatoryArg _ x) = toField x
81- toField (OptionalArg _ (Just x)) = toField x
82- toField (OptionalArg name Nothing ) = throw . DefaultValueNotFound $ name
81+ toField (MandatoryArg _name _atype x) = toField x
82+ toField (OptionalArg _name _atype (Just x)) = toField x
83+ toField (OptionalArg name _atype Nothing ) = throw . DefaultValueNotFound $ name
8384
84- formatArgument :: Argument -> Maybe String
85- formatArgument (MandatoryArg _name _value) = Just " ?"
86- formatArgument (OptionalArg name (Just _value)) = Just $ name ++
85+
86+ callExpression :: String
8787#ifdef OlderCallSyntax
88- " := ? "
88+ callExpression = " := "
8989#else
90- " => ? "
90+ callExpression = " => "
9191#endif
9292
93- formatArgument (OptionalArg _name Nothing ) = Nothing
93+ formatArgument :: Bool -> Argument -> Maybe String
94+ formatArgument cast = format where
95+ format = \ case
96+ (MandatoryArg _name atype _value) -> Just $ placeholder atype
97+
98+ (OptionalArg name atype (Just _value)) -> Just . concat $ [
99+ name , callExpression, placeholder atype]
100+
101+ (OptionalArg _name _atype Nothing ) -> Nothing
102+
103+ placeholder atype = if cast then (" (?)::" ++ atype) else " ?"
104+
94105
95- formatArguments :: [Argument ] -> String
96- formatArguments = concat . (intersperse " ," ) . catMaybes . (map formatArgument)
106+ formatArguments :: Bool -> [Argument ] -> String
107+ formatArguments cast = concat . (intersperse " ," ) . catMaybes . (map $ formatArgument cast )
97108
98109filterArguments :: [Argument ] -> [Argument ]
99110filterArguments = filter isPresented where
100111 isPresented :: Argument -> Bool
101- isPresented (OptionalArg _name Nothing ) = False
102- isPresented _ = True
112+ isPresented (OptionalArg _name _atype Nothing ) = False
113+ isPresented _ = True
103114
104115
105116-- | Example: "varchar" -> PostgresType "varchar"
@@ -193,12 +204,17 @@ traceIdWrapE = id
193204-- (PGFunction "public" "foo"
194205-- [PGArgument "x" "varchar" True, PGArgument "y" "bigint" False] (PGSingle "varchar"))
195206-- args -> { Query $ BS.pack $ concat ["select public.foo (", (formatArguments args), ")"] }
196- mkSqlQuery :: PostgresBindOptions -> PGFunction -> Maybe Name -> Exp
207+ mkSqlQuery :: PostgresBindOptions -> PGFunction -> Maybe Name -> Q Exp
197208mkSqlQuery opt (PGFunction schema fname _args ret) argsName =
198- toQuery . traceIdWrapE . AppE (VarE 'concat) . ListE $ [
199- mkStrLit $ concat [prefix opt, " " , functionName, " (" ]
200- , maybe (mkStrLit " " ) (\ args -> (VarE 'formatArguments) `AppE ` (VarE args)) argsName
201- , mkStrLit " )" ] where
209+ lift (pboExplicitCasts opt) >>= \ cast ->
210+ return . toQuery . traceIdWrapE . AppE (VarE 'concat) . ListE $ [
211+ mkStrLit $ concat [prefix opt, " " , functionName, " (" ]
212+ , maybe (mkStrLit " " ) (\ args -> foldl1 AppE [
213+ VarE 'formatArguments
214+ , cast
215+ , VarE args
216+ ]) argsName
217+ , mkStrLit " )" ] where
202218
203219 prefix (PostgresBindOptions {.. }) = case ret of
204220 PGTable _ -> mkSelect AsRow
@@ -240,7 +256,7 @@ traceShowIdWrapE = id
240256-- [PGArgument "x" "varchar" True, PGArgument "y" "bigint" False] (PGSingle "varchar")) -> {
241257-- foo conn x1 x2 = query conn
242258-- (Query $ BS.pack $ concat ["select public.foo (", (formatArguments args), ")"])
243- -- (filterArguments [MandatoryArg "x1" x1, OptionalArg "x2" x2])
259+ -- (filterArguments [MandatoryArg "x1" x1, OptionalArg "x2" x2]) }
244260mkFunctionE :: PostgresBindOptions -> PGFunction -> Q Dec
245261mkFunctionE opt@ (PostgresBindOptions {.. }) f@ (PGFunction _schema _fname args ret) = do
246262 names <- sequence $ replicate (length args) (newName " x" )
@@ -250,18 +266,19 @@ mkFunctionE opt@(PostgresBindOptions {..}) f@(PGFunction _schema _fname args ret
250266 True -> return Nothing
251267 False -> Just <$> newName " args"
252268
253- let wrapArg (PGArgument n _ d) argName = foldl1 AppE $ case d of
254- False -> [( ConE 'MandatoryArg), ( LitE (StringL n)), ( VarE argName) ]
255- True -> [( ConE 'OptionalArg), ( LitE (StringL n)), ( VarE argName) ]
269+ let wrapArg (PGArgument n t d) argName = foldl1 AppE $ case d of
270+ False -> [ConE 'MandatoryArg, LitE (StringL n), LitE ( StringL t), VarE argName]
271+ True -> [ConE 'OptionalArg, LitE (StringL n), LitE ( StringL t), VarE argName]
256272
257273 let argsExpr = (VarE 'filterArguments) `AppE ` (ListE $ zipWith wrapArg args names)
258274
259275 let funcName = mkName $ pboFunctionName f
260276 let funcArgs = (VarP connName): (map VarP names)
277+ sqlQuery <- mkSqlQuery opt f argsName
261278 let funcBody = NormalB $ unwrapE opt ret $ foldl1 AppE $ [
262279 VarE $ maybe 'query_ (const 'query) argsName
263280 , VarE connName
264- , mkSqlQuery opt f argsName
281+ , sqlQuery
265282 ] ++ (const (traceShowIdWrapE argsExpr) <$> maybeToList argsName)
266283
267284 let decl = (\ name -> ValD (VarP name) (NormalB argsExpr) [] ) <$> maybeToList argsName
0 commit comments