@@ -3,11 +3,13 @@ import TutorialD.Interpreter.DatabaseExpr
3import TutorialD.Interpreter
3import TutorialD.Interpreter
4import TutorialD.Interpreter.Base
4import TutorialD.Interpreter.Base
5import Test.HUnit
5import Test.HUnit
6−import ProjectM36.RelationalExpression
7import ProjectM36.Relation
6import ProjectM36.Relation
8import ProjectM36.Tuple
7import ProjectM36.Tuple
9import ProjectM36.TupleSet
8import ProjectM36.TupleSet
10import ProjectM36.Error
9import ProjectM36.Error
10+import ProjectM36.DatabaseContext
11+import ProjectM36.DataTypes.Primitive
12+import ProjectM36.DateExamples
11import ProjectM36.Base hiding (Finite)
13import ProjectM36.Base hiding (Finite)
12import qualified ProjectM36.Base as Base
14import qualified ProjectM36.Base as Base
13import ProjectM36.TransactionGraph
15import ProjectM36.TransactionGraph
@@ -22,9 +24,6 @@ import qualified Data.Vector as V
22import Data.Text.Encoding as TE
24import Data.Text.Encoding as TE
23import Data.Typeable (Proxy(..))
25import Data.Typeable (Proxy(..))
24import Data.Text (Text)
26import Data.Text (Text)
25−import Data.Time.Clock (UTCTime(..))
26−import Data.Time.Calendar (fromGregorian)
27−import Data.Interval (interval, Interval, Extended(Finite))
28import Control.Concurrent.STM
27import Control.Concurrent.STM
29import Control.Concurrent
28import Control.Concurrent
30import qualified STMContainers.Map as STMMap
29import qualified STMContainers.Map as STMMap
@@ -39,13 +38,13 @@ main = do
39 ("x:=false", Right relationFalse),
38 ("x:=false", Right relationFalse),
40 ("x:=true union false", Right relationTrue),
39 ("x:=true union false", Right relationTrue),
41 ("x:=true; x:=false", Right relationFalse),
40 ("x:=true; x:=false", Right relationFalse),
42− ("x:=relation{a int}", mkRelation simpleAAttributes emptyTupleSet),
41+ ("x:=relation{a Int}{}", mkRelation simpleAAttributes emptyTupleSet),
43− ("x:=relation{c int} rename {c as d}", mkRelation simpleBAttributes emptyTupleSet),
42+ ("x:=relation{c Int}{} rename {c as d}", mkRelation simpleBAttributes emptyTupleSet),
44− ("y:=relation{b int, c int}; x:=y{c}", mkRelation simpleProjectionAttributes emptyTupleSet),
43+ ("y:=relation{b Int, c Int}{}; x:=y{c}", mkRelation simpleProjectionAttributes emptyTupleSet),
45− ("x:=relation{tuple{a \"spam\", b 5}}", mkRelation simpleCAttributes $ RelationTupleSet [(RelationTuple simpleCAttributes) (V.fromList [stringAtom "spam", intAtom 5])]),
44+ ("x:=relation{tuple{a \"spam\", b 5}}", mkRelation simpleCAttributes $ RelationTupleSet [(RelationTuple simpleCAttributes) (V.fromList [textAtom "spam", intAtom 5])]),
46 ("constraint failc true in false; x:=true", Left $ InclusionDependencyCheckError "failc"),
45 ("constraint failc true in false; x:=true", Left $ InclusionDependencyCheckError "failc"),
47 ("x:=y; x:=true", Left $ RelVarNotDefinedError "y"),
46 ("x:=y; x:=true", Left $ RelVarNotDefinedError "y"),
48− ("x:=relation{}", Right relationFalse),
47+ ("x:=relation{}{}", Right relationFalse),
49 ("x:=relation{tuple{}}", Right relationTrue),
48 ("x:=relation{tuple{}}", Right relationTrue),
50 ("x:=true where true", Right relationTrue),
49 ("x:=true where true", Right relationTrue),
51 ("x:=true where false", Right relationFalse),
50 ("x:=true where false", Right relationFalse),
@@ -56,50 +55,49 @@ main = do
56 ("x:=true=true", Right relationTrue),
55 ("x:=true=true", Right relationTrue),
57 ("x:=true=false", Right relationFalse),
56 ("x:=true=false", Right relationFalse),
58 ("x:=true; undefine x", Left (RelVarNotDefinedError "x")),
57 ("x:=true; undefine x", Left (RelVarNotDefinedError "x")),
59− ("x:=relation {b int, a char}; insert x relation{tuple{b 5, a \"spam\"}}", mkRelationFromTuples simpleCAttributes [RelationTuple simpleCAttributes $ V.fromList[stringAtom "spam", intAtom 5]]),
58+ ("x:=relation {b Int, a Text}{}; insert x relation{tuple{b 5, a \"spam\"}}", mkRelationFromTuples simpleCAttributes [RelationTuple simpleCAttributes $ V.fromList[textAtom "spam", intAtom 5]]),
60 -- test nested relation constructor
59 -- test nested relation constructor
61 ("x:=relation{tuple{a 5, b relation{tuple{a 6}}}}", mkRelation nestedRelationAttributes $ RelationTupleSet [RelationTuple nestedRelationAttributes (V.fromList [intAtom 5, Atom (Relation simpleAAttributes $ RelationTupleSet [RelationTuple simpleAAttributes $ V.fromList [intAtom 6]])])]),
60 ("x:=relation{tuple{a 5, b relation{tuple{a 6}}}}", mkRelation nestedRelationAttributes $ RelationTupleSet [RelationTuple nestedRelationAttributes (V.fromList [intAtom 5, Atom (Relation simpleAAttributes $ RelationTupleSet [RelationTuple simpleAAttributes $ V.fromList [intAtom 6]])])]),
62− ("x:=relation{tuple{b 5,a \"spam\"},tuple{b 6,a \"sam\"}}; delete x where b=6", mkRelation simpleCAttributes $ RelationTupleSet [RelationTuple simpleCAttributes (V.fromList [stringAtom "spam", intAtom 5])]),
61+ ("x:=relation{tuple{b 5,a \"spam\"},tuple{b 6,a \"sam\"}}; delete x where b=6", mkRelation simpleCAttributes $ RelationTupleSet [RelationTuple simpleCAttributes (V.fromList [textAtom "spam", intAtom 5])]),
63 ("x:=relation{tuple{a 5}} : {b:=@a}", mkRelation simpleDAttributes $ RelationTupleSet [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 5])]),
62 ("x:=relation{tuple{a 5}} : {b:=@a}", mkRelation simpleDAttributes $ RelationTupleSet [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 5])]),
64 ("x:=relation{tuple{a 5}} : {b:=6}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 6])]),
63 ("x:=relation{tuple{a 5}} : {b:=6}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 6])]),
65 ("x:=relation{tuple{a 5}} : {b:=add(@a,5)}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 10])]),
64 ("x:=relation{tuple{a 5}} : {b:=add(@a,5)}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 10])]),
66− ("x:=relation{tuple{a 5}} : {b:=add(@a,\"spam\")}", Left (AtomFunctionTypeError "add" 2 intAtomType stringAtomType)),
65+ ("x:=relation{tuple{a 5}} : {b:=add(@a,\"spam\")}", Left (AtomFunctionTypeError "add" 2 intAtomType textAtomType)),
67 ("x:=relation{tuple{a 5}} : {b:=add(add(@a,2),5)}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 12])])
66 ("x:=relation{tuple{a 5}} : {b:=add(add(@a,2),5)}", mkRelationFromTuples simpleDAttributes [RelationTuple simpleDAttributes (V.fromList [intAtom 5, intAtom 12])])
69 simpleAAttributes = A.attributesFromList [Attribute "a" intAtomType]
68 simpleAAttributes = A.attributesFromList [Attribute "a" intAtomType]
70 simpleBAttributes = A.attributesFromList [Attribute "d" intAtomType]
69 simpleBAttributes = A.attributesFromList [Attribute "d" intAtomType]
71− simpleCAttributes = A.attributesFromList [Attribute "a" stringAtomType, Attribute "b" intAtomType]
70+ simpleCAttributes = A.attributesFromList [Attribute "a" textAtomType, Attribute "b" intAtomType]
72 simpleDAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" intAtomType]
71 simpleDAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" intAtomType]
73 simpleMaybeTextAttributes = A.attributesFromList [Attribute "a" $ atomTypeForProxy (Proxy :: Proxy (Maybe Text))]
72 simpleMaybeTextAttributes = A.attributesFromList [Attribute "a" $ atomTypeForProxy (Proxy :: Proxy (Maybe Text))]
74 simpleMaybeIntAttributes = A.attributesFromList [Attribute "a" $ atomTypeForProxy (Proxy :: Proxy (Maybe Int))]
73 simpleMaybeIntAttributes = A.attributesFromList [Attribute "a" $ atomTypeForProxy (Proxy :: Proxy (Maybe Int))]
75− simpleIntervalDateTimeAttributes = A.attributesFromList [Attribute "a" $ atomTypeForProxy (Proxy :: Proxy (Interval UTCTime))]
76 simpleProjectionAttributes = A.attributesFromList [Attribute "c" intAtomType]
74 simpleProjectionAttributes = A.attributesFromList [Attribute "c" intAtomType]
77 nestedRelationAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" (RelationAtomType $ A.attributesFromList [Attribute "a" intAtomType])]
75 nestedRelationAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" (RelationAtomType $ A.attributesFromList [Attribute "a" intAtomType])]
78 extendTestAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" $ RelationAtomType (attributes suppliersRel)]
76 extendTestAttributes = A.attributesFromList [Attribute "a" intAtomType, Attribute "b" $ RelationAtomType (attributes suppliersRel)]
79 byteStringAttributes = A.attributesFromList [Attribute "y" byteStringAtomType]
77 byteStringAttributes = A.attributesFromList [Attribute "y" byteStringAtomType]
80 groupCountAttrs = A.attributesFromList [Attribute "z" intAtomType]
78 groupCountAttrs = A.attributesFromList [Attribute "z" intAtomType]
81− minMaxAttrs = A.attributesFromList [Attribute "S#" stringAtomType, Attribute "z" intAtomType]
79+ minMaxAttrs = A.attributesFromList [Attribute "S#" textAtomType, Attribute "z" intAtomType]
82 dateExampleRelTests = [("x:=S where true", Right suppliersRel),
80 dateExampleRelTests = [("x:=S where true", Right suppliersRel),
83− ("x:=S where CITY = \"London\"", restrict (\tuple -> atomForAttributeName "CITY" tuple == (Right $ stringAtom "London")) suppliersRel),
81+ ("x:=S where CITY = \"London\"", restrict (\tuple -> atomForAttributeName "CITY" tuple == (Right $ textAtom "London")) suppliersRel),
84 ("x:=S where false", Right $ Relation (attributes suppliersRel) emptyTupleSet),
82 ("x:=S where false", Right $ Relation (attributes suppliersRel) emptyTupleSet),
85− ("x:=P where COLOR=\"Blue\" and CITY=\"Paris\"", mkRelationFromList (attributes productsRel) [[stringAtom "P5", stringAtom "Cam", stringAtom "Blue", intAtom 12, stringAtom "Paris"]]),
83+ ("x:=P where COLOR=\"Blue\" and CITY=\"Paris\"", mkRelationFromList (attributes productsRel) [[textAtom "P5", textAtom "Cam", textAtom "Blue", intAtom 12, textAtom "Paris"]]),
86 ("a:=S; update a (STATUS:=50); x:=a{STATUS}", mkRelation (A.attributesFromList [Attribute "STATUS" intAtomType]) (RelationTupleSet [mkRelationTuple (A.attributesFromList [Attribute "STATUS" intAtomType]) (V.fromList [intAtom 50])])),
84 ("a:=S; update a (STATUS:=50); x:=a{STATUS}", mkRelation (A.attributesFromList [Attribute "STATUS" intAtomType]) (RelationTupleSet [mkRelationTuple (A.attributesFromList [Attribute "STATUS" intAtomType]) (V.fromList [intAtom 50])])),
87 --atom function tests
85 --atom function tests
88 ("x:=((S : {STATUS2 := add(10,@STATUS)}) where STATUS2=add(10,@STATUS)){CITY,S#,SNAME,STATUS}", Right suppliersRel),
86 ("x:=((S : {STATUS2 := add(10,@STATUS)}) where STATUS2=add(10,@STATUS)){CITY,S#,SNAME,STATUS}", Right suppliersRel),
89− ("x:=S; update x where SNAME=\"Blake\" (CITY:=\"Boston\")", relMap (\tuple -> if atomForAttributeName "SNAME" tuple == (Right $ stringAtom "Blake") then updateTuple (M.singleton "CITY" (stringAtom "Boston")) tuple else tuple) suppliersRel),
87+ ("x:=S; update x where SNAME=\"Blake\" (CITY:=\"Boston\")", relMap (\tuple -> if atomForAttributeName "SNAME" tuple == (Right $ textAtom "Blake") then updateTuple (M.singleton "CITY" (textAtom "Boston")) tuple else tuple) suppliersRel),
90 ("x:=relation{tuple{a 5}} : {b:=S}", mkRelation extendTestAttributes (RelationTupleSet [mkRelationTuple extendTestAttributes (V.fromList [intAtom 5, Atom suppliersRel])])),
88 ("x:=relation{tuple{a 5}} : {b:=S}", mkRelation extendTestAttributes (RelationTupleSet [mkRelationTuple extendTestAttributes (V.fromList [intAtom 5, Atom suppliersRel])])),
91 --relatom function tests
89 --relatom function tests
92 ("x:=((S group ({CITY} as y)):{z:=count(@y)}){z}", mkRelation groupCountAttrs (RelationTupleSet [mkRelationTuple groupCountAttrs (V.singleton $ intAtom 1)])),
90 ("x:=((S group ({CITY} as y)):{z:=count(@y)}){z}", mkRelation groupCountAttrs (RelationTupleSet [mkRelationTuple groupCountAttrs (V.singleton $ intAtom 1)])),
93 ("x:=(SP group ({S#} as y)) ungroup y", Right supplierProductsRel),
91 ("x:=(SP group ({S#} as y)) ungroup y", Right supplierProductsRel),
94− ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=max(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [stringAtom s,intAtom i]) [("S1", 400), ("S2", 400), ("S3", 200), ("S4", 400)])),
92+ ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=max(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [textAtom s,intAtom i]) [("S1", 400), ("S2", 400), ("S3", 200), ("S4", 400)])),
95− ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=min(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [stringAtom s,intAtom i]) [("S1", 100), ("S2", 300), ("S3", 200), ("S4", 200)])),
93+ ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=min(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [textAtom s,intAtom i]) [("S1", 100), ("S2", 300), ("S3", 200), ("S4", 200)])),
96− ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=sum(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [stringAtom s,intAtom i]) [("S1", 1000), ("S2", 700), ("S3", 200), ("S4", 900)])),
94+ ("x:=((SP{S#,QTY}) group ({QTY} as x):{z:=sum(@x)}){S#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [textAtom s,intAtom i]) [("S1", 1000), ("S2", 700), ("S3", 200), ("S4", 900)])),
97 --boolean function restriction
95 --boolean function restriction
98− ("x:=S where ^lt(@STATUS,20)", mkRelationFromList (attributes suppliersRel) [[stringAtom "S2", stringAtom "Jones", intAtom 10, stringAtom "Paris"]]),
96+ ("x:=S where ^lt(@STATUS,20)", mkRelationFromList (attributes suppliersRel) [[textAtom "S2", textAtom "Jones", intAtom 10, textAtom "Paris"]]),
99− ("x:=S where ^gt(@STATUS,20)", mkRelationFromList (attributes suppliersRel) [[stringAtom "S3", stringAtom "Blake", intAtom 30, stringAtom "Paris"],
97+ ("x:=S where ^gt(@STATUS,20)", mkRelationFromList (attributes suppliersRel) [[textAtom "S3", textAtom "Blake", intAtom 30, textAtom "Paris"],
100− [stringAtom "S5", stringAtom "Adams", intAtom 30, stringAtom "Athens"]]),
98+ [textAtom "S5", textAtom "Adams", intAtom 30, textAtom "Athens"]]),
101 ("x:=S where ^sum(@STATUS)", Left $ AtomTypeMismatchError intAtomType boolAtomType),
99 ("x:=S where ^sum(@STATUS)", Left $ AtomTypeMismatchError intAtomType boolAtomType),
102− ("x:=S where ^not(gte(@STATUS,20))", mkRelationFromList (attributes suppliersRel) [[stringAtom "S2", stringAtom "Jones", intAtom 10, stringAtom "Paris"]]),
100+ ("x:=S where ^not(gte(@STATUS,20))", mkRelationFromList (attributes suppliersRel) [[textAtom "S2", textAtom "Jones", intAtom 10, textAtom "Paris"]]),
103 --test "all but" attribute inversion syntax
101 --test "all but" attribute inversion syntax
104 ("x:=S{all but S#} = S{CITY,SNAME,STATUS}", Right $ relationTrue),
102 ("x:=S{all but S#} = S{CITY,SNAME,STATUS}", Right $ relationTrue),
105 --test key syntax
103 --test key syntax
@@ -108,14 +106,9 @@ main = do
108 --test binary bytestring data type
106 --test binary bytestring data type
109 ("x:=relation{tuple{y \"dGVzdGRhdGE=\"::bytestring}}", mkRelationFromList byteStringAttributes [[Atom (TE.encodeUtf8 "testdata")]]),
107 ("x:=relation{tuple{y \"dGVzdGRhdGE=\"::bytestring}}", mkRelationFromList byteStringAttributes [[Atom (TE.encodeUtf8 "testdata")]]),
110 --test Maybe Text
108 --test Maybe Text
111− ("x:=relation{tuple{a Just \"spam\"::maybe char}}", mkRelationFromList simpleMaybeTextAttributes [[Atom (Just "spam" :: Maybe Text)]]),
109+ ("x:=relation{tuple{a Just \"spam\"}}", mkRelationFromList simpleMaybeTextAttributes [[ConstructedAtom "Just" (ConstructedAtomType "Maybe" (M.singleton "a" textAtomType)) [textAtom "spam"]]]),
112 --test Maybe Int
110 --test Maybe Int
113− ("x:=relation{tuple{a Just 3::maybe int}}", mkRelationFromList simpleMaybeIntAttributes [[Atom (Just 3 :: Maybe Int)]]),
111+ ("x:=relation{tuple{a Just 3}}", mkRelationFromList simpleMaybeIntAttributes [[Atom (Just 3 :: Maybe Int)]])
114− --test datetime interval
115− ("x:=relation{tuple{a interval_datetime((\"2015-01-01 00:00:00\",\"2016-01-01 00:00:00\"])}}", mkRelationFromList simpleIntervalDateTimeAttributes [
116− [Atom $ interval (Finite (UTCTime (fromGregorian 2015 1 1) 0), False)
117− (Finite (UTCTime (fromGregorian 2016 1 1) 0), True)]
121assertTutdEqual :: DatabaseContext -> Either RelationalError Relation -> String -> Assertion
114assertTutdEqual :: DatabaseContext -> Either RelationalError Relation -> String -> Assertion
@@ -205,24 +198,24 @@ transactionBranchTest = TestCase $ do
205simpleJoinTest :: Test
198simpleJoinTest :: Test
206simpleJoinTest = TestCase $ assertTutdEqual dateExamples joinedRel "x:=S join SP"
199simpleJoinTest = TestCase $ assertTutdEqual dateExamples joinedRel "x:=S join SP"
208− attrs = A.attributesFromList [Attribute "CITY" stringAtomType,
201+ attrs = A.attributesFromList [Attribute "CITY" textAtomType,
209 Attribute "QTY" intAtomType,
202 Attribute "QTY" intAtomType,
210− Attribute "P#" stringAtomType,
203+ Attribute "P#" textAtomType,
211− Attribute "S#" stringAtomType,
204+ Attribute "S#" textAtomType,
212− Attribute "SNAME" stringAtomType,
205+ Attribute "SNAME" textAtomType,
213 Attribute "STATUS" intAtomType]
206 Attribute "STATUS" intAtomType]
214− joinedRel = mkRelationFromList attrs [[stringAtom "London", intAtom 100, stringAtom "P6", stringAtom "S1", stringAtom "Smith", intAtom 20],
207+ joinedRel = mkRelationFromList attrs [[textAtom "London", intAtom 100, textAtom "P6", textAtom "S1", textAtom "Smith", intAtom 20],
215− [stringAtom "London", intAtom 400, stringAtom "P3", stringAtom "S1", stringAtom "Smith", intAtom 20],
208+ [textAtom "London", intAtom 400, textAtom "P3", textAtom "S1", textAtom "Smith", intAtom 20],
216− [stringAtom "London", intAtom 400, stringAtom "P5", stringAtom "S4", stringAtom "Clark", intAtom 20],
209+ [textAtom "London", intAtom 400, textAtom "P5", textAtom "S4", textAtom "Clark", intAtom 20],
217− [stringAtom "London", intAtom 300, stringAtom "P1", stringAtom "S1", stringAtom "Smith", intAtom 20],
210+ [textAtom "London", intAtom 300, textAtom "P1", textAtom "S1", textAtom "Smith", intAtom 20],
218− [stringAtom "Paris", intAtom 200, stringAtom "P2", stringAtom "S3", stringAtom "Blake", intAtom 30],
211+ [textAtom "Paris", intAtom 200, textAtom "P2", textAtom "S3", textAtom "Blake", intAtom 30],
219− [stringAtom "Paris", intAtom 300, stringAtom "P1", stringAtom "S2", stringAtom "Jones", intAtom 10],
212+ [textAtom "Paris", intAtom 300, textAtom "P1", textAtom "S2", textAtom "Jones", intAtom 10],
220− [stringAtom "London", intAtom 100, stringAtom "P5", stringAtom "S1", stringAtom "Smith", intAtom 20],
213+ [textAtom "London", intAtom 100, textAtom "P5", textAtom "S1", textAtom "Smith", intAtom 20],
221− [stringAtom "London", intAtom 300, stringAtom "P4", stringAtom "S4", stringAtom "Clark", intAtom 20],
214+ [textAtom "London", intAtom 300, textAtom "P4", textAtom "S4", textAtom "Clark", intAtom 20],
222− [stringAtom "Paris", intAtom 400, stringAtom "P2", stringAtom "S2", stringAtom "Jones", intAtom 10],
215+ [textAtom "Paris", intAtom 400, textAtom "P2", textAtom "S2", textAtom "Jones", intAtom 10],
223− [stringAtom "London", intAtom 200, stringAtom "P2", stringAtom "S1", stringAtom "Smith", intAtom 20],
216+ [textAtom "London", intAtom 200, textAtom "P2", textAtom "S1", textAtom "Smith", intAtom 20],
224− [stringAtom "London", intAtom 200, stringAtom "P4", stringAtom "S1", stringAtom "Smith", intAtom 20],
217+ [textAtom "London", intAtom 200, textAtom "P4", textAtom "S1", textAtom "Smith", intAtom 20],
225− [stringAtom "London", intAtom 200, stringAtom "P2", stringAtom "S4", stringAtom "Clark", intAtom 20]
218+ [textAtom "London", intAtom 200, textAtom "P2", textAtom "S4", textAtom "Clark", intAtom 20]
227transactionGraph :: Connection -> IO TransactionGraph
220transactionGraph :: Connection -> IO TransactionGraph
228transactionGraph (InProcessConnection _ _ _ tvar) = atomically $ readTVar tvar
221transactionGraph (InProcessConnection _ _ _ tvar) = atomically $ readTVar tvar