packages feed

project-m36-1.2.0: src/lib/ProjectM36/DatabaseContextExpr.hs

module ProjectM36.DatabaseContextExpr where
import ProjectM36.DatabaseContext.Types
import ProjectM36.DatabaseContext
import ProjectM36.Base
import ProjectM36.AccessControlList
import ProjectM36.Error
import ProjectM36.RelationalExpression
import ProjectM36.TransactionGraph.Types
import qualified Data.Map as M
import Data.Functor.Identity
import qualified Data.Functor.Foldable as Fold

resolvedDatabaseContextAsDatabaseContextExpr :: ResolvedDatabaseContext -> DatabaseContextExpr
resolvedDatabaseContextAsDatabaseContextExpr context = do
  let relVarsExprs = map (\(name, rel) -> Assign name (stripGraphRefRelationalExpr rel)) (M.toList relVars)
      relVars = runIdentity (relationVariables context)
      incDeps = runIdentity (inclusionDependencies context)
      incDepsExprs = map (uncurry AddInclusionDependency) (M.toList incDeps)
      funcsExprs = []
  MultipleExpr $ relVarsExprs ++ incDepsExprs ++ funcsExprs
  
-- | convert an existing database context into its constituent expression.   
databaseContextAsDatabaseContextExpr :: DatabaseContext -> TransactionGraph -> Either RelationalError DatabaseContextExpr
databaseContextAsDatabaseContextExpr context graph = do
  relVars <- resolveDBC' graph context relationVariables
  incDeps <- resolveDBC' graph context inclusionDependencies
  let relVarsExprs = map (\(name, rel) -> Assign name (stripGraphRefRelationalExpr rel)) (M.toList relVars)
      incDepsExprs = map (uncurry AddInclusionDependency) (M.toList incDeps)
      funcsExprs = []
  pure $ MultipleExpr $ relVarsExprs ++ incDepsExprs ++ funcsExprs

resolveRoleIds :: (RoleName -> Maybe RoleId) -> DatabaseContextExprBase a RoleName -> Either RelationalError (DatabaseContextExprBase a RoleId)
resolveRoleIds resolver expr = do
  case expr of
    NoOperation -> pure NoOperation
    Define rv exprs -> pure (Define rv exprs)
    Undefine rv -> pure (Undefine rv)
    Assign rv expr' -> pure (Assign rv expr')
    Insert rv expr' -> pure (Insert rv expr')
    Delete rv expr' -> pure (Delete rv expr')
    Update rv atoms expr' -> pure (Update rv atoms expr')
    AddInclusionDependency iname idep -> pure (AddInclusionDependency iname idep)
    RemoveInclusionDependency iname -> pure (RemoveInclusionDependency iname)
    AddNotification notName exprA exprB exprC -> pure (AddNotification notName exprA exprB exprC)
    RemoveNotification notName -> pure (RemoveNotification notName)
    AddTypeConstructor tDef dDefs -> pure (AddTypeConstructor tDef dDefs)
    RemoveTypeConstructor tName -> pure (RemoveTypeConstructor tName)
    RemoveAtomFunction fName -> pure (RemoveAtomFunction fName)
    RemoveDatabaseContextFunction fname -> pure (RemoveDatabaseContextFunction fname)
    ExecuteDatabaseContextFunction fname exprs -> pure (ExecuteDatabaseContextFunction fname exprs)
    AddRegisteredQuery qName expr' -> pure (AddRegisteredQuery qName expr')
    RemoveRegisteredQuery qName -> pure (RemoveRegisteredQuery qName)
    AlterACL expr' -> AlterACL <$> resolveRoleIdsDBCACLExpr resolver expr'
    MultipleExpr exprs -> MultipleExpr <$> mapM (resolveRoleIds resolver) exprs

resolveRoleNames :: (RoleId -> Maybe RoleName) -> DatabaseContextExprBase a RoleId -> Either RelationalError (DatabaseContextExprBase a RoleName)
resolveRoleNames resolver expr = do
  case expr of
    NoOperation -> pure NoOperation
    Define rv exprs -> pure (Define rv exprs)
    Undefine rv -> pure (Undefine rv)
    Assign rv expr' -> pure (Assign rv expr')
    Insert rv expr' -> pure (Insert rv expr')
    Delete rv expr' -> pure (Delete rv expr')
    Update rv atoms expr' -> pure (Update rv atoms expr')
    AddInclusionDependency iname idep -> pure (AddInclusionDependency iname idep)
    RemoveInclusionDependency iname -> pure (RemoveInclusionDependency iname)
    AddNotification notName exprA exprB exprC -> pure (AddNotification notName exprA exprB exprC)
    RemoveNotification notName -> pure (RemoveNotification notName)
    AddTypeConstructor tDef dDefs -> pure (AddTypeConstructor tDef dDefs)
    RemoveTypeConstructor tName -> pure (RemoveTypeConstructor tName)
    RemoveAtomFunction fName -> pure (RemoveAtomFunction fName)
    RemoveDatabaseContextFunction fname -> pure (RemoveDatabaseContextFunction fname)
    ExecuteDatabaseContextFunction fname exprs -> pure (ExecuteDatabaseContextFunction fname exprs)
    AddRegisteredQuery qName expr' -> pure (AddRegisteredQuery qName expr')
    RemoveRegisteredQuery qName -> pure (RemoveRegisteredQuery qName)
    AlterACL alterACLExpr -> AlterACL <$> resolveRoleNamesDBCACLExpr resolver alterACLExpr
    MultipleExpr exprs -> MultipleExpr <$> mapM (resolveRoleNames resolver) exprs

resolveRoleIdsDBCACLExpr :: (RoleName -> Maybe RoleId) -> AlterDBCACLExprBase RoleName -> Either RelationalError (AlterDBCACLExprBase RoleId)
resolveRoleIdsDBCACLExpr resolver =
  recurseRoles resolver'
  where
    resolver' roleName = maybe (Left (NoSuchRoleNameError roleName)) pure (resolver roleName)

-- | convert role ids into role names or vice versa
recurseRoles :: (a -> Either RelationalError b) -> AlterDBCACLExprBase a -> Either RelationalError (AlterDBCACLExprBase b)
recurseRoles resolver =
  Fold.cataA recurse
  where
--    recurse :: AlterDBCACLExprBaseF RoleId (Either RelationalError (AlterDBCACLExprBase RoleName)) -> Either RelationalError (AlterDBCACLExprBase RoleName)
    recurse (GrantAccessExprF roleInfo perm mgrant) = do
      roleOut <- resolver roleInfo
      pure (GrantAccessExpr roleOut perm mgrant)
    recurse (RevokeAccessExprF roleInfo perm) = do
      roleOut <- resolver roleInfo
      pure (RevokeAccessExpr roleOut perm)
    recurse (GrantDBCFunctionAccessExprF roleInfo funcName' perm mgrant) = do
      roleOut <- resolver roleInfo
      pure (GrantDBCFunctionAccessExpr roleOut funcName' perm mgrant)
    recurse (RevokeDBCFunctionAccessExprF roleInfo funcName' perm) = do
      roleOut <- resolver roleInfo
      pure (RevokeDBCFunctionAccessExpr roleOut funcName' perm)

resolveRoleNamesDBCACLExpr :: (RoleId -> Maybe RoleName) -> AlterDBCACLExprBase RoleId -> Either RelationalError (AlterDBCACLExprBase RoleName)
resolveRoleNamesDBCACLExpr resolver = recurseRoles resolver'
  where
    resolver' roleId = maybe (Left NoSuchRoleIdError) pure (resolver roleId)