packages feed

dsh-sql-0.2.0.0: src/Database/DSH/Backend/Sql/Opt/Properties/Cols.hs

{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE TemplateHaskell     #-}

-- | Infer the output schema of TableAlgebra operators.
module Database.DSH.Backend.Sql.Opt.Properties.Cols where

import qualified Data.Set.Monad                             as S


import           Database.Algebra.Table.Lang

import           Database.DSH.Common.Impossible
import           Database.DSH.Backend.Sql.Opt.Properties.Auxiliary
import           Database.DSH.Backend.Sql.Opt.Properties.Types

----------------------------------------------------------------------------
-- Type inference for tablealgebra expressions

isNumeric :: BinFun -> Bool
isNumeric f = f `elem` [Plus, Minus, Times, Div]

isComp :: BinFun -> Bool
isComp f = f `elem` [Gt, Lt, LtE, GtE, Eq, Contains, SimilarTo, Like]

isBool :: BinFun -> Bool
isBool f = f `elem` [And, Or]

binAppTy :: BinFun -> ATy -> ATy -> ATy
binAppTy f t1 _t2 =
    case f of
        Gt        -> ABool
        Lt        -> ABool
        LtE       -> ABool
        GtE       -> ABool
        Eq        -> ABool
        NEq       -> ABool
        Contains  -> ABool
        SimilarTo -> ABool
        Like      -> ABool
        And       -> ABool
        Or        -> ABool
        Plus      -> t1
        Minus     -> t1
        Times     -> t1
        Div       -> t1
        Modulo    -> AInt
        Concat    -> AStr
        Coalesce  -> t1

unAppTy :: UnFun -> ATy
unAppTy Not         = ABool
unAppTy (Cast t)    = t
unAppTy Sin         = ADouble
unAppTy Cos         = ADouble
unAppTy Tan         = ADouble
unAppTy ASin        = ADouble
unAppTy ACos        = ADouble
unAppTy ATan        = ADouble
unAppTy Log         = ADouble
unAppTy Sqrt        = ADouble
unAppTy Exp         = ADouble
unAppTy SubString{} = AStr
unAppTy DateDay     = AInt
unAppTy DateMonth   = AInt
unAppTy DateYear    = AInt
unAppTy IsNull      = ABool

valType :: AVal -> ATy
valType (VInt _)    = AInt
valType (VStr _)    = AStr
valType (VBool _)   = ABool
valType (VDouble _) = ADouble
valType (VDec _)    = ADec
valType (VDate _)   = ADate

exprTy :: S.Set TypedAttr -> Expr -> ATy
exprTy childCols expr =
    case expr of
        ColE c          -> typeOf c childCols
        ConstE v        -> valType v
        BinAppE f e1 e2 -> binAppTy f (exprTy childCols e1) (exprTy childCols e2)
        UnAppE f _      -> unAppTy f
        IfE _ t _       -> exprTy childCols t

----------------------------------------------------------------------------
-- Type inference for aggregate functions

numAggr :: ATy -> ATy
numAggr AInt    = AInt
numAggr ADec    = ADec
numAggr ADouble = ADouble
numAggr _       = $impossible

aggrTy :: S.Set TypedAttr -> (AggrType, Attr) -> TypedAttr
aggrTy childCols (aggr, resCol) = (resCol, resType)
  where
    resType = case aggr of
        All _     -> ABool
        Any _     -> ABool
        CountStar -> AInt
        Count _   -> AInt
        Avg e     -> numAggr $ exprTy childCols e
        Max e     -> numAggr $ exprTy childCols e
        Min e     -> numAggr $ exprTy childCols e
        Sum e     -> numAggr $ exprTy childCols e

winFunTy :: S.Set TypedAttr -> (WinFun, Attr) -> TypedAttr
winFunTy childCols (aggr, resCol) = (resCol, resType)
  where
    resType = case aggr of
        WinAll _        -> ABool
        WinAny _        -> ABool
        WinCount        -> AInt
        WinAvg e        -> numAggr $ exprTy childCols e
        WinMax e        -> numAggr $ exprTy childCols e
        WinMin e        -> numAggr $ exprTy childCols e
        WinSum e        -> numAggr $ exprTy childCols e
        WinFirstValue e -> exprTy childCols e
        WinLastValue e  -> exprTy childCols e

----------------------------------------------------------------------------
-- Schema inference for tablealgebra operators

inferColsNullOp :: NullOp -> S.Set TypedAttr
inferColsNullOp op =
    case op of
        LitTable (_, schema)   -> S.fromList schema
        TableRef (_, attrs, _) -> S.fromList attrs

inferColsUnOp :: S.Set TypedAttr -> UnOp -> S.Set TypedAttr
inferColsUnOp childCols op =
    case op of
        WinFun ((resCol, fun), _, _, _) -> S.insert (winFunTy childCols (fun, resCol)) childCols
        RowNum (resCol, _, _) -> S.insert (resCol, AInt) childCols
        RowRank (resCol, _)   -> S.insert (resCol, AInt) childCols
        Rank (resCol, _)      -> S.insert (resCol, AInt) childCols
        Project projs         -> S.fromList $ map (\(c, e) -> (c, exprTy childCols e)) projs
        Select _              -> childCols
        Distinct _            -> childCols
        Aggr (afuns, pexprs)  -> (S.fromList $ map (aggrTy childCols) afuns)
                                 ∪
                                 [ (c, exprTy childCols e) | (c, e) <- S.fromList pexprs ]
        Serialize (ref, key, ord, items) ->
            let cols = (S.fromList $ map (\(PayloadCol c _) -> c) items)
                       ∪ (S.fromList $ map (\(RefCol c _) -> c) ref)
                       ∪ (S.fromList $ map (\(OrdCol (c, _) _) -> c) ord)
                       ∪ (S.fromList $ map (\(KeyCol c _) -> c) key)
            in S.map (\c -> (c, typeOf c childCols)) cols

inferColsBinOp :: S.Set TypedAttr -> S.Set TypedAttr -> BinOp -> S.Set TypedAttr
inferColsBinOp leftCols rightCols op =
    case op of
        Cross _         -> S.union leftCols rightCols
        EqJoin _        -> S.union leftCols rightCols
        ThetaJoin _     -> S.union leftCols rightCols
        LeftOuterJoin _ -> S.union leftCols rightCols
        SemiJoin _      -> S.union leftCols rightCols
        AntiJoin _      -> S.union leftCols rightCols
        DisjUnion _     -> leftCols
        Difference _    -> leftCols