project-m36-0.1: src/lib/ProjectM36/TransGraphRelationalExpression.hs
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
--really, a better name for this module could be "TransTransactionGraphRelationalExpr", but that name is too long
module ProjectM36.TransGraphRelationalExpression where
import ProjectM36.Base
import ProjectM36.TransactionGraph
import ProjectM36.Transaction
import ProjectM36.RelationalExpression
import ProjectM36.Error
import ProjectM36.Tuple
import ProjectM36.AtomType
import qualified Data.Map as M
import Control.Monad.Trans.Reader
import Data.Binary
-- | The TransGraphRelationalExpression is equivalent to a relational expression except that relation variables can reference points in the transaction graph (at previous points in time).
type TransGraphRelationalExpr = RelationalExprBase TransactionIdLookup
instance Binary TransGraphRelationalExpr
type TransGraphExtendTupleExpr = ExtendTupleExprBase TransactionIdLookup
instance Binary TransGraphExtendTupleExpr
type TransGraphTupleExpr = TupleExprBase TransactionIdLookup
instance Binary TransGraphTupleExpr
type TransGraphRestrictionPredicateExpr = RestrictionPredicateExprBase TransactionIdLookup
instance Binary TransGraphRestrictionPredicateExpr
type TransGraphAtomExpr = AtomExprBase TransactionIdLookup
instance Binary TransGraphAtomExpr
type TransGraphAttributeExpr = AttributeExprBase TransactionIdLookup
-- OUTDATED a previous attempt at this function attempted to convert TransGraphRelationalExpr to RelationalExpr by resolving the transaction lookups. However, there is no way to resolve a FunctionAtomExpr to an Atom without fully evaluating the higher levels (TupleExpr, etc.). An anonymous function expression cannot be serialized, so that workaround is out. Still, I suspect we can reuse the existing static optimizer logic to work on both structures. The current conversion reduces the chance of whole-query optimization due to full-evaluation on top of full-evaluation, so this function would benefit from some re-design.
evalTransGraphRelationalExpr :: TransGraphRelationalExpr -> TransactionGraph -> Either RelationalError RelationalExpr
evalTransGraphRelationalExpr (MakeRelationFromExprs mAttrExprs tupleExprs) graph = do
tupleExprs' <- mapM (evalTransGraphTupleExpr graph) tupleExprs
case mAttrExprs of
Nothing -> pure (MakeRelationFromExprs Nothing tupleExprs')
Just attrExprs -> do
attrExprs' <- mapM (evalTransGraphAttributeExpr graph) attrExprs
pure (MakeRelationFromExprs (Just attrExprs') tupleExprs')
evalTransGraphRelationalExpr (MakeStaticRelation attrs tupSet) _ = pure (MakeStaticRelation attrs tupSet)
evalTransGraphRelationalExpr (ExistingRelation rel) _ = pure (ExistingRelation rel)
evalTransGraphRelationalExpr (RelationVariable rvname transLookup) graph = do
trans <- lookupTransaction graph transLookup
rel <- runReader (evalRelationalExpr (RelationVariable rvname ())) (RelationalExprStateElems (concreteDatabaseContext trans))
pure (ExistingRelation rel)
evalTransGraphRelationalExpr (Project attrNames expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (Project attrNames expr')
evalTransGraphRelationalExpr (Union exprA exprB) graph = do
exprA' <- evalTransGraphRelationalExpr exprA graph
exprB' <- evalTransGraphRelationalExpr exprB graph
pure (Union exprA' exprB')
evalTransGraphRelationalExpr (Join exprA exprB) graph = do
exprA' <- evalTransGraphRelationalExpr exprA graph
exprB' <- evalTransGraphRelationalExpr exprB graph
pure (Join exprA' exprB')
evalTransGraphRelationalExpr (Rename attrName1 attrName2 expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (Rename attrName1 attrName2 expr')
evalTransGraphRelationalExpr (Difference exprA exprB) graph = do
exprA' <- evalTransGraphRelationalExpr exprA graph
exprB' <- evalTransGraphRelationalExpr exprB graph
pure (Difference exprA' exprB')
evalTransGraphRelationalExpr (Group attrNames attrName expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (Group attrNames attrName expr')
evalTransGraphRelationalExpr (Ungroup attrName expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (Ungroup attrName expr')
evalTransGraphRelationalExpr (Restrict predicateExpr expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
predicateExpr' <- evalTransGraphRestrictionPredicateExpr predicateExpr graph
pure (Restrict predicateExpr' expr')
evalTransGraphRelationalExpr (Equals exprA exprB) graph = do
exprA' <- evalTransGraphRelationalExpr exprA graph
exprB' <- evalTransGraphRelationalExpr exprB graph
pure (Equals exprA' exprB')
evalTransGraphRelationalExpr (NotEquals exprA exprB) graph = do
exprA' <- evalTransGraphRelationalExpr exprA graph
exprB' <- evalTransGraphRelationalExpr exprB graph
pure (NotEquals exprA' exprB')
evalTransGraphRelationalExpr (Extend extendExpr expr) graph = do
extendExpr' <- evalTransGraphExtendTupleExpr extendExpr graph
expr' <- evalTransGraphRelationalExpr expr graph
pure (Extend extendExpr' expr')
evalTransGraphTupleExpr :: TransactionGraph -> TransGraphTupleExpr -> Either RelationalError TupleExpr
evalTransGraphTupleExpr graph (TupleExpr attrMap) = do
attrAssoc <- mapM (\(attrName, atomExpr) -> do
aExpr <- evalTransGraphAtomExpr graph atomExpr
pure (attrName, aExpr)
) (M.toList attrMap)
pure (TupleExpr (M.fromList attrAssoc))
evalTransGraphAtomExpr :: TransactionGraph -> TransGraphAtomExpr -> Either RelationalError AtomExpr
evalTransGraphAtomExpr _ (AttributeAtomExpr aname) = pure $ AttributeAtomExpr aname
evalTransGraphAtomExpr _ (NakedAtomExpr atom) = pure $ NakedAtomExpr atom
evalTransGraphAtomExpr graph (FunctionAtomExpr funcName args tLookup) = do
trans <- lookupTransaction graph tLookup
--I can't return a FunctionAtomExpr because the function needs to be resolved at a specific context
args' <- mapM (evalTransGraphAtomExpr graph) args
atom <- runReader (evalAtomExpr emptyTuple (FunctionAtomExpr funcName args' ())) (RelationalExprStateElems (concreteDatabaseContext trans))
pure (NakedAtomExpr atom)
evalTransGraphAtomExpr graph (RelationAtomExpr expr) = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (RelationAtomExpr expr')
evalTransGraphAtomExpr graph (ConstructedAtomExpr dConsName args tLookup) = do
trans <- lookupTransaction graph tLookup
args' <- mapM (evalTransGraphAtomExpr graph) args
atom <- runReader (evalAtomExpr emptyTuple (ConstructedAtomExpr dConsName args' ())) (RelationalExprStateElems (concreteDatabaseContext trans))
pure (NakedAtomExpr atom)
evalTransGraphRestrictionPredicateExpr :: TransGraphRestrictionPredicateExpr -> TransactionGraph -> Either RelationalError RestrictionPredicateExpr
evalTransGraphRestrictionPredicateExpr TruePredicate _ = pure TruePredicate
evalTransGraphRestrictionPredicateExpr (AndPredicate exprA exprB) graph = do
exprA' <- evalTransGraphRestrictionPredicateExpr exprA graph
exprB' <- evalTransGraphRestrictionPredicateExpr exprB graph
pure (AndPredicate exprA' exprB')
evalTransGraphRestrictionPredicateExpr (OrPredicate exprA exprB) graph = do
exprA' <- evalTransGraphRestrictionPredicateExpr exprA graph
exprB' <- evalTransGraphRestrictionPredicateExpr exprB graph
pure (OrPredicate exprA' exprB')
evalTransGraphRestrictionPredicateExpr (NotPredicate expr) graph = do
expr' <- evalTransGraphRestrictionPredicateExpr expr graph
pure (NotPredicate expr')
evalTransGraphRestrictionPredicateExpr (RelationalExprPredicate expr) graph = do
expr' <- evalTransGraphRelationalExpr expr graph
pure (RelationalExprPredicate expr')
evalTransGraphRestrictionPredicateExpr (AtomExprPredicate expr) graph = do
expr' <- evalTransGraphAtomExpr graph expr
pure (AtomExprPredicate expr')
evalTransGraphRestrictionPredicateExpr (AttributeEqualityPredicate attrName expr) graph = do
expr' <- evalTransGraphAtomExpr graph expr
pure (AttributeEqualityPredicate attrName expr')
evalTransGraphExtendTupleExpr :: TransGraphExtendTupleExpr -> TransactionGraph -> Either RelationalError ExtendTupleExpr
evalTransGraphExtendTupleExpr (AttributeExtendTupleExpr attrName expr) graph = do
expr' <- evalTransGraphAtomExpr graph expr
pure (AttributeExtendTupleExpr attrName expr')
evalTransGraphAttributeExpr :: TransactionGraph -> TransGraphAttributeExpr -> Either RelationalError AttributeExpr
evalTransGraphAttributeExpr graph (AttributeAndTypeNameExpr attrName tCons tLookup) = do
trans <- lookupTransaction graph tLookup
aType <- atomTypeForTypeConstructor tCons (typeConstructorMapping (concreteDatabaseContext trans))
pure (NakedAttributeExpr (Attribute attrName aType))
evalTransGraphAttributeExpr _ (NakedAttributeExpr attr) = pure (NakedAttributeExpr attr)