{-# LANGUAGE GADTs, FlexibleContexts, FlexibleInstances #-} {-# LANGUAGE CPP, DataKinds #-} -- | The expression type underlying 'Col'. module Database.Selda.Exp where import Database.Selda.SqlType ( Lit, SqlTypeRep ) import Database.Selda.Types ( ColName ) import Data.Text (Text) -- | A type-erased column, which may also be renamed. -- Only for internal use. data SomeCol sql where Some :: !(Exp sql a) -> SomeCol sql Named :: !ColName -> !(Exp sql a) -> SomeCol sql data UntypedCol sql where Untyped :: !(Exp sql a) -> UntypedCol sql -- | Turn a renamed column back into a regular one. -- If the column was renamed, it will be represented by a literal column, -- and not its original expression. hideRenaming :: SomeCol sql -> UntypedCol sql hideRenaming (Named n _) = Untyped (Col n) hideRenaming (Some c) = Untyped c -- | Underlying column expression type, parameterised over the type of -- SQL queries. data Exp sql a where Col :: !ColName -> Exp sql a Lit :: !(Lit a) -> Exp sql a BinOp :: !(BinOp a b c) -> !(Exp sql a) -> !(Exp sql b) -> Exp sql c UnOp :: !(UnOp a b) -> !(Exp sql a) -> Exp sql b NulOp :: !(NulOp a) -> Exp sql a Fun2 :: !Text -> !(Exp sql a) -> !(Exp sql b) -> Exp sql c If :: !(Exp sql Bool) -> !(Exp sql a) -> !(Exp sql a) -> Exp sql a Cast :: !SqlTypeRep -> !(Exp sql a) -> Exp sql b Raw :: !Text -> Exp sql a AggrEx :: !Text -> !(Exp sql a) -> Exp sql b InList :: !(Exp sql a) -> ![Exp sql a] -> Exp sql Bool InQuery :: !(Exp sql a) -> !sql -> Exp sql Bool data NulOp a where Fun0 :: !Text -> NulOp a data UnOp a b where Abs :: UnOp a a Not :: UnOp Bool Bool Neg :: UnOp a a Sgn :: UnOp a a IsNull :: UnOp (Maybe a) Bool Fun :: !Text -> UnOp a b data BinOp a b c where Gt :: BinOp a a Bool Lt :: BinOp a a Bool Gte :: BinOp a a Bool Lte :: BinOp a a Bool Eq :: BinOp a a Bool Neq :: BinOp a a Bool And :: BinOp Bool Bool Bool Or :: BinOp Bool Bool Bool Add :: BinOp a a a Sub :: BinOp a a a Mul :: BinOp a a a Div :: BinOp a a a Like :: BinOp Text Text Bool CustomOp :: !Text -> BinOp a b c -- | Any type which may contain column names. class Names a where -- | Get all column names used in the given expression. allNamesIn :: a -> [ColName] instance Names a => Names [a] where allNamesIn = concatMap allNamesIn instance Names sql => Names (Exp sql a) where allNamesIn (Col n) = [n] allNamesIn (Lit _) = [] allNamesIn (BinOp _ a b) = allNamesIn a ++ allNamesIn b allNamesIn (UnOp _ a) = allNamesIn a allNamesIn (NulOp _) = [] allNamesIn (Fun2 _ a b) = allNamesIn a ++ allNamesIn b allNamesIn (If a b c) = allNamesIn a ++ allNamesIn b ++ allNamesIn c allNamesIn (Cast _ x) = allNamesIn x allNamesIn (AggrEx _ x) = allNamesIn x allNamesIn (InList x xs) = concatMap allNamesIn (x:xs) allNamesIn (InQuery x q) = allNamesIn x ++ allNamesIn q allNamesIn (Raw _) = [] instance Names sql => Names (SomeCol sql) where allNamesIn (Some c) = allNamesIn c allNamesIn (Named n c) = n : allNamesIn c instance Names sql => Names (UntypedCol sql) where allNamesIn (Untyped c) = allNamesIn c