@@ -10,6 +10,7 @@ import ProjectM36.Key
10import qualified ProjectM36.DisconnectedTransaction as Discon
10import qualified ProjectM36.DisconnectedTransaction as Discon
11import qualified ProjectM36.DatabaseContext as DBC
11import qualified ProjectM36.DatabaseContext as DBC
12import ProjectM36.RelationalExpression
12import ProjectM36.RelationalExpression
13+import ProjectM36.StaticOptimizer
14import qualified Data.ByteString.Lazy as BS
15import qualified Data.ByteString.Lazy as BS
15import System.Exit
16import System.Exit
@@ -20,8 +21,7 @@ import qualified Data.Map as M
20import Data.Maybe
21import Data.Maybe
21import Data.Time.Clock
22import Data.Time.Clock
22import Data.Time.Calendar
23import Data.Time.Calendar
23−
24+import qualified Data.List.NonEmpty as NE
24−import Control.Monad.State
26{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
26{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
@@ -61,9 +61,10 @@ basicTransactionGraph = do
61 uuidA = fakeUUID 10
61 uuidA = fakeUUID 10
62 uuidB = fakeUUID 11
62 uuidB = fakeUUID 11
63 uuidRoot = fakeUUID 1
63 uuidRoot = fakeUUID 1
64+ parents' = uuidRoot NE.:| []
64 rootContext = concreteDatabaseContext rootTrans
65 rootContext = concreteDatabaseContext rootTrans
65− (_, bsGraph') <- addTransaction "branchA" (createTrans uuidA (TransactionInfo S.empty testTime) rootContext) bsGraph
66+ (_, bsGraph') <- addTransaction "branchA" (createTrans uuidA (TransactionInfo parents' testTime) rootContext) bsGraph
66− (_, bsGraph'') <- addTransaction "branchB" (createTrans uuidB (TransactionInfo S.empty testTime) rootContext) bsGraph'
67+ (_, bsGraph'') <- addTransaction "branchB" (createTrans uuidB (TransactionInfo parents' testTime) rootContext) bsGraph'
67 pure bsGraph''
68 pure bsGraph''
69addTransaction :: HeadName -> Transaction -> TransactionGraph -> IO (Transaction, TransactionGraph)
70addTransaction :: HeadName -> Transaction -> TransactionGraph -> IO (Transaction, TransactionGraph)
@@ -107,7 +108,7 @@ testSubGraphToFirstAncestorSnipBranch = TestCase $ do
107 baseGraph <- basicTransactionGraph
108 baseGraph <- basicTransactionGraph
108 transA <- assertMaybe (transactionForHead "branchA" baseGraph) "failed to get branchA"
109 transA <- assertMaybe (transactionForHead "branchA" baseGraph) "failed to get branchA"
109 transB <- assertMaybe (transactionForHead "branchB" baseGraph) "failed to get branchB"
110 transB <- assertMaybe (transactionForHead "branchB" baseGraph) "failed to get branchB"
110− (_, graph) <- addTransaction "branchC" (createTrans (fakeUUID 12) (TransactionInfo (fakeUUID 1) S.empty testTime) (concreteDatabaseContext transA)) baseGraph
111+ (_, graph) <- addTransaction "branchC" (createTrans (fakeUUID 12) (TransactionInfo (fakeUUID 1 NE.:| []) testTime) (concreteDatabaseContext transA)) baseGraph
111 subgraph <- assertEither $ subGraphOfFirstCommonAncestor graph (transactionHeadsForGraph baseGraph) transA transB S.empty
112 subgraph <- assertEither $ subGraphOfFirstCommonAncestor graph (transactionHeadsForGraph baseGraph) transA transB S.empty
112 assertGraph subgraph
113 assertGraph subgraph
113 let graphEq graphArg = S.map transactionId (transactionsForGraph graphArg)
114 let graphEq graphArg = S.map transactionId (transactionsForGraph graphArg)
@@ -121,16 +122,18 @@ testSubGraphToFirstAncestorMoreTransactions = TestCase $ do
122-- add another relvar to branchB
123-- add another relvar to branchB
123 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
124 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
125+ let env = mkDatabaseContextEvalEnv (transactionId branchBTrans) graph
126+ branchBContext = concreteDatabaseContext branchBTrans
124− (updatedBranchBContext,_,_) <- case runState (evalDatabaseContextExpr (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) (freshDatabaseState (concreteDatabaseContext branchBTrans)) of
127+ updatedBranchBContext <- case runDatabaseContextEvalMonad branchBContext env (optimizeAndEvalDatabaseContextExpr True (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) of
125− (Left err, _) -> assertFailure (show err) >> undefined
128+ Left err -> assertFailure (show err) >> undefined
126− (Right (), context) -> pure context
129+ Right st -> pure $ dbc_context st
127− (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) updatedBranchBContext) graph
130+ (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans NE.:| []) testTime) updatedBranchBContext) graph
128 branchBTrans' <- assertMaybe (transactionForHead "branchB" graph') "failed to get branchB head"
131 branchBTrans' <- assertMaybe (transactionForHead "branchB" graph') "failed to get branchB head"
129 assertEqual "branchB id 3" (fakeUUID 3) (transactionId branchBTrans')
132 assertEqual "branchB id 3" (fakeUUID 3) (transactionId branchBTrans')
131 -- add another transaction to branchA
134 -- add another transaction to branchA
132 branchATrans <- assertMaybe (transactionForHead "branchA" graph) "failed to get branchA head"
135 branchATrans <- assertMaybe (transactionForHead "branchA" graph) "failed to get branchA head"
133− (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans) S.empty testTime) (concreteDatabaseContext branchATrans)) graph'
136+ (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans NE.:| []) testTime) (concreteDatabaseContext branchATrans)) graph'
134 branchATrans' <- assertMaybe (transactionForHead "branchA" graph'') "failed to get branchA head"
137 branchATrans' <- assertMaybe (transactionForHead "branchA" graph'') "failed to get branchA head"
135 assertEqual "branchA id 4" (fakeUUID 4) (transactionId branchATrans')
138 assertEqual "branchA id 4" (fakeUUID 4) (transactionId branchATrans')
@@ -148,10 +151,12 @@ testSelectedBranchMerge = TestCase $ do
149 -- add another relvar to branchB
152 -- add another relvar to branchB
150 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
153 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "failed to get branchB head"
151− (updatedBranchBContext,_,_) <- case runState (evalDatabaseContextExpr (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) (freshDatabaseState (concreteDatabaseContext branchBTrans)) of
154+ let env = mkDatabaseContextEvalEnv (transactionId branchBTrans) graph
155+ branchBContext = concreteDatabaseContext branchBTrans
156+ updatedBranchBContext <- case runDatabaseContextEvalMonad branchBContext env (optimizeAndEvalDatabaseContextExpr True (Assign "branchBOnlyRelvar" (ExistingRelation relationTrue))) of
152− (Left err, _) -> assertFailure (show err) >> undefined
157+ Left err -> assertFailure (show err) >> undefined
153− (Right (), context) -> pure context
158+ Right st -> pure (dbc_context st)
154− (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) updatedBranchBContext) graph
159+ (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans NE.:| []) testTime) updatedBranchBContext) graph
155 --create the merge transaction in the graph
160 --create the merge transaction in the graph
156 let eGraph' = mergeTransactions testTime (fakeUUID 4) (fakeUUID 10) (SelectedBranchMergeStrategy "branchA") ("branchA", "branchB") graph'
161 let eGraph' = mergeTransactions testTime (fakeUUID 4) (fakeUUID 10) (SelectedBranchMergeStrategy "branchA") ("branchA", "branchB") graph'
@@ -175,18 +180,21 @@ testUnionPreferMergeStrategy = TestCase $ do
175 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "branchBTrans"
180 branchBTrans <- assertMaybe (transactionForHead "branchB" graph) "branchBTrans"
176 branchBRelVar <- assertEither $ mkRelationFromList (attributesFromList [Attribute "conflict" IntAtomType]) []
181 branchBRelVar <- assertEither $ mkRelationFromList (attributesFromList [Attribute "conflict" IntAtomType]) []
177 let branchAContext = (concreteDatabaseContext branchATrans) {relationVariables = M.insert conflictRelVarName branchARelVar (relationVariables (concreteDatabaseContext branchATrans))}
182 let branchAContext = (concreteDatabaseContext branchATrans) {relationVariables = M.insert conflictRelVarName branchARelVar (relationVariables (concreteDatabaseContext branchATrans))}
178− branchARelVar = relationTrue
183+ branchARelVar = ExistingRelation relationTrue
179− branchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.insert conflictRelVarName branchBRelVar (relationVariables (concreteDatabaseContext branchBTrans))}
184+ branchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.insert conflictRelVarName (ExistingRelation branchBRelVar) (relationVariables (concreteDatabaseContext branchBTrans))}
180− conflictRelVarName = "conflictRelVar"
185+ conflictRelVarName = "conflictRelVar"
182− (_, graph') <- addTransaction "branchA" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchATrans) S.empty testTime) branchAContext) graph
187+ (_, graph') <- addTransaction "branchA" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchATrans NE.:| []) testTime) branchAContext) graph
183− (_, graph'') <- addTransaction "branchB" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchBTrans) S.empty testTime) branchBContext) graph'
188+ (_, graph'') <- addTransaction "branchB" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchBTrans NE.:| []) testTime) branchBContext) graph'
184 -- validate that the conflict is hidden because we preferred a branch
189 -- validate that the conflict is hidden because we preferred a branch
185 let merged = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) (UnionPreferMergeStrategy "branchB") ("branchA", "branchB") graph''
190 let merged = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) (UnionPreferMergeStrategy "branchB") ("branchA", "branchB") graph''
186 case merged of
191 case merged of
187 Left err -> assertFailure ("expected merge success: " ++ show err)
192 Left err -> assertFailure ("expected merge success: " ++ show err)
188− Right (discon, _) ->
193+ Right (discon, _) -> do
194+ let Just rvExpr = M.lookup conflictRelVarName (relationVariables (Discon.concreteDatabaseContext discon))
195+ reEnv = freshGraphRefRelationalExprEnv (Just (Discon.concreteDatabaseContext discon)) graph
196+ Right rvRel = runGraphRefRelationalExprM reEnv (evalGraphRefRelationalExpr rvExpr)
189− assertEqual "branchB relvar preferred in conflict" (Just branchBRelVar) (M.lookup conflictRelVarName (relationVariables (Discon.concreteDatabaseContext discon)))
197+ assertEqual "branchB relvar preferred in conflict" branchBRelVar rvRel
191-- try various individual component conflicts and check for merge failure
199-- try various individual component conflicts and check for merge failure
192testUnionMergeStrategy :: Test
200testUnionMergeStrategy :: Test
@@ -201,14 +209,18 @@ testUnionMergeStrategy = TestCase $ do
202 let updatedBranchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.insert branchBOnlyRelVarName branchBOnlyRelVar (relationVariables (concreteDatabaseContext branchBTrans)) }
210 let updatedBranchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.insert branchBOnlyRelVarName branchBOnlyRelVar (relationVariables (concreteDatabaseContext branchBTrans)) }
203 updatedBranchAContext = (concreteDatabaseContext branchATrans) {inclusionDependencies = M.insert branchAOnlyIncDepName branchAOnlyIncDep (inclusionDependencies (concreteDatabaseContext branchATrans)) }
211 updatedBranchAContext = (concreteDatabaseContext branchATrans) {inclusionDependencies = M.insert branchAOnlyIncDepName branchAOnlyIncDep (inclusionDependencies (concreteDatabaseContext branchATrans)) }
204− branchBOnlyRelVar = relationTrue
212+ branchBOnlyRelVar = ExistingRelation relationTrue
205 branchAOnlyIncDepName = "branchAOnlyIncDep"
213 branchAOnlyIncDepName = "branchAOnlyIncDep"
206 branchBOnlyRelVarName = "branchBOnlyRelVar"
214 branchBOnlyRelVarName = "branchBOnlyRelVar"
207 branchAOnlyIncDep = InclusionDependency (ExistingRelation relationTrue) (ExistingRelation relationTrue)
215 branchAOnlyIncDep = InclusionDependency (ExistingRelation relationTrue) (ExistingRelation relationTrue)
208− (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) updatedBranchBContext) graph
216+ (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans NE.:| []) testTime) updatedBranchBContext) graph
209 (discon, _) <- assertEither $ mergeTransactions testTime (fakeUUID 5) (fakeUUID 10) UnionMergeStrategy ("branchA", "branchB") graph'
217 (discon, _) <- assertEither $ mergeTransactions testTime (fakeUUID 5) (fakeUUID 10) UnionMergeStrategy ("branchA", "branchB") graph'
218+ let Just rvExpr = M.lookup branchBOnlyRelVarName (relationVariables (Discon.concreteDatabaseContext discon))
219+ Right rvRel = runGraphRefRelationalExprM reEnv (evalGraphRefRelationalExpr rvExpr)
220+ reEnv = freshGraphRefRelationalExprEnv (Just (Discon.concreteDatabaseContext discon)) graph
210− assertEqual "branchBOnlyRelVar should appear in the merge" (M.lookup branchBOnlyRelVarName (relationVariables (Discon.concreteDatabaseContext discon))) (Just relationTrue)
222+ assertEqual "branchBOnlyRelVar should appear in the merge" relationTrue rvRel
211− (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans) S.empty testTime) updatedBranchAContext) graph'
223+ (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans NE.:| []) testTime) updatedBranchAContext) graph'
212 let eMergeGraph = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph''
224 let eMergeGraph = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph''
213 case eMergeGraph of
225 case eMergeGraph of
214 Left err -> assertFailure ("expected merge success: " ++ show err)
226 Left err -> assertFailure ("expected merge success: " ++ show err)
@@ -216,15 +228,18 @@ testUnionMergeStrategy = TestCase $ do
216 -- check that the new merge transaction has the correct parents
228 -- check that the new merge transaction has the correct parents
217 mergeTrans <- assertEither $ transactionForId (fakeUUID 5) mergeGraph
229 mergeTrans <- assertEither $ transactionForId (fakeUUID 5) mergeGraph
218 let mergeContext = concreteDatabaseContext mergeTrans
230 let mergeContext = concreteDatabaseContext mergeTrans
219− assertEqual "merge transaction parents" (transactionParentIds mergeTrans) (S.fromList [fakeUUID 3, fakeUUID 4])
231+ assertEqual "merge transaction parents" (parentIds mergeTrans) (S.fromList [fakeUUID 3, fakeUUID 4])
220 -- check that the new merge tranasction has elements from both A and B branches
232 -- check that the new merge tranasction has elements from both A and B branches
221− assertEqual "merge transaction relvars" (Just relationTrue) (M.lookup branchBOnlyRelVarName (relationVariables mergeContext))
233+ let Just rvExpr' = M.lookup branchBOnlyRelVarName (relationVariables mergeContext)
234+ Right rvRel' = runGraphRefRelationalExprM reEnv' (evalGraphRefRelationalExpr rvExpr')
235+ reEnv' = freshGraphRefRelationalExprEnv (Just mergeContext) graph
236+ assertEqual "merge transaction relvars" relationTrue rvRel'
222 assertEqual "merge transaction incdeps" (Just branchAOnlyIncDep) (M.lookup branchAOnlyIncDepName (inclusionDependencies mergeContext))
237 assertEqual "merge transaction incdeps" (Just branchAOnlyIncDep) (M.lookup branchAOnlyIncDepName (inclusionDependencies mergeContext))
223 -- test an expected conflict- add branchBOnlyRelVar with same name but different attributes
238 -- test an expected conflict- add branchBOnlyRelVar with same name but different attributes
224 conflictRelVar <- assertEither $ mkRelationFromList (attributesFromList [Attribute "conflict" IntAtomType]) []
239 conflictRelVar <- assertEither $ mkRelationFromList (attributesFromList [Attribute "conflict" IntAtomType]) []
225− let conflictContextA = updatedBranchAContext {relationVariables = M.insert branchBOnlyRelVarName conflictRelVar (relationVariables updatedBranchAContext) }
240+ let conflictContextA = updatedBranchAContext {relationVariables = M.insert branchBOnlyRelVarName (ExistingRelation conflictRelVar) (relationVariables updatedBranchAContext) }
226 conflictBranchATrans <- assertMaybe (transactionForHead "branchA" graph'') "retrieving head transaction for expected conflict"
241 conflictBranchATrans <- assertMaybe (transactionForHead "branchA" graph'') "retrieving head transaction for expected conflict"
227− (_, graph''') <- addTransaction "branchA" (createTrans (fakeUUID 6) (TransactionInfo (transactionId conflictBranchATrans) S.empty testTime) conflictContextA) graph''
242+ (_, graph''') <- addTransaction "branchA" (createTrans (fakeUUID 6) (TransactionInfo (transactionId conflictBranchATrans NE.:| []) testTime) conflictContextA) graph''
228 let failingMerge = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph'''
243 let failingMerge = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph'''
229 case failingMerge of
244 case failingMerge of
230 Right _ -> assertFailure "expected merge failure"
245 Right _ -> assertFailure "expected merge failure"
@@ -244,17 +259,17 @@ testUnionMergeIncDepViolation = TestCase $ do
244 rvName = "x"
259 rvName = "x"
245 Right branchArv = eRel 2
260 Right branchArv = eRel 2
246 Right branchBrv = eRel 3
261 Right branchBrv = eRel 3
247− branchAContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.singleton rvName branchArv}
262+ branchAContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.singleton rvName (ExistingRelation branchArv)}
248− branchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.singleton rvName branchBrv,
263+ branchBContext = (concreteDatabaseContext branchBTrans) {relationVariables = M.singleton rvName (ExistingRelation branchBrv),
249 inclusionDependencies = M.singleton incDepName incDep}
264 inclusionDependencies = M.singleton incDepName incDep}
250 incDepName = "x_key"
265 incDepName = "x_key"
251 incDep = inclusionDependencyForKey (AttributeNames (S.singleton "x")) (RelationVariable "x" ())
266 incDep = inclusionDependencyForKey (AttributeNames (S.singleton "x")) (RelationVariable "x" ())
254 --add the rv in new commits to both branches
269 --add the rv in new commits to both branches
255− (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans) S.empty testTime) branchBContext) graph
270+ (_, graph') <- addTransaction "branchB" (createTrans (fakeUUID 3) (TransactionInfo (transactionId branchBTrans NE.:| []) testTime) branchBContext) graph
257− (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans) S.empty testTime) branchAContext) graph'
272+ (_, graph'') <- addTransaction "branchA" (createTrans (fakeUUID 4) (TransactionInfo (transactionId branchATrans NE.:| []) testTime) branchAContext) graph'
259 --check that the union merge fails due to a violated constraint
274 --check that the union merge fails due to a violated constraint
260 let eMerge = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph''
275 let eMerge = mergeTransactions testTime (fakeUUID 5) (fakeUUID 3) UnionMergeStrategy ("branchA", "branchB") graph''