@@ -16,6 +16,7 @@ import Control.Monad
16import qualified Data.Text as T
16import qualified Data.Text as T
17import GHC.Generics
17import GHC.Generics
18import Data.Binary
18import Data.Binary
20--operators which manipulate a transaction graph
21--operators which manipulate a transaction graph
21data TransactionGraphOperator = JumpToHead HeadName |
22data TransactionGraphOperator = JumpToHead HeadName |
@@ -210,34 +211,7 @@ evalGraphOp _ (DisconnectedTransaction parentUUID _) graph Rollback = case trans
210 newDiscon = newDisconnectedTransaction parentUUID (transactionContext parentTransaction)
211 newDiscon = newDisconnectedTransaction parentUUID (transactionContext parentTransaction)
212-- a successful merge should remove a head
213-- a successful merge should remove a head
213−evalGraphOp newUUID (DisconnectedTransaction parentUUID _) graph (MergeTransactions mergeStrategy headNameA headNameB) = do
214+evalGraphOp newUUID (DisconnectedTransaction parentUUID _) graph (MergeTransactions mergeStrategy headNameA headNameB) = mergeTransactions newUUID parentUUID mergeStrategy (headNameA, headNameB) graph
214− let transactionForHeadErr name = case transactionForHead name graph of
215− Nothing -> Left (NoSuchHeadNameError name)
217− transA <- transactionForHeadErr headNameA
218− transB <- transactionForHeadErr headNameB
219− let transAid = transactionUUID transA
220− transBid = transactionUUID transB
221− headNameToDelete <- if parentUUID == transAid then
223− else if parentUUID == transBid then
226− Left (MergeTransactionError (DisconnectedTransactionNotAMergeHeadError parentUUID))
228− disconParent <- transactionForUUID parentUUID graph
229− subGraph <- subGraphToFirstCommonAncestor graph emptyTransactionGraph transA transB
230− case mergeTransactions newUUID mergeStrategy subGraph (transA, transB) of
231− Left err -> Left (MergeTransactionError err)
232− Right mergedTrans -> case headNameForTransaction disconParent graph of
233− Nothing -> Left (TransactionIsNotAHeadError parentUUID)
235− let newDiscon = newDisconnectedTransaction mergedTransUUID (transactionContext mergedTrans)
236− mergedTransUUID = transactionUUID mergedTrans
237− (_, newGraph) <- addDisconnectedTransaction mergedTransUUID headName newDiscon graph
238− let newGraph' = TransactionGraph newHeads (transactionsForGraph newGraph)
239− newHeads = M.delete headNameToDelete (transactionHeadsForGraph newGraph)
240− pure (newDiscon, newGraph')
242--present a transaction graph as a relation showing the uuids, parentuuids, and flag for the current location of the disconnected transaction
216--present a transaction graph as a relation showing the uuids, parentuuids, and flag for the current location of the disconnected transaction
243graphAsRelation :: DisconnectedTransaction -> TransactionGraph -> Either RelationalError Relation
217graphAsRelation :: DisconnectedTransaction -> TransactionGraph -> Either RelationalError Relation
@@ -281,43 +255,91 @@ evalROGraphOp discon graph ShowGraph = do
281 return graphRel
255 return graphRel
284−--execute the merge strategy against the transactions, returning a new transaction to be added to the graph
258+-- | Execute the merge strategy against the transactions, returning a new transaction which can be then added to the transaction graph
285−-- a successful merge should also remove a head
286−mergeTransactions :: U.UUID -> MergeStrategy -> TransactionGraph -> (Transaction, Transaction) -> Either MergeError Transaction
259+createMergeTransaction :: U.UUID -> MergeStrategy -> TransactionGraph -> (Transaction, Transaction) -> Either MergeError Transaction
287−mergeTransactions newUUID (SelectedBranchMergeStrategy selectedBranch) graph t2@(trans1, trans2) = do
260+createMergeTransaction newUUID (SelectedBranchMergeStrategy selectedBranch) graph t2@(trans1, trans2) = do
288 selectedTrans <- validateHeadName selectedBranch graph t2
261 selectedTrans <- validateHeadName selectedBranch graph t2
289 pure $ Transaction newUUID (MergeTransactionInfo (transactionUUID trans1) (transactionUUID trans2) S.empty) (transactionContext selectedTrans)
262 pure $ Transaction newUUID (MergeTransactionInfo (transactionUUID trans1) (transactionUUID trans2) S.empty) (transactionContext selectedTrans)
291−mergeTransactions newUUID UnionMergeStrategy graph t2 = undefined
264+--createMergeTransaction newUUID UnionMergeStrategy graph t2 = undefined
294-- | Returns the correct Transaction for the branch name in the graph and ensures that it is one of the two transaction arguments in the tuple.
266-- | Returns the correct Transaction for the branch name in the graph and ensures that it is one of the two transaction arguments in the tuple.
295validateHeadName :: HeadName -> TransactionGraph -> (Transaction, Transaction) -> Either MergeError Transaction
267validateHeadName :: HeadName -> TransactionGraph -> (Transaction, Transaction) -> Either MergeError Transaction
268+validateHeadName headName graph (t1, t2) = do
296−validateHeadName headName graph (t1, t2) = case transactionForHead headName graph of
269+ case transactionForHead headName graph of
297− Nothing -> Left SelectedHeadMismatchMergeError
270+ Nothing -> Left SelectedHeadMismatchMergeError
298− Just trans -> if trans /= t1 && trans /= t2 then
271+ Just trans -> if trans /= t1 && trans /= t2 then
299− Left SelectedHeadMismatchMergeError
272+ Left SelectedHeadMismatchMergeError
301− Right trans
274+ Right trans
303−-- | Return the common ancestor of two transactions. When looking for the first common ancestor, we don't need to search both parents of a merge transaction because the merge must have diverged from a common ancestor anyway, so we arbitrarily just search one of the parents of a merge transaction. Technically, due to merge transactions, this may not actually return the first common ancestor, but it should be pretty close. The incoming subgraph's heads remain unchanged in the return value.
276+-- | Return the common ancestor of two transactions. When looking for the first common ancestor, we don't need to search both parents of a merge transaction because the merge must have diverged from a common ancestor anyway, so we arbitrarily just search one of the parents of a merge transaction. Technically, due to merge transactions, this may not actually return the first common ancestor, but it should be pretty close.
304−subGraphToFirstCommonAncestor :: TransactionGraph -> TransactionGraph -> Transaction -> Transaction -> Either RelationalError TransactionGraph
277+subGraphToFirstCommonAncestor :: TransactionGraph -> TransactionHeads -> TransactionGraph -> Transaction -> Transaction -> Either RelationalError TransactionGraph
305−subGraphToFirstCommonAncestor origGraph subGraph trans1 trans2 = do
278+subGraphToFirstCommonAncestor origGraph resultHeads subGraph trans1 trans2 = do
306 let t1id = transactionUUID trans1
279 let t1id = transactionUUID trans1
307 t2id = transactionUUID trans2
280 t2id = transactionUUID trans2
281+ validChildIds = traceShowId $ S.map transactionUUID (transactionsForGraph subGraph)
282+ filterTransSet transSet = S.map (\t -> filterChildTransactions t validChildIds) transSet
308 if t1id == t2id then
283 if t1id == t2id then
309− Right subGraph
284+ --also filter child transactions
285+ Right (TransactionGraph resultHeads (S.union (transactionsForGraph subGraph) (filterTransSet (S.singleton trans1))))
310− else if U.null t1id || U.null t2id then --no common ancestor
286+ else if U.null t1id || U.null t2id then --no common ancestor
311− Left (NoCommonTransactionAncestorError t1id t2id)
287+ Left (NoCommonTransactionAncestorError t1id t2id)
313− parentTrans1 <- oneParent trans1
289+ parentTrans1 <- oneParent trans1
314− parentTrans2 <- oneParent trans2
290+ parentTrans2 <- oneParent trans2
315− --add transactions to graph
291+ --add transactions to graph
316− let subGraph' = TransactionGraph headNames newTrans
292+ let subGraph' = TransactionGraph resultHeads newTrans
317− headNames = transactionHeadsForGraph subGraph
318− newTrans = S.union (transactionsForGraph subGraph) (S.fromList [parentTrans1, parentTrans2])
293+ newTrans = S.union (transactionsForGraph subGraph) (filterTransSet (S.fromList [trans1, trans2]))
319− subGraphToFirstCommonAncestor origGraph subGraph' parentTrans1 parentTrans2
294+ subGraphToFirstCommonAncestor origGraph resultHeads subGraph' parentTrans1 parentTrans2
321 oneParent (Transaction _ (TransactionInfo parentId _) _) = transactionForUUID parentId origGraph
296 oneParent (Transaction _ (TransactionInfo parentId _) _) = transactionForUUID parentId origGraph
322 oneParent (Transaction _ (MergeTransactionInfo parentId _ _) _) = transactionForUUID parentId origGraph
297 oneParent (Transaction _ (MergeTransactionInfo parentId _ _) _) = transactionForUUID parentId origGraph
300+mergeTransactions :: U.UUID -> U.UUID -> MergeStrategy -> (HeadName, HeadName) -> TransactionGraph -> Either RelationalError (DisconnectedTransaction, TransactionGraph)
301+mergeTransactions newUUID parentUUID mergeStrategy (headNameA, headNameB) graph = do
302+ let transactionForHeadErr name = case transactionForHead name graph of
303+ Nothing -> Left (NoSuchHeadNameError name)
305+ transA <- transactionForHeadErr headNameA
306+ transB <- transactionForHeadErr headNameB
307+ let transAid = transactionUUID transA
308+ transBid = transactionUUID transB
309+ headNameToDelete <- if parentUUID == transAid then
311+ else if parentUUID == transBid then
314+ Left (MergeTransactionError (DisconnectedTransactionNotAMergeHeadError parentUUID))
316+ disconParent <- transactionForUUID parentUUID graph
317+ let subHeads = M.filterWithKey (\k _ -> elem k [headNameA, headNameB]) (transactionHeadsForGraph graph)
318+ subGraph <- subGraphToFirstCommonAncestor graph subHeads emptyTransactionGraph transA transB
319+ --traceShowM ("hello\n" ++ showGraphStructureX subGraph)
320+ case createMergeTransaction newUUID mergeStrategy subGraph (transA, transB) of
321+ Left err -> Left (MergeTransactionError err)
322+ Right mergedTrans -> case headNameForTransaction disconParent graph of
323+ Nothing -> Left (TransactionIsNotAHeadError parentUUID)
325+ let newDiscon = newDisconnectedTransaction mergedTransUUID (transactionContext mergedTrans)
326+ mergedTransUUID = transactionUUID mergedTrans
327+ (_, newGraph) <- addDisconnectedTransaction mergedTransUUID headName newDiscon graph
328+ let newGraph' = TransactionGraph newHeads (transactionsForGraph newGraph)
329+ newHeads = M.delete headNameToDelete (transactionHeadsForGraph newGraph)
330+ pure (newDiscon, newGraph')
332+--TEMPORARY COPY/PASTE
333+showTransactionStructureX :: Transaction -> TransactionGraph -> String
334+showTransactionStructureX trans graph = headInfo ++ " " ++ show (transactionUUID trans) ++ " " ++ parentTransactionsInfo
336+ headInfo = maybe "" show (headNameForTransaction trans graph)
337+ parentTransactionsInfo = if isRootTransaction trans graph then "root" else case parentTransactions trans graph of
338+ Left err -> show err
339+ Right parentTransSet -> concat $ S.toList $ S.map (show . transactionUUID) parentTransSet
341+showGraphStructureX :: TransactionGraph -> String
342+showGraphStructureX graph@(TransactionGraph heads transSet) = headsInfo ++ S.foldr folder "" transSet
344+ folder trans acc = acc ++ showTransactionStructureX trans graph ++ "\n"
345+ headsInfo = show $ M.map transactionUUID heads