{-# 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 TransGraphAttributeNames = AttributeNamesBase TransactionIdLookup instance Binary TransGraphAttributeNames 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 transAttrNames expr) graph = do expr' <- evalTransGraphRelationalExpr expr graph attrNames <- evalTransAttributeNames transAttrNames 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 let expr' = evalTransGraphRelationalExpr expr graph Rename attrName1 attrName2 <$> expr' evalTransGraphRelationalExpr (Difference exprA exprB) graph = do exprA' <- evalTransGraphRelationalExpr exprA graph exprB' <- evalTransGraphRelationalExpr exprB graph pure (Difference exprA' exprB') evalTransGraphRelationalExpr (Group transAttrNames attrName expr) graph = do expr' <- evalTransGraphRelationalExpr expr graph attrNames <- evalTransAttributeNames transAttrNames graph pure (Group attrNames attrName expr') evalTransGraphRelationalExpr (Ungroup attrName expr) graph = do let expr' = evalTransGraphRelationalExpr expr graph 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') evalTransGraphRelationalExpr (With views expr) graph = do evaldViews <- mapM (\(vname, vexpr) -> do vexpr' <- evalTransGraphRelationalExpr vexpr graph pure (vname, vexpr') ) views expr' <- evalTransGraphRelationalExpr expr graph pure (With evaldViews expr') evalTransGraphTupleExpr :: TransactionGraph -> TransGraphTupleExpr -> Either RelationalError TupleExpr evalTransGraphTupleExpr graph (TupleExpr attrMap) = do let attrAssoc = mapM (\(attrName, atomExpr) -> do aExpr <- evalTransGraphAtomExpr graph atomExpr pure (attrName, aExpr) ) (M.toList attrMap) 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 let expr' = evalTransGraphRelationalExpr expr graph 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 let expr' = evalTransGraphRestrictionPredicateExpr expr graph NotPredicate <$> expr' evalTransGraphRestrictionPredicateExpr (RelationalExprPredicate expr) graph = do let expr' = evalTransGraphRelationalExpr expr graph RelationalExprPredicate <$> expr' evalTransGraphRestrictionPredicateExpr (AtomExprPredicate expr) graph = do let expr' = evalTransGraphAtomExpr graph expr AtomExprPredicate <$> expr' evalTransGraphRestrictionPredicateExpr (AttributeEqualityPredicate attrName expr) graph = do let expr' = evalTransGraphAtomExpr graph expr AttributeEqualityPredicate attrName <$> expr' evalTransGraphExtendTupleExpr :: TransGraphExtendTupleExpr -> TransactionGraph -> Either RelationalError ExtendTupleExpr evalTransGraphExtendTupleExpr (AttributeExtendTupleExpr attrName expr) graph = do let expr' = evalTransGraphAtomExpr graph expr 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)) M.empty pure (NakedAttributeExpr (Attribute attrName aType)) evalTransGraphAttributeExpr _ (NakedAttributeExpr attr) = pure (NakedAttributeExpr attr) evalTransAttributeNames :: TransGraphAttributeNames -> TransactionGraph -> Either RelationalError AttributeNames evalTransAttributeNames (AttributeNames names) _ = Right (AttributeNames names) evalTransAttributeNames (InvertedAttributeNames names) _ = Right (InvertedAttributeNames names) evalTransAttributeNames (UnionAttributeNames namesA namesB) graph = do nA <- evalTransAttributeNames namesA graph nB <- evalTransAttributeNames namesB graph Right (UnionAttributeNames nA nB) evalTransAttributeNames (IntersectAttributeNames namesA namesB) graph = do nA <- evalTransAttributeNames namesA graph nB <- evalTransAttributeNames namesB graph Right (IntersectAttributeNames nA nB) evalTransAttributeNames (RelationalExprAttributeNames expr) graph = do evaldExpr <- evalTransGraphRelationalExpr expr graph Right (RelationalExprAttributeNames evaldExpr)