module Database.PostgreSQL.Typed.Internal
( stringE
, pattern StringE
, SQLSplit(..)
, sqlSplitExprs
, sqlSplitParams
) where
import Data.Char (isDigit)
import Data.String (IsString(..))
import qualified Language.Haskell.TH as TH
import Numeric (readDec)
stringE :: String -> TH.Exp
stringE = TH.LitE . TH.StringL
pattern StringE s = TH.LitE (TH.StringL s)
instance IsString TH.Exp where
fromString = stringE
data SQLSplit a (literal :: Bool) where
SQLLiteral :: String -> SQLSplit a 'False -> SQLSplit a 'True
SQLPlaceholder :: a -> SQLSplit a 'True -> SQLSplit a 'False
SQLSplitEnd :: SQLSplit a any
sqlCons :: Char -> SQLSplit a 'True -> SQLSplit a 'True
sqlCons c (SQLLiteral s l) = SQLLiteral (c : s) l
sqlCons c SQLSplitEnd = SQLLiteral [c] SQLSplitEnd
sqlSplitExprs :: String -> SQLSplit String 'True
sqlSplitExprs ('$':'$':'{':s) = sqlCons '$' $ sqlCons '{' $ sqlSplitExprs s
sqlSplitExprs ('$':'{':s)
| (e, '}':r) <- break (\c -> c == '{' || c == '}') s = SQLLiteral "" $ SQLPlaceholder e $ sqlSplitExprs r
| otherwise = error $ "Error parsing SQL: could not find end of expression: ${" ++ s
sqlSplitExprs (c:s) = sqlCons c $ sqlSplitExprs s
sqlSplitExprs [] = SQLSplitEnd
sqlSplitParams :: String -> SQLSplit Int 'True
sqlSplitParams ('$':'$':d:s) | isDigit d = sqlCons '$' $ sqlCons d $ sqlSplitParams s
sqlSplitParams ('$':s@(d:_)) | isDigit d, [(n, r)] <- readDec s = SQLLiteral "" $ SQLPlaceholder n $ sqlSplitParams r
sqlSplitParams (c:s) = sqlCons c $ sqlSplitParams s
sqlSplitParams [] = SQLSplitEnd