@@ -8,6 +8,8 @@ import RelationalError
8import RelationExpr
8import RelationExpr
9import RelationTerm
9import RelationTerm
10import RelationStaticOptimizer
10import RelationStaticOptimizer
11+import RelationalTransaction
12+import RelationalTransactionShow
11import Text.Parsec
13import Text.Parsec
12import Text.Parsec.String
14import Text.Parsec.String
13import Text.Parsec.Expr
15import Text.Parsec.Expr
@@ -22,7 +24,24 @@ import Control.Monad.State
22import System.Console.Haskeline
24import System.Console.Haskeline
23import System.IO
25import System.IO
24import System.Directory (getHomeDirectory)
26import System.Directory (getHomeDirectory)
27+import qualified Data.UUID as U
28+import Data.UUID.V4 (nextRandom)
31+List of Tutorial D operators:
32+show relation expression type :: relexpr -> context -> opresult
33+show relvar :: relvar name -> context -> opresult
35+show graph :: graph -> DisconnectedTransaction -> opresult
36+show constraints :: context -> opresult
37+jump to head :: head name -> graph -> DisconnectedTransaction (graph unchanged)
38+jump to UUID :: uuid -> graph -> DisconnectedTransaction (graph unchanged)
39+branch :: uuid -> branch name -> graph -> (DisconnectedTransation, graph)
40+commit :: uuid -> DisconnectedTransaction -> graph -> (DisconnectedTransaction, graph)
41+rollback :: DisconnectedTransaction -> graph -> (DisconnectedTransaction, graph)
26lexer :: Token.TokenParser ()
45lexer :: Token.TokenParser ()
27lexer = Token.makeTokenParser tutD
46lexer = Token.makeTokenParser tutD
28 where tutD = emptyDef {
47 where tutD = emptyDef {
@@ -39,6 +58,13 @@ identifier = Token.identifier lexer
39comma = Token.comma lexer
58comma = Token.comma lexer
40semi = Token.semi lexer
59semi = Token.semi lexer
61+uuidP :: Parser U.UUID
63+ uuidStr <- many (alphaNum <|> char '-')
64+ case U.fromString uuidStr of
65+ Nothing -> fail "Invalid uuid string"
66+ Just uuid -> return uuid
42--used in projection
68--used in projection
43attributeList :: Parser [AttributeName]
69attributeList :: Parser [AttributeName]
44attributeList = sepBy identifier comma
70attributeList = sepBy identifier comma
@@ -244,49 +270,103 @@ parseString str = case parse (multipleDatabaseExpr <* eof) "" str of
244 Left err -> Left $ ParseError (show err)
270 Left err -> Left $ ParseError (show err)
245 Right r -> Right r
271 Right r -> Right r
247−data TutorialDOperator where
273+--operators which only rely on database context reading
274+data ContextOperator where
248− ShowRelation :: RelationalExpr -> TutorialDOperator
275+ ShowRelation :: RelationalExpr -> ContextOperator
249− ShowRelationType :: RelationalExpr -> TutorialDOperator
276+ ShowRelationType :: RelationalExpr -> ContextOperator
250− ShowConstraint :: String -> TutorialDOperator
277+ ShowConstraint :: String -> ContextOperator
251− ShowPlan :: DatabaseExpr -> TutorialDOperator
278+ ShowPlan :: DatabaseExpr -> ContextOperator
252− Quit :: TutorialDOperator
279+ Quit :: ContextOperator
253 deriving (Show)
280 deriving (Show)
282+--operators which manipulate a transaction graph
283+data GraphOperator where
284+ JumpToHead :: String -> GraphOperator
285+ JumpToTransaction :: U.UUID -> GraphOperator
286+ Branch :: HeadName -> GraphOperator
287+ Commit :: GraphOperator
288+ Rollback :: GraphOperator
289+ ShowGraph :: GraphOperator
255−typeP :: Parser TutorialDOperator
291+typeP :: Parser ContextOperator
256typeP = do
292typeP = do
257− reservedOp ":t"
293+ reservedOp ":type"
258 expr <- relExpr
294 expr <- relExpr
259 return $ ShowRelationType expr
295 return $ ShowRelationType expr
261−showRelP :: Parser TutorialDOperator
297+showRelP :: Parser ContextOperator
262showRelP = do
298showRelP = do
263− reservedOp ":s"
299+ reservedOp ":showExpr"
264− expr <- relExpr <* eof
300+ expr <- relExpr
265 return $ ShowRelation expr
301 return $ ShowRelation expr
267−showPlanP :: Parser TutorialDOperator
303+showPlanP :: Parser ContextOperator
268showPlanP = do
304showPlanP = do
269− reservedOp ":p"
305+ reservedOp ":showplan"
270 expr <- databaseExpr
306 expr <- databaseExpr
271 return $ ShowPlan expr
307 return $ ShowPlan expr
273−quitP :: Parser TutorialDOperator
309+quitP :: Parser ContextOperator
274quitP = do
310quitP = do
275− reservedOp ":q"
311+ reservedOp ":quit"
276 return Quit
312 return Quit
278−showConstraintsP :: Parser TutorialDOperator
314+showConstraintsP :: Parser ContextOperator
279showConstraintsP = do
315showConstraintsP = do
280− reservedOp ":c"
316+ reservedOp ":constraints"
281 constraintName <- option "" identifier
317 constraintName <- option "" identifier
282 return $ ShowConstraint constraintName
318 return $ ShowConstraint constraintName
284−interpreterOps :: Parser TutorialDOperator
320+jumpToHeadP :: Parser GraphOperator
285−interpreterOps = typeP
321+jumpToHeadP = do
322+ reservedOp ":jumphead"
324+ return $ JumpToHead head
326+jumpToTransactionP :: Parser GraphOperator
327+jumpToTransactionP = do
330+ return $ JumpToTransaction uuid
332+branchTransactionP :: Parser GraphOperator
333+branchTransactionP = do
334+ reservedOp ":branch"
335+ branchName <- identifier
336+ return $ Branch branchName
338+commitTransactionP :: Parser GraphOperator
339+commitTransactionP = do
340+ reservedOp ":commit"
343+rollbackTransactionP :: Parser GraphOperator
344+rollbackTransactionP = do
345+ reservedOp ":rollback"
348+showGraphP :: Parser GraphOperator
350+ reservedOp ":showGraph"
353+transactionGraphOps = do
355+ <|> jumpToTransactionP
356+ <|> branchTransactionP
357+ <|> commitTransactionP
358+ <|> rollbackTransactionP
361+contextOps :: Parser ContextOperator
286− <|> showRelP
363+ <|> showRelP
287− <|> showConstraintsP
364+ <|> showConstraintsP
288− <|> showPlanP
365+ <|> showPlanP
289− <|> quitP
366+ <|> quitP
368+interpreterOps :: Parser (Either ContextOperator GraphOperator)
369+interpreterOps = liftM Left contextOps <|> liftM Right transactionGraphOps
291showRelationAttributes :: Relation -> String
371showRelationAttributes :: Relation -> String
292showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribute attrs) ++ "}"
372showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribute attrs) ++ "}"
@@ -300,19 +380,20 @@ showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribu
300data TutorialDOperatorResult = QuitResult |
380data TutorialDOperatorResult = QuitResult |
301 DisplayResult String |
381 DisplayResult String |
302 DisplayErrorResult String |
382 DisplayErrorResult String |
303− NoActionResult
383+ QuietSuccessResult |
384+ NoActionResult --refactor to make this dead- there should be only one parser
305−evalTutorialDOp :: DatabaseContext -> TutorialDOperator -> TutorialDOperatorResult
386+evalContextOp :: DatabaseContext -> ContextOperator -> TutorialDOperatorResult
306−evalTutorialDOp context (ShowRelationType expr) = case runState (typeForRelationalExpr expr) context of
387+evalContextOp context (ShowRelationType expr) = case runState (typeForRelationalExpr expr) context of
307 (Right rel, _) -> DisplayResult $ showRelationAttributes rel
388 (Right rel, _) -> DisplayResult $ showRelationAttributes rel
308 (Left err, _) -> DisplayErrorResult $ show err
389 (Left err, _) -> DisplayErrorResult $ show err
310−evalTutorialDOp context (ShowRelation expr) = do
391+evalContextOp context (ShowRelation expr) = do
311 case runState (evalRelationalExpr expr) context of
392 case runState (evalRelationalExpr expr) context of
312 (Left err, _) -> DisplayErrorResult $ show err
393 (Left err, _) -> DisplayErrorResult $ show err
313 (Right rel, _) -> DisplayResult $ showRelation rel
394 (Right rel, _) -> DisplayResult $ showRelation rel
315−evalTutorialDOp context (ShowConstraint name) = do
396+evalContextOp context (ShowConstraint name) = do
316 DisplayResult $ show filteredDeps
397 DisplayResult $ show filteredDeps
318 deps = inclusionDependencies context
399 deps = inclusionDependencies context
@@ -320,23 +401,80 @@ evalTutorialDOp context (ShowConstraint name) = do
320 "" -> deps
401 "" -> deps
321 name -> HS.filter (\(InclusionDependency n _ _) -> n == name) deps
402 name -> HS.filter (\(InclusionDependency n _ _) -> n == name) deps
323−evalTutorialDOp context (ShowPlan dbExpr) = do
404+evalContextOp context (ShowPlan dbExpr) = do
324 DisplayResult $ show plan
405 DisplayResult $ show plan
326 plan = evalState (applyStaticDatabaseOptimization dbExpr) context
407 plan = evalState (applyStaticDatabaseOptimization dbExpr) context
328−evalTutorialDOp context (Quit) = QuitResult
409+evalContextOp context (Quit) = QuitResult
330−example1 = "relA {a,b, c}"
411+-- returns the new "current" transaction, updated graph, and tutorial d result
331−example2 = "relA join relB"
412+-- the current transaction is not part of the transaction graph until it is committed
332−example3 = "relA join relB {x,y,z}"
413+evalGraphOp :: U.UUID -> DisconnectedTransaction -> TransactionGraph -> GraphOperator -> Either RelationalError (DisconnectedTransaction, TransactionGraph, TutorialDOperatorResult)
333−example4 = "(relA) {x,y,z}"
414+
334−example5 = "relA union relB"
415+--affects only disconncted transaction
335−example6 = "rv1 := true"
416+evalGraphOp newUUID trans graph (JumpToTransaction jumpUUID) = case transactionForUUID jumpUUID graph of
336−example7 = "rv1 := relA union relB"
417+ Left err -> Left err
337−example8 = "relA := true; relB := false"
418+ Right parentTrans -> Right (newTrans, graph, QuietSuccessResult)
338−example9 = "relA := relation { SNO CHAR }"
419+ where
420+ newTrans = DisconnectedTransaction jumpUUID (transactionContext parentTrans)
422+-- switch from one head to another
423+-- affects only disconnectedtransaction
424+evalGraphOp newUUID currentTransaction graph (JumpToHead headName) =
425+ case transactionForHead headName graph of
426+ Just newHeadTransaction -> let disconnectedTrans = newDisconnectedTransaction (transactionUUID newHeadTransaction) (transactionContext newHeadTransaction) in
427+ Right (disconnectedTrans, graph, QuietSuccessResult)
428+ Nothing -> Left $ NoSuchHeadNameError headName
429+-- add new head pointing to branchPoint
430+-- repoint the disconnected transaction to the new branch commit (with a potentially different disconnected context)
431+-- affects transactiongraph and the disconnectedtransaction is recreated based off the branch
433+evalGraphOp newUUID discon@(DisconnectedTransaction parentUUID disconContext) graph (Branch newBranchName) = case transactionForUUID parentUUID graph of
434+ Nothing -> (discon, graph, DisplayErrorResult "Failed to find parent transaction.")
435+ Just parentTrans -> case addBranch newBranchName parentTrans graph of
436+ Nothing -> (discon, graph, DisplayErrorResult "Failed to add branch.")
437+ Just newGraph -> (newDiscon, newGraph, DisplayResult "Branched.")
439+ newDiscon = DisconnectedTransaction (transactionUUID parentTrans) disconContext
442+-- create a new commit and add it to the heads
443+-- technically, the new head could be added to an existing commit, but by adding a new commit, the new head is unambiguously linked to a new commit (with a context indentical to its parent)
444+evalGraphOp newUUID discon@(DisconnectedTransaction parentUUID disconContext) graph (Branch newBranchName) = case transactionForUUID parentUUID graph of
445+ Left err -> Left err
446+ Right parentTrans -> case addBranch newUUID newBranchName parentTrans graph of
447+ Left err -> Left err
448+ Right (newTrans, newGraph) -> Right (newDiscon, newGraph, QuietSuccessResult)
450+ newDiscon = DisconnectedTransaction newUUID disconContext
452+-- add the disconnected transaction to the graph
453+-- affects graph and disconnectedtransaction- the new disconnectedtransaction's parent is the freshly committed transaction
454+evalGraphOp newTransUUID discon@(DisconnectedTransaction parentUUID context) graph Commit = case transactionForUUID parentUUID graph of
455+ Left err -> Left err
456+ Right parentTransaction -> case headNameForTransaction parentTransaction graph of
457+ Nothing -> Left $ TransactionIsNotAHeadError parentUUID
458+ Just headName -> case maybeUpdatedGraph of
460+ Right (_, updatedGraph) -> Right (newDisconnectedTrans, updatedGraph, QuietSuccessResult)
462+ newDisconnectedTrans = newDisconnectedTransaction newTransUUID context
463+ maybeUpdatedGraph = addDisconnectedTransaction newTransUUID headName discon graph
465+-- refresh the disconnected transaction, return the same graph
466+evalGraphOp _ discon@(DisconnectedTransaction parentUUID _) graph Rollback = case transactionForUUID parentUUID graph of
467+ Left err -> Left err
468+ Right parentTransaction -> Right (newDiscon, graph, QuietSuccessResult)
470+ newDiscon = newDisconnectedTransaction parentUUID (transactionContext parentTransaction)
472+--display transaction graph as relation
473+evalGraphOp _ discon graph ShowGraph = do
474+ graphStr <- graphAsRelation discon graph
475+ return (discon, graph, DisplayResult $ showRelation graphStr)
477+--shouldn't this be Either RelationalError DatabaseContext?
340interpret :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
478interpret :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
341interpret context tutdstring = case parseString tutdstring of
479interpret context tutdstring = case parseString tutdstring of
342 Left err -> (Just err, context)
480 Left err -> (Just err, context)
@@ -358,33 +496,53 @@ interpretNO context tutdstring = case parseString tutdstring of
360-- for interpreter-specific operations
498-- for interpreter-specific operations
361−interpretOps :: DatabaseContext -> String -> TutorialDOperatorResult
499+interpretOps :: U.UUID -> DisconnectedTransaction -> TransactionGraph -> String -> (DisconnectedTransaction, TransactionGraph, TutorialDOperatorResult)
362−interpretOps context instring = case parse interpreterOps "" instring of
500+interpretOps newUUID trans@(DisconnectedTransaction parentUUID context) transGraph instring = case parse interpreterOps "" instring of
363− Left err -> NoActionResult
501+ Left err -> (trans, transGraph, NoActionResult)
364− Right ops -> evalTutorialDOp context ops
502+ Right ops -> case ops of
503+ Left contextOp -> (trans, transGraph, (evalContextOp context contextOp))
504+ Right graphOp -> case evalGraphOp newUUID trans transGraph graphOp of
505+ Left err -> (trans, transGraph, DisplayErrorResult $ show err)
506+ Right (newDiscon, newGraph, result) -> (newDiscon, newGraph, result)
366−reprLoop :: DatabaseContext -> IO ()
508+promptText :: DisconnectedTransaction -> TransactionGraph -> String
367−reprLoop context = do
509+promptText (DisconnectedTransaction parentUUID _) graph = "TutorialD (" ++ transInfo ++ "): "
511+ transInfo = case transactionForUUID parentUUID graph of
512+ Left err -> "unknown"
513+ Right parentTrans -> case headNameForTransaction parentTrans graph of
514+ Nothing -> show $ transactionUUID parentTrans
515+ Just headName -> headName
517+reprLoop :: DisconnectedTransaction -> TransactionGraph -> IO ()
518+reprLoop currentTransaction@(DisconnectedTransaction currentParentUUID currentContext) graph = do
368 homeDirectory <- getHomeDirectory
519 homeDirectory <- getHomeDirectory
369− let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
520+ let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
370− maybeLine <- runInputT settings $ do
522+ maybeLine <- runInputT settings $ getInputLine (promptText currentTransaction graph)
371− getInputLine "TutorialD: "
523+
524+ let roloop = reprLoop currentTransaction graph
372 case maybeLine of
525 case maybeLine of
373 Nothing -> return ()
526 Nothing -> return ()
374 Just line -> do
527 Just line -> do
528+ newUUID <- nextRandom
375− case interpretOps context line of
529+ case interpretOps newUUID currentTransaction graph line of
376− QuitResult -> return ()
530+ (_, _, QuitResult) -> return ()
377− DisplayErrorResult err -> hPutStrLn stderr ("ERR: " ++ err) >> reprLoop context
531+ (_, _, DisplayErrorResult err) -> hPutStrLn stderr ("ERR: " ++ err) >> roloop
378− DisplayResult out -> do
532+ (updatedTrans, updatedGraph, DisplayResult out) -> do
379 putStrLn out
533 putStrLn out
380− reprLoop context
534+ reprLoop updatedTrans updatedGraph
535+ (updatedTrans, updatedGraph, QuietSuccessResult) -> do
537+ reprLoop updatedTrans updatedGraph
381− NoActionResult -> do
538+ (_, _, NoActionResult) -> do
382− let (value, contextup) = interpret context line
539+ let (value, contextup) = interpret currentContext line
540+ let updatedTransaction = DisconnectedTransaction currentParentUUID contextup
383− case value of
541+ case value of
384− Nothing -> reprLoop contextup
542+ Nothing -> reprLoop updatedTransaction graph
385− (Just err) -> do
543+ Just err -> do
386− hPutStrLn stderr ("ERR:" ++ show err)
544+ hPutStrLn stderr ("ERR:" ++ show err)
387− reprLoop context
545+ reprLoop currentTransaction graph
389restrictionPredicateP :: Parser RestrictionPredicateExpr
547restrictionPredicateP :: Parser RestrictionPredicateExpr
390restrictionPredicateP = buildExpressionParser predicateOperators predicateTerm
548restrictionPredicateP = buildExpressionParser predicateOperators predicateTerm
@@ -419,4 +577,8 @@ stringAtomP = liftA StringAtom (string "\"" *> many quotedChar <* string "\"")
419intAtomP = do
577intAtomP = do
420 intstr <- many digit
578 intstr <- many digit
421 return $ IntAtom (read intstr)
579 return $ IntAtom (read intstr)
582+displayTransactionGraph :: TransactionGraph -> String
583+displayTransactionGraph (TransactionGraph heads transSet) = L.intercalate "\n" $ S.foldr (\(Transaction tUUID pUUID _ ) acc -> acc ++ [show tUUID ++ " " ++ show pUUID]) [] transSet