module HESQL.Syntax where import Database.HDBC (SqlValue(..)) import Data.List (intercalate) type ModuleName = String type DeclName = String type Vars = [String] type TableName = String type ColName = String type ColAlias = String type FunName = String data HesqlModule = HesqlModule ModuleName [HesqlDecls] deriving (Show) data HesqlDecls = HesqlDecls { declName :: DeclName , declVars :: Vars , declSQL :: SQL } deriving Show data SQL = SELECT [SelectOption] SelectColumns (Maybe From) (Maybe SqlExp) (Maybe SqlOrder) (Maybe Group) | INSERT TableName InsertColumns [SqlExp] | UPDATE TableName [(ColName, SqlExp)] (Maybe SqlExp) | DELETE TableName (Maybe SqlExp) | DummySQL data SqlExp = SqlFunApp FunName [SqlExp] | SqlInfixApp SqlExp SqlInfixOp SqlExp | SqlPlaceHolder String | SqlLiteral SqlValue | SqlColumn ColName | SqlNot SqlExp deriving Show data SqlInfixOp = SqlEqual | SqlLike | SqlLess | SqlGreater | SqlEqualOrGreater | SqlEqualOrLess | SqlAnd | SqlOr | SqlIs | SqlPlus | SqlMult | SqlMinus | SqlDiv deriving Show data SqlOrderDirection = ASC | DESC deriving Show type SqlOrder = [(SqlExp, Maybe SqlOrderDirection)] instance Show SQL where show = sqlToString infixPrio SqlEqual = 3 infixPrio SqlLike = 3 infixPrio SqlLess = 3 infixPrio SqlGreater = 3 infixPrio SqlIs = 3 infixPrio SqlAnd = 4 infixPrio SqlOr = 5 infixPrio SqlPlus = 1 infixPrio SqlMinus = 1 infixPrio SqlMult = 2 infixPrio SqlDiv = 2 sqlToString :: SQL -> String sqlToString DummySQL = "" sqlToString (SELECT _ cols from wh order group) = "select " ++ showColumns cols ++ showFrom from ++ showWhere wh ++ showOrder order -- TODO where order group sqlToString (INSERT tab spec vals) = "insert into " ++ tab ++ " " ++ (withParens $ comaSepList spec) ++ " values " ++ (withParens $ comaSepList $ map showSqlExp vals) sqlToString (UPDATE tab updates wh) = "update " ++ tab ++ " set " ++ (comaSepList $ map updateStr updates) ++ showWhere wh where updateStr (col, e) = col ++ " = " ++ showSqlExp e sqlToString (DELETE tab wh) = "delete from " ++ tab ++ showWhere wh showColumns :: SelectColumns -> String showColumns (ExplicitColumns cols) = comaSepList $ map (showSqlExp . fst) cols -- TODO Alias showColumns _ = todo "showColumns" showFrom Nothing = "" showFrom (Just table) = " from " ++ table showWhere Nothing = "" showWhere (Just sqlExp) = " where " ++ showSqlExp sqlExp showOrder Nothing = "" showOrder (Just sqlOrder) = " order by " ++ (comaSepList $ map orderStr sqlOrder) where orderStr (sqlExp, Nothing) = showSqlExp sqlExp orderStr (sqlExp, Just order) = showSqlExp sqlExp ++ " " ++ show order showSqlExp = showSqlExp' 5 showSqlExp' p (SqlColumn n) = n showSqlExp' p (SqlInfixApp a op b) = par (showSqlExp' p' a ++ " " ++ infixOpToString op ++ " " ++ showSqlExp' p' b) where par = if p' > p then withParens else id p' = infixPrio op showSqlExp' p (SqlPlaceHolder _) = "?" showSqlExp' p (SqlFunApp f args) = f ++ (withParens $ comaSepList $ map showSqlExp args) showSqlExp' p (SqlLiteral v) = showSqlValue v showSqlExp' p (SqlNot e) = "not " ++ showSqlExp e showSqlValue (SqlBool b) = show b showSqlValue SqlNull = "null" showSqlValue (SqlString s) = "'" ++ s ++ "'" showSqlValue (SqlInteger i) = show i showSqlValue (SqlDouble d) = show d comaSepList = intercalate ", " withParens s = "(" ++ s ++ ")" todo s = error ("TODO " ++ s) data SelectOption = Strict | ReturnMaybe deriving (Show, Eq) data SelectColumns = AllColumns | ExplicitColumns [(SqlExp, Maybe ColAlias)] deriving Show -- data From = FromSubQuery SQL | FromTables [(TableName, TableAlias)] deriving Show type From = TableName type InsertColumns = [ColName] type TableAlias = String type Group = () infixOpToString SqlEqual = "=" infixOpToString SqlLike = "like" infixOpToString SqlGreater = ">" infixOpToString SqlEqualOrGreater = ">=" infixOpToString SqlEqualOrLess = "<=" infixOpToString SqlLess = "<" infixOpToString SqlAnd = "and" infixOpToString SqlOr = "or" infixOpToString SqlIs = "is" infixOpToString SqlPlus = "+" infixOpToString SqlMinus = "-" infixOpToString SqlDiv = "/" infixOpToString SqlMult = "*" isSelect (SELECT _ _ _ _ _ _) = True isSelect _ = False selectOpts :: SQL -> [SelectOption] selectOpts (SELECT opts _ _ _ _ _) = opts selectOpts _ = [] selectColumns (SELECT _ cols _ _ _ _) = cols