project-m36-0.6: src/bin/TutorialD/Interpreter/RODatabaseContextOperator.hs
{-# LANGUAGE GADTs #-}
module TutorialD.Interpreter.RODatabaseContextOperator where
import ProjectM36.Base
import qualified ProjectM36.DataFrame as DF
import ProjectM36.Error
import ProjectM36.InclusionDependency
import qualified ProjectM36.Client as C
import TutorialD.Interpreter.Base
import TutorialD.Interpreter.RelationalExpr
import TutorialD.Interpreter.DatabaseContextExpr
import Control.Monad.State
import qualified Data.Text as T
import ProjectM36.Relation.Show.Gnuplot
import qualified Data.Map as M
import Data.Maybe
--operators which only rely on database context reading
data RODatabaseContextOperator where
ShowRelation :: RelationalExpr -> RODatabaseContextOperator
PlotRelation :: RelationalExpr -> RODatabaseContextOperator
ShowRelationType :: RelationalExpr -> RODatabaseContextOperator
ShowConstraint :: StringType -> RODatabaseContextOperator
ShowPlan :: DatabaseContextExpr -> RODatabaseContextOperator
ShowTypes :: RODatabaseContextOperator
ShowRelationVariables :: RODatabaseContextOperator
ShowAtomFunctions :: RODatabaseContextOperator
ShowDatabaseContextFunctions :: RODatabaseContextOperator
ShowDataFrame :: DF.DataFrameExpr -> RODatabaseContextOperator
Quit :: RODatabaseContextOperator
deriving (Show)
typeP :: Parser RODatabaseContextOperator
typeP = do
reservedOp ":type"
ShowRelationType <$> relExprP
showRelP :: Parser RODatabaseContextOperator
showRelP = do
reservedOp ":showexpr"
ShowRelation <$> relExprP
showPlanP :: Parser RODatabaseContextOperator
showPlanP = do
reservedOp ":showplan"
ShowPlan <$> databaseContextExprP
showTypesP :: Parser RODatabaseContextOperator
showTypesP = reserved ":showtypes" >> pure ShowTypes
showRelationVariables :: Parser RODatabaseContextOperator
showRelationVariables = reserved ":showrelvars" >> pure ShowRelationVariables
showAtomFunctionsP :: Parser RODatabaseContextOperator
showAtomFunctionsP = reserved ":showatomfunctions" >> pure ShowAtomFunctions
showDatabaseContextFunctionsP :: Parser RODatabaseContextOperator
showDatabaseContextFunctionsP = reserved ":showdatabasecontextfunctions" >> pure ShowDatabaseContextFunctions
quitP :: Parser RODatabaseContextOperator
quitP = do
reservedOp ":quit"
return Quit
showConstraintsP :: Parser RODatabaseContextOperator
showConstraintsP = do
reservedOp ":constraints"
ShowConstraint <$> option "" identifier
plotRelExprP :: Parser RODatabaseContextOperator
plotRelExprP = do
reserved ":plotexpr"
PlotRelation <$> relExprP
roDatabaseContextOperatorP :: Parser RODatabaseContextOperator
roDatabaseContextOperatorP = typeP
<|> showRelP
<|> showRelationVariables
<|> plotRelExprP
<|> showConstraintsP
<|> showPlanP
<|> showTypesP
<|> showAtomFunctionsP
<|> showDatabaseContextFunctionsP
<|> showDataFrameP
<|> quitP
--logically, these read-only operations could happen purely, but not if a remote call is required
evalRODatabaseContextOp :: C.SessionId -> C.Connection -> RODatabaseContextOperator -> IO TutorialDOperatorResult
evalRODatabaseContextOp sessionId conn (ShowRelationType expr) = do
res <- C.typeForRelationalExpr sessionId conn expr
case res of
Left err -> pure $ DisplayErrorResult $ T.pack (show err)
Right rel -> pure $ DisplayRelationResult rel
evalRODatabaseContextOp sessionId conn (ShowRelation expr) = do
res <- C.executeRelationalExpr sessionId conn expr
case res of
Left err -> pure $ DisplayErrorResult $ T.pack (show err)
Right rel -> pure $ DisplayRelationResult rel
evalRODatabaseContextOp sessionId conn (PlotRelation expr) = do
res <- C.executeRelationalExpr sessionId conn expr
pure $ case res of
Left err -> DisplayErrorResult $ T.pack (show err)
Right rel -> DisplayIOResult $ do
err <- plotRelation rel
when (isJust err) $ print err
evalRODatabaseContextOp sessionId conn (ShowConstraint name) = do
eIncDeps <- C.inclusionDependencies sessionId conn
let val = case eIncDeps of
Left err -> Left err
Right incDeps -> case name of
"" -> inclusionDependenciesAsRelation incDeps
depName -> case M.lookup depName incDeps of
Nothing -> Left (InclusionDependencyNameNotInUseError depName)
Just dep -> inclusionDependenciesAsRelation (M.singleton depName dep)
pure $ case val of
Left err -> DisplayErrorResult (T.pack (show err))
Right rel -> DisplayRelationResult rel
evalRODatabaseContextOp sessionId conn (ShowPlan dbExpr) = do
plan <- C.planForDatabaseContextExpr sessionId conn dbExpr
pure $ case plan of
Left err -> DisplayErrorResult (T.pack (show err))
Right optDbExpr -> DisplayResult $ T.pack (show optDbExpr)
evalRODatabaseContextOp sessionId conn ShowTypes = do
eRel <- C.atomTypesAsRelation sessionId conn
case eRel of
Left err -> pure $ DisplayErrorResult (T.pack (show err))
Right rel -> evalRODatabaseContextOp sessionId conn (ShowRelation (ExistingRelation rel))
evalRODatabaseContextOp sessionId conn ShowRelationVariables = do
eRel <- C.relationVariablesAsRelation sessionId conn
case eRel of
Left err -> pure $ DisplayErrorResult (T.pack (show err))
Right rel -> evalRODatabaseContextOp sessionId conn (ShowRelation (ExistingRelation rel))
evalRODatabaseContextOp sessionId conn ShowAtomFunctions = do
eRel <- C.atomFunctionsAsRelation sessionId conn
case eRel of
Left err -> pure $ DisplayErrorResult (T.pack (show err))
Right rel -> evalRODatabaseContextOp sessionId conn (ShowRelation (ExistingRelation rel))
evalRODatabaseContextOp sessionId conn ShowDatabaseContextFunctions = do
eRel <- C.databaseContextFunctionsAsRelation sessionId conn
case eRel of
Left err -> pure $ DisplayErrorResult (T.pack (show err))
Right rel -> evalRODatabaseContextOp sessionId conn (ShowRelation (ExistingRelation rel))
evalRODatabaseContextOp sessionId conn (ShowDataFrame dfExpr) = do
eDataFrame <- C.executeDataFrameExpr sessionId conn dfExpr
case eDataFrame of
Left err -> pure (DisplayErrorResult (T.pack (show err)))
Right dframe -> pure (DisplayDataFrameResult dframe)
evalRODatabaseContextOp _ _ Quit = pure QuitResult
interpretRODatabaseContextOp :: C.SessionId -> C.Connection -> T.Text -> IO TutorialDOperatorResult
interpretRODatabaseContextOp sessionId conn tutdstring = case parse roDatabaseContextOperatorP "" tutdstring of
Left err -> pure $ DisplayErrorResult (T.pack (show err))
Right parsed -> evalRODatabaseContextOp sessionId conn parsed
showDataFrameP :: Parser RODatabaseContextOperator
showDataFrameP = do
reservedOp ":showdataframe"
relExpr <- relExprP
reservedOp "orderby"
attrOrdersExpr <- attrOrdersExprP
mbOffset <- optional offsetP
mbLimit <- optional limitP
pure $ ShowDataFrame (DF.DataFrameExpr relExpr attrOrdersExpr mbOffset mbLimit)
offsetP :: Parser Integer
offsetP = do
reservedOp "offset"
natural
limitP :: Parser Integer
limitP = do
reservedOp "limit"
natural
attrOrdersExprP :: Parser [DF.AttributeOrderExpr]
attrOrdersExprP = braces (sepBy attrOrderExprP comma)
attrOrderExprP :: Parser DF.AttributeOrderExpr
attrOrderExprP = DF.AttributeOrderExpr <$> identifier <*> orderP
orderP :: Parser DF.Order
orderP = try (reservedOp "ascending" >> pure DF.AscendingOrder) <|> try (reservedOp "descending" >> pure DF.DescendingOrder) <|> pure DF.AscendingOrder