on master help sign in
WIP: lots of refactoring for new constructed atom types and primitive types separation
commit9835bf4dc38ad00ecd04bff35d6908aa37add12f authorAgentM <agentm@themactionfaction.com> dateWed 10 Feb 2016, 22:35 (11 years ago) parenta740264
26 files changed+461−376
Database/Persist/ProjectM36.hs+3−1 ProjectM36/Atom.hs+12−39 ProjectM36/AtomConstructor.hs+7 ProjectM36/AtomFunctions/Basic.hs+11 ProjectM36/AtomFunctions/Primitive.hs+100 ProjectM36/AtomType.hs+5−4 ProjectM36/Base.hs+18−17 ProjectM36/Client.hs+2−1 ProjectM36/DataTypes/Basic.hs+14 ProjectM36/DataTypes/Day.hs+18 ProjectM36/DataTypes/Primitive.hs+38 ProjectM36/DatabaseContext.hs+12 ProjectM36/DateExamples.hs+81 ProjectM36/Error.hs+1 ProjectM36/Relation.hs−37 ProjectM36/Relation/Show/Gnuplot.hs+2−1 ProjectM36/Relation/Show/HTML.hs+2−4 ProjectM36/RelationalExpression.hs+61−150 ProjectM36/Sessions.hs+5−4 ProjectM36/StaticOptimizer.hs+7 ProjectM36/Transaction/Persist.hs+16−2 ProjectM36/TransactionGraph.hs+5−5 TutorialD/Interpreter/Base.hs+5−3 TutorialD/Interpreter/DatabaseExpr.hs+2−2 TutorialD/Interpreter/RelationalExpr.hs+24−106 benchmark/bigrel.hs+10
Database/Persist/ProjectM36.hs+3−1
@@ -76,6 +76,8 @@ persistValueAtom val = case val of
7676 _ -> Nothing
7777
7878atomAsPersistValue :: Atom -> PersistValue
79+--constructed atoms are written as text to the database
80+atomAsPersistValue atom@(ConstructedAtom _ _ _) = PersistText (atomToText atom)
7981atomAsPersistValue atom@(Atom atomv) = if typeRep (Proxy :: Proxy Int) == typeOf atomv then
8082 PersistInt64 (fromIntegral ((unsafeCast atom) :: Int))
8183 else if typeRep (Proxy :: Proxy T.Text) == typeOf atomv then
@@ -523,7 +525,7 @@ instance PersistQuery ProjectM36Backend where
523525 allAttrNamesList = map (unDBName . fieldDB) (entityFields entDef) ++ [unDBName (fieldDB (entityId entDef))]
524526 allAttrNames = AttributeNames $ S.fromList allAttrNamesList
525527 groupExpr = Group allAttrNames "persistcountrel" (Restrict restrictionPredicate (RelationVariable relVarName))
526− tupleExpr = AttributeTupleExpr "persistcount" (FunctionAtomExpr "count" [AttributeAtomExpr "persistcountrel"])
528+ tupleExpr = AttributeExtendTupleExpr "persistcount" (FunctionAtomExpr "count" [AttributeAtomExpr "persistcountrel"])
527529 countExpr = Extend tupleExpr groupExpr
528530 rel <- Trans.liftIO $ C.executeRelationalExpr sessionId conn countExpr
529531 case rel of
ProjectM36/Atom.hs+12−39
@@ -8,7 +8,6 @@ import qualified Data.Text as T
88import Data.Time.Calendar (Day)
99import Data.Time.Clock
1010import Data.ByteString (ByteString)
11−import qualified Data.Map as M
1211
1312relationForAtom :: Atom -> Either RelationalError Relation
1413relationForAtom (Atom atom) = case cast atom of
@@ -16,30 +15,6 @@ relationForAtom (Atom atom) = case cast atom of
1615 Nothing -> Left $ AttributeIsNotRelationValuedError ""
1716relationForAtom (ConstructedAtom _ _ _) = Left $ AttributeIsNotRelationValuedError ""
1817
19−atomTypeForProxy :: (Atomable a) => Proxy a -> AtomType
20−atomTypeForProxy prox = AtomType $ CTR (typeRep prox)
21−
22−--some convenience functions
23−stringAtomType :: AtomType
24−stringAtomType = atomTypeForProxy (Proxy :: Proxy StringType)
25−
26−intAtomType :: AtomType
27−intAtomType = atomTypeForProxy (Proxy :: Proxy Int)
28−
29−boolAtomType :: AtomType
30−boolAtomType = atomTypeForProxy (Proxy :: Proxy Bool)
31−
32−dateAtomType :: AtomType
33−dateAtomType = atomTypeForProxy (Proxy :: Proxy Day)
34−
35−dateTimeAtomType :: AtomType
36−dateTimeAtomType = atomTypeForProxy (Proxy :: Proxy UTCTime)
37−
38−byteStringAtomType :: AtomType
39−byteStringAtomType = atomTypeForProxy (Proxy :: Proxy ByteString)
40−
41−doubleAtomType :: AtomType
42−doubleAtomType = atomTypeForProxy (Proxy :: Proxy Double)
4318
4419--another hard-coded typerep dispatch table :/
4520makeAtomFromText :: AttributeName -> AtomType -> T.Text -> Either RelationalError Atom
@@ -62,9 +37,8 @@ makeAtomFromText _ (AtomType cTypeRep) textIn = if
6237 Left $ ParseError textIn
6338makeAtomFromText attrName _ _ = Left $ AtomTypeNotSupported attrName
6439
65−--textAtom shortcut
66−stringAtom :: T.Text -> Atom
67−stringAtom t = Atom t
40+textAtom :: T.Text -> Atom
41+textAtom t = Atom t
6842
6943--intAtom shortcut
7044intAtom :: Int -> Atom
@@ -77,15 +51,14 @@ castRelation (Atom atom) = case cast atom of
7751 Just rel -> rel
7852 Nothing -> error "castRelation attempt on non-relation-typed Atom"
7953
80−unsafeCast :: (Atomable a) => Atom -> a
81−unsafeCast (ConstructedAtom _ _ _) = error "unsafeCast attempt on ConstructedAtom"
82−unsafeCast (Atom atom) = case cast atom of
83− Just x -> x
84− Nothing -> error "unsafeCast failed"
85−
86−emptyAtomConstructor :: AtomConstructor
87−emptyAtomConstructor = AtomConstructor M.empty
88−
54+{-
8955basicAtomTypes :: AtomTypes
90−basicAtomTypes = M.fromList [("Int", (intAtomType, emptyAtomConstructor))]
91−
56+basicAtomTypes = M.union primitiveAtomTypes moreTypes
57+ where
58+ moreTypes = M.fromList [("Day", (dateAtomType,
59+ AtomConstructor (M.singleton "Day" ["Int"])))
60+ ]
61+-}
62+atomToText :: Atom -> T.Text
63+atomToText (Atom atom) = toText atom
64+atomToText (ConstructedAtom dConsName _ atoms) = dConsName `T.append` T.intercalate " " (map atomToText atoms)
ProjectM36/AtomConstructor.hsnew file+7
@@ -0,0 +1,7 @@
1+module ProjectM36.AtomConstructor where
2+import ProjectM36.Base
3+import qualified Data.Map as M
4+
5+emptyAtomConstructor :: AtomConstructor
6+emptyAtomConstructor = AtomConstructor M.empty
7+
ProjectM36/AtomFunctions/Basic.hsnew file+11
@@ -0,0 +1,11 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+--atom functions on primitive atom values plus the basic atom functions
3+module ProjectM36.AtomFunctions.Basic where
4+import ProjectM36.Base
5+import ProjectM36.DataTypes.Day
6+import ProjectM36.AtomFunctions.Primitive
7+import qualified Data.HashSet as HS
8+
9+basicAtomFunctions :: AtomFunctions
10+basicAtomFunctions = primitiveAtomFunctions `HS.union` dayFunctions
11+
ProjectM36/AtomFunctions/Primitive.hsnew file+100
@@ -0,0 +1,100 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module ProjectM36.AtomFunctions.Primitive where
3+import ProjectM36.Atom
4+import ProjectM36.Base
5+import ProjectM36.Relation (relFold)
6+import ProjectM36.Tuple
7+import ProjectM36.AtomFunction
8+import ProjectM36.DataTypes.Primitive
9+import qualified Data.HashSet as HS
10+import Data.Typeable (cast)
11+import qualified Data.Vector as V
12+import qualified Data.ByteString.Base64 as B64
13+import qualified Data.Text.Encoding as TE
14+import qualified Data.Text as T
15+
16+primitiveAtomFunctions :: AtomFunctions
17+primitiveAtomFunctions = HS.fromList [
18+ --match on any relation type
19+ AtomFunction { atomFuncName = "add",
20+ atomFuncType = [intAtomType, intAtomType, intAtomType],
21+ atomFunc = (\(i1:i2:_) -> Atom $ ((unsafeCast i1)::Int) + unsafeCast i2)},
22+ AtomFunction { atomFuncName = "id",
23+ atomFuncType = [AnyAtomType, AnyAtomType],
24+ atomFunc = (\(x:_) -> x)},
25+ AtomFunction { atomFuncName = "sum",
26+ atomFuncType = foldAtomFuncType intAtomType intAtomType,
27+ atomFunc = (\(relAtom:_) -> relationSum $ unsafeCast relAtom)},
28+ AtomFunction { atomFuncName = "count",
29+ atomFuncType = foldAtomFuncType AnyAtomType intAtomType,
30+ atomFunc = (\((relIn):_) -> relationCount (castRelation relIn))},
31+ AtomFunction { atomFuncName = "max",
32+ atomFuncType = foldAtomFuncType intAtomType intAtomType,
33+ atomFunc = (\((relIn):_) -> relationMax (castRelation relIn))},
34+ AtomFunction { atomFuncName = "min",
35+ atomFuncType = foldAtomFuncType intAtomType intAtomType,
36+ atomFunc = (\((relIn):_) -> relationMin (castRelation relIn))},
37+ AtomFunction { atomFuncName = "lt",
38+ atomFuncType = [intAtomType, intAtomType, boolAtomType],
39+ atomFunc = intAtomFuncLessThan False},
40+ AtomFunction { atomFuncName = "lte",
41+ atomFuncType = [intAtomType, intAtomType, boolAtomType],
42+ atomFunc = intAtomFuncLessThan True},
43+ AtomFunction { atomFuncName = "gte",
44+ atomFuncType = [intAtomType, intAtomType, boolAtomType],
45+ atomFunc = boolAtomNot . (:[]) . intAtomFuncLessThan False},
46+ AtomFunction { atomFuncName = "gt",
47+ atomFuncType = [intAtomType, intAtomType, boolAtomType],
48+ atomFunc = boolAtomNot . (:[]) . intAtomFuncLessThan True},
49+ AtomFunction { atomFuncName = "not",
50+ atomFuncType = [boolAtomType, boolAtomType],
51+ atomFunc = boolAtomNot},
52+ AtomFunction { atomFuncName = "makeByteString",
53+ atomFuncType = [textAtomType, byteStringAtomType],
54+ --I need a proper error-handling scheme for AtomFunctions!
55+ atomFunc = \(textIn:_) -> Atom $ (B64.decodeLenient . TE.encodeUtf8) ((unsafeCast textIn)::T.Text) }
56+ ]
57+
58+unsafeCast :: (Atomable a) => Atom -> a
59+unsafeCast (ConstructedAtom _ _ _) = error "unsafeCast attempt on ConstructedAtom"
60+unsafeCast (Atom atom) = case cast atom of
61+ Just x -> x
62+ Nothing -> error "unsafeCast failed"
63+
64+intAtomFuncLessThan :: Bool -> [Atom] -> Atom
65+intAtomFuncLessThan equality (iatom1:iatom2:_) = (\i1 i2 -> Atom $ ((unsafeCast i1)::Int) `op` unsafeCast i2) iatom1 iatom2
66+ where
67+ op = if equality then (<=) else (<)
68+intAtomFuncLessThan _ _= Atom False
69+
70+boolAtomNot :: [Atom] -> Atom
71+boolAtomNot (bool:_) = Atom $ not (unsafeCast bool)
72+boolAtomNot _ = Atom False
73+
74+--used by sum atom function
75+relationSum :: Relation -> Atom
76+relationSum relIn = Atom $ relFold (\tupIn acc -> acc + (newVal tupIn)) 0 relIn
77+ where
78+ --extract Int from Atom
79+ newVal :: RelationTuple -> Int
80+ newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
81+
82+relationCount :: Relation -> Atom
83+relationCount relIn = Atom $ relFold (\_ acc -> acc + 1) (0::Int) relIn
84+
85+relationMax :: Relation -> Atom
86+relationMax relIn = Atom $ relFold (\tupIn acc -> max acc (newVal tupIn)) minBound relIn
87+ where
88+ newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
89+
90+relationMin :: Relation -> Atom
91+relationMin relIn = Atom $ relFold (\tupIn acc -> min acc (newVal tupIn)) maxBound relIn
92+ where
93+ newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
94+
95+castInt :: Atom -> Int
96+castInt (ConstructedAtom _ _ _) = error "castInt attempt on ConstructedAtom"
97+castInt (Atom atom) = case cast atom of
98+ Just i -> i
99+ Nothing -> error "int cast failure" -- the type checker must ensure this can never occur
100+
ProjectM36/AtomType.hs+5−4
@@ -2,6 +2,7 @@
22module ProjectM36.AtomType where
33import ProjectM36.Base
44import ProjectM36.Relation
5+import ProjectM36.DataTypes.Primitive
56import qualified Data.Text as T
67import ProjectM36.Error
78import ProjectM36.Attribute
@@ -13,13 +14,13 @@ import Data.Either (isRight)
1314typesAsRelation :: AtomTypes -> Either RelationalError Relation
1415typesAsRelation aTypes = mkRelationFromTuples attrs tuples
1516 where
16− attrs = attributesFromList [Attribute "TypeConstructor" stringAtomType,
17+ attrs = attributesFromList [Attribute "TypeConstructor" textAtomType,
1718 Attribute "DataConstructors" dConsType]
18− subAttrs = attributesFromList [Attribute "DataConstructor" stringAtomType]
19+ subAttrs = attributesFromList [Attribute "DataConstructor" textAtomType]
1920 dConsType = RelationAtomType subAttrs
2021 tuples = map mkTypeConsDescription (M.toList aTypes)
21− mkTypeConsDescription (tConsName, (_, AtomConstructor dConsMap)) = RelationTuple attrs (V.fromList [stringAtom tConsName, mkDataConsRelation dConsMap])
22− mkDataConsRelation dConsMap = case mkRelationFromTuples subAttrs $ map (\(dConsName, dConsTypeNames) -> RelationTuple subAttrs (V.singleton $ stringAtom $ T.intercalate " " (dConsName:dConsTypeNames))) (M.toList dConsMap) of
22+ mkTypeConsDescription (tConsName, (_, AtomConstructor dConsMap)) = RelationTuple attrs (V.fromList [textAtom tConsName, mkDataConsRelation dConsMap])
23+ mkDataConsRelation dConsMap = case mkRelationFromTuples subAttrs $ map (\(dConsName, dConsTypeNames) -> RelationTuple subAttrs (V.singleton $ textAtom $ T.intercalate " " (dConsName:dConsTypeNames))) (M.toList dConsMap) of
2324 Left err -> error ("mkRelationFromTuples pooped " ++ show err)
2425 Right rel -> Atom rel
2526{-
ProjectM36/Base.hs+18−17
@@ -23,6 +23,8 @@ import Data.Typeable
2323import Text.Read (readMaybe)
2424import Data.ByteString (ByteString)
2525import ProjectM36.ConcreteTypeRep
26+import qualified Data.Text.Encoding as TE
27+import qualified Data.ByteString.Base64 as BS64
2628
2729type StringType = Text
2830
@@ -50,7 +52,8 @@ instance Atomable Text where
5052 toText t = t
5153instance Atomable Day
5254instance Atomable UTCTime
53−instance Atomable ByteString
55+instance Atomable ByteString where
56+ toText bs = TE.decodeUtf8With (\_ _ -> Just '?') (BS64.encode bs)
5457instance Atomable Bool
5558instance Atomable Relation
5659instance (Atomable a) => Atomable (Maybe a)
@@ -89,8 +92,6 @@ instance Binary Atom where
8992 Atom <$> (get :: Get Double)
9093 else if unCTR cTypeRep == typeRep (Proxy :: Proxy Day) then
9194 Atom <$> (get :: Get Day)
92− else if unCTR cTypeRep == typeRep (Proxy :: Proxy UTCTime) then
93− Atom <$> (get :: Get UTCTime)
9495 else if unCTR cTypeRep == typeRep (Proxy :: Proxy ByteString) then
9596 Atom <$> (get :: Get ByteString)
9697 else if unCTR cTypeRep == typeRep (Proxy :: Proxy Bool) then
@@ -230,8 +231,10 @@ type RelVarName = StringType
230231
231232-- | A relational expression represents query (read) operations on a database.
232233data RelationalExpr where
233− --- | Create a relation from attribute and atom expressions.
234− MakeRelationFromAtomExprs :: [AttributeExpr] -> [AtomExpr] -> RelationalExpr
234+ --- | Create a relation from tuple expressions.
235+ MakeRelationFromTupleExprs :: [TupleExpr] -> RelationalExpr
236+ --- | Create an empty relation with the given attributes.
237+ MakeEmptyRelation :: [AttributeExpr] -> RelationalExpr
235238 --- | Create and reference a relation from attributes and a tuple set.
236239 MakeStaticRelation :: Attributes -> RelationTupleSet -> RelationalExpr
237240 --- | Reference an existing relation in Haskell-space.
@@ -260,9 +263,7 @@ data RelationalExpr where
260263 NotEquals :: RelationalExpr -> RelationalExpr -> RelationalExpr
261264 Extend :: ExtendTupleExpr -> RelationalExpr -> RelationalExpr
262265 --Summarize :: AtomExpr -> AttributeName -> RelationalExpr -> RelationalExpr -> RelationalExpr -- a special case of Extend
263− deriving (Show,Eq, Generic)
264−
265−instance Binary RelationalExpr
266+ deriving (Show, Eq, Generic, Binary)
266267
267268type NotificationName = StringType
268269type Notifications = M.Map NotificationName Notification
@@ -294,7 +295,7 @@ instance Binary InclusionDependency
294295
295296-- | Database context expressions modify the database context.
296297data DatabaseExpr where
297− Define :: RelVarName -> Attributes -> DatabaseExpr
298+ Define :: RelVarName -> [AttributeExpr] -> DatabaseExpr
298299 Undefine :: RelVarName -> DatabaseExpr --forget existence of relvar X
299300 Assign :: RelVarName -> RelationalExpr -> DatabaseExpr
300301 Insert :: RelVarName -> RelationalExpr -> DatabaseExpr
@@ -386,7 +387,7 @@ instance Eq Transaction where
386387instance Ord Transaction where
387388 compare (Transaction uuidA _ _) (Transaction uuidB _ _) = compare uuidA uuidB
388389
389−-- | An atom expression represents an action to take when extending a relation.
390+-- | An atom expression represents an action to take when extending a relation or when statically defining a relation or a new tuple.
390391data AtomExpr = AttributeAtomExpr AttributeName |
391392 NakedAtomExpr Atom |
392393 FunctionAtomExpr AtomFunctionName [AtomExpr] |
@@ -396,12 +397,9 @@ data AtomExpr = AttributeAtomExpr AttributeName |
396397
397398instance Binary AtomExpr
398399
399−-- | A tuple expression declares what action to take when extending a relation.
400−data ExtendTupleExpr = AttributeExtendTupleExpr AttributeName AtomExpr
401− deriving (Show, Eq, Generic, Binary)
402−
403400-- | Used in tuple creation when creating a relation.
404−data TupleExpr = TupleExpr Attributes [AtomExpr]
401+data ExtendTupleExpr = AttributeExtendTupleExpr AttributeName AtomExpr
402+ deriving (Show, Eq, Binary, Generic)
405403
406404--enumerates the list of functions available to be run as part of tuple expressions
407405type AtomFunctions = HS.HashSet AtomFunction
@@ -439,5 +437,8 @@ data PersistenceStrategy = NoPersistence | -- ^ no filesystem persistence/memory
439437 CrashSafePersistence FilePath -- ^ full fsync to disk (flushes kernel and physical drive buffers to ensure that the transaction is on non-volatile storage)
440438 deriving (Show, Read)
441439
442−data AttributeExpr = AttributeAndAtomExpr AttributeName AtomExpr |
443− AttributeAndTypeName AttributeName TypeConstructorName
440+data AttributeExpr = AttributeAndTypeNameExpr AttributeName TypeConstructorName
441+ deriving (Eq, Show, Generic, Binary)
442+
443+data TupleExpr = TupleExpr (M.Map AttributeName AtomExpr)
444+ deriving (Eq, Show, Generic, Binary)
ProjectM36/Client.hs+2−1
@@ -52,6 +52,7 @@ import ProjectM36.Error
5252import ProjectM36.StaticOptimizer
5353import Control.Monad.State
5454import qualified ProjectM36.RelationalExpression as RE
55+import ProjectM36.DatabaseContext (basicDatabaseContext)
5556import ProjectM36.TransactionGraph
5657import ProjectM36.TransactionGraph.Persist
5758import ProjectM36.Attribute hiding (atomTypes)
@@ -179,7 +180,7 @@ connectProjectM36 :: ConnectionInfo -> IO (Either ConnectionError Connection)
179180--create a new in-memory database/transaction graph
180181connectProjectM36 (InProcessConnectionInfo strat notificationCallback) = do
181182 freshUUID <- nextRandom
182− let bootstrapContext = RE.basicDatabaseContext
183+ let bootstrapContext = basicDatabaseContext
183184 freshGraph = bootstrapTransactionGraph freshUUID bootstrapContext
184185 case strat of
185186 --create date examples graph for now- probably should be empty context in the future
ProjectM36/DataTypes/Basic.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+-- wraps up primitives plus other basic data types
3+module ProjectM36.DataTypes.Basic where
4+import ProjectM36.DataTypes.Primitive
5+import qualified Data.Map as M
6+import ProjectM36.Base
7+
8+basicAtomTypes :: AtomTypes
9+basicAtomTypes = M.union primitiveAtomTypes moreTypes
10+ where
11+ moreTypes = M.fromList [("Day", (ConstructedAtomType "Day",
12+ AtomConstructor (M.singleton "Day" ["Int"])))]
13+
14+
ProjectM36/DataTypes/Day.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module ProjectM36.DataTypes.Day where
3+import ProjectM36.Base
4+import ProjectM36.DataTypes.Primitive
5+import ProjectM36.AtomFunctions.Primitive
6+import qualified Data.HashSet as HS
7+import Data.Time.Calendar
8+
9+dayAtomType :: AtomType
10+dayAtomType = ConstructedAtomType "Day"
11+
12+dayFunctions :: AtomFunctions
13+dayFunctions = HS.fromList [
14+ AtomFunction { atomFuncName = "fromGregorian",
15+ atomFuncType = [intAtomType, intAtomType, intAtomType, dayAtomType],
16+ atomFunc = \(year:month:day:_) -> ConstructedAtom "Day" dayAtomType [Atom (fromGregorian (fromIntegral (unsafeCast year::Int)) (unsafeCast month) (unsafeCast day))]
17+ }
18+ ]
ProjectM36/DataTypes/Primitive.hsnew file+38
@@ -0,0 +1,38 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module ProjectM36.DataTypes.Primitive where
3+import ProjectM36.Base
4+import Data.Proxy
5+import Data.Typeable
6+import ProjectM36.AtomConstructor
7+import ProjectM36.ConcreteTypeRep
8+import qualified Data.Map as M
9+import qualified Data.Text as T
10+import qualified Data.ByteString as BS
11+
12+atomTypeForProxy :: (Atomable a) => Proxy a -> AtomType
13+atomTypeForProxy prox = AtomType $ CTR (typeRep prox)
14+
15+textAtomType :: AtomType
16+textAtomType = atomTypeForProxy (Proxy :: Proxy T.Text)
17+
18+intAtomType :: AtomType
19+intAtomType = atomTypeForProxy (Proxy :: Proxy Int)
20+
21+boolAtomType :: AtomType
22+boolAtomType = atomTypeForProxy (Proxy :: Proxy Bool)
23+
24+doubleAtomType :: AtomType
25+doubleAtomType = atomTypeForProxy (Proxy :: Proxy Double)
26+
27+byteStringAtomType :: AtomType
28+byteStringAtomType = atomTypeForProxy (Proxy :: Proxy BS.ByteString)
29+
30+primitiveAtomTypes :: AtomTypes
31+primitiveAtomTypes = M.fromList $ map (\(typeName,typ) -> (typeName, (typ, emptyAtomConstructor))) prims
32+ where
33+ prims = [("Int", intAtomType),
34+ ("Text", textAtomType),
35+ ("Double", doubleAtomType),
36+ ("Bool", boolAtomType),
37+ ("ByteString", byteStringAtomType)
38+ ]
ProjectM36/DatabaseContext.hs+12
@@ -1,7 +1,11 @@
1+{-# LANGUAGE OverloadedStrings #-}
12module ProjectM36.DatabaseContext where
23import ProjectM36.Base
34import qualified Data.Map as M
45import qualified Data.HashSet as HS
6+import ProjectM36.DataTypes.Basic
7+import ProjectM36.AtomFunctions.Basic
8+import ProjectM36.Relation
59
610empty :: DatabaseContext
711empty = DatabaseContext { inclusionDependencies = M.empty,
@@ -19,3 +23,11 @@ databaseContextAsDatabaseContextExpr context = MultipleExpr $ incDepsExprs ++ re
1923 incDepsExprs = map (\(name, dep) -> AddInclusionDependency name dep) (M.toList (inclusionDependencies context))
2024 funcsExprs = [] -- map (\func -> ) (HS.toList funcs) -- there are no databaseExprs to add atom functions yet
2125
26+basicDatabaseContext :: DatabaseContext
27+basicDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
28+ relationVariables = M.fromList [("true", relationTrue),
29+ ("false", relationFalse)],
30+ atomFunctions = basicAtomFunctions,
31+ notifications = M.empty,
32+ atomTypes = basicAtomTypes
33+ }
ProjectM36/DateExamples.hsnew file+81
@@ -0,0 +1,81 @@
1+module ProjectM36.DateExamples where
2+import ProjectM36.Base
3+import ProjectM36.AtomFunctions.Basic
4+import ProjectM36.DataTypes.Basic
5+
6+dateExamples :: DatabaseContext
7+dateExamples = DatabaseContext { inclusionDependencies = dateIncDeps,
8+ relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars,
9+ notifications = M.empty,
10+ atomFunctions = basicAtomFunctions,
11+ atomTypes = basicAtomTypes }
12+ where
13+ dateRelVars = M.fromList [("S", suppliers),
14+ ("P", products),
15+ ("SP", supplierProducts)]
16+ suppliers = suppliersRel
17+ products = productsRel
18+ supplierProducts = supplierProductsRel
19+ dateIncDeps = M.fromList [("S_pkey", simplePKey ["S#"] "S"),
20+ ("P_pkey", simplePKey ["P#"] "P"),
21+ ("SP_pkey", simplePKey ["S#", "P#"] "SP")
22+ ]
23+ simplePKey attrNames relvarName = inclusionDependencyForKey (AttributeNames $ S.fromList attrNames) (RelationVariable relvarName)
24+
25+suppliersRel :: Relation
26+suppliersRel = case mkRelationFromList attrs atomMatrix of
27+ Left _ -> undefined
28+ Right rel -> rel
29+ where
30+ attrs = A.attributesFromList [Attribute "S#" textAtomType,
31+ Attribute "SNAME" textAtomType,
32+ Attribute "STATUS" intAtomType,
33+ Attribute "CITY" textAtomType]
34+ atomMatrix = [
35+ [textAtom "S1", textAtom "Smith", intAtom 20, textAtom "London"],
36+ [textAtom "S2", textAtom "Jones", intAtom 10, textAtom "Paris"],
37+ [textAtom "S3", textAtom "Blake", intAtom 30, textAtom "Paris"],
38+ [textAtom "S4", textAtom "Clark", intAtom 20, textAtom "London"],
39+ [textAtom "S5", textAtom "Adams", intAtom 30, textAtom "Athens"]]
40+
41+supplierProductsRel :: Relation
42+supplierProductsRel = case mkRelationFromList attrs matrix of
43+ Left _ -> undefined
44+ Right rel -> rel
45+ where
46+ attrs = A.attributesFromList [Attribute "S#" textAtomType,
47+ Attribute "P#" textAtomType,
48+ Attribute "QTY" intAtomType]
49+ matrix = [
50+ [textAtom "S1", textAtom "P1", intAtom 300],
51+ [textAtom "S1", textAtom "P2", intAtom 200],
52+ [textAtom "S1", textAtom "P3", intAtom 400],
53+ [textAtom "S1", textAtom "P4", intAtom 200],
54+ [textAtom "S1", textAtom "P5", intAtom 100],
55+ [textAtom "S1", textAtom "P6", intAtom 100],
56+ [textAtom "S2", textAtom "P1", intAtom 300],
57+ [textAtom "S2", textAtom "P2", intAtom 400],
58+ [textAtom "S3", textAtom "P2", intAtom 200],
59+ [textAtom "S4", textAtom "P2", intAtom 200],
60+ [textAtom "S4", textAtom "P4", intAtom 300],
61+ [textAtom "S4", textAtom "P5", intAtom 400]
62+ ]
63+
64+productsRel :: Relation
65+productsRel = case mkRelationFromList attrs matrix of
66+ Left _ -> undefined
67+ Right rel -> rel
68+ where
69+ attrs = A.attributesFromList [Attribute "P#" textAtomType,
70+ Attribute "PNAME" textAtomType,
71+ Attribute "COLOR" textAtomType,
72+ Attribute "WEIGHT" intAtomType,
73+ Attribute "CITY" textAtomType]
74+ matrix = [
75+ [textAtom "P1", textAtom "Nut", textAtom "Red", intAtom 12, textAtom "London"],
76+ [textAtom "P2", textAtom "Bolt", textAtom "Green", intAtom 17, textAtom "Paris"],
77+ [textAtom "P3", textAtom "Screw", textAtom "Blue", intAtom 17, textAtom "Oslo"],
78+ [textAtom "P4", textAtom "Screw", textAtom "Red", intAtom 14, textAtom "London"],
79+ [textAtom "P5", textAtom "Cam", textAtom "Blue", intAtom 12, textAtom "Paris"],
80+ [textAtom "P6", textAtom "Cog", textAtom "Red", intAtom 19, textAtom "London"]
81+ ]
ProjectM36/Error.hs+1
@@ -17,6 +17,7 @@ data RelationalError = NoSuchAttributeNamesError (S.Set AttributeName)
1717 | AttributeNamesMismatchError (S.Set AttributeName)
1818 | AttributeNameInUseError AttributeName
1919 | AttributeIsNotRelationValuedError AttributeName
20+ | CouldNotInferAttributes
2021 | RelVarNotDefinedError RelVarName
2122 | RelVarAlreadyDefinedError RelVarName
2223 | RelVarAssignmentTypeMismatchError Attributes Attributes --expected, found
ProjectM36/Relation.hs−37
@@ -4,15 +4,12 @@ import qualified Data.Set as S
44import qualified Data.HashSet as HS
55import Control.Monad
66import qualified Data.Vector as V
7−import ProjectM36.Atom
8−import Data.Typeable (cast)
97import ProjectM36.Base
108import ProjectM36.Tuple
119import qualified ProjectM36.Attribute as A
1210import qualified ProjectM36.AttributeNames as AS
1311import ProjectM36.TupleSet
1412import ProjectM36.Error
15−import qualified Data.Text as T
1613import qualified Control.Parallel.Strategies as P
1714import Data.Either (isRight)
1815
@@ -260,39 +257,5 @@ imageRelationJoin rel1@(Relation attrNameSet1 tupSet1) rel2@(Relation attrNameSe
260257 tupleSetJoiner tup1 acc = undefined
261258-}
262259
263−-- returns a relation with tupleCount tuples with a set of integer attributes attributesCount long
264−-- this is useful for performance and resource usage testing
265−matrixRelation :: Int -> Int -> Either RelationalError Relation
266−matrixRelation attributeCount tupleCount = do
267− let attrs = A.attributesFromList $ map (\c-> Attribute (T.pack $ "a" ++ show c) intAtomType) [0 .. attributeCount-1]
268− tuple tupleX = RelationTuple attrs (V.generate attributeCount (\_ -> Atom tupleX))
269− tuples = map (\c -> tuple c) [0 .. tupleCount]
270− mkRelationDeferVerify attrs (RelationTupleSet tuples)
271−
272−
273−castInt :: Atom -> Int
274−castInt (ConstructedAtom _ _ _) = error "castInt attempt on ConstructedAtom"
275−castInt (Atom atom) = case cast atom of
276− Just i -> i
277− Nothing -> error "int cast failure" -- the type checker must ensure this can never occur
278−
279−--used by sum atom function
280−relationSum :: Relation -> Atom
281−relationSum relIn = Atom $ relFold (\tupIn acc -> acc + (newVal tupIn)) 0 relIn
282− where
283− --extract Int from Atom
284− newVal :: RelationTuple -> Int
285− newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
286−
287−relationCount :: Relation -> Atom
288−relationCount relIn = Atom $ relFold (\_ acc -> acc + 1) (0::Int) relIn
289260
290−relationMax :: Relation -> Atom
291−relationMax relIn = Atom $ relFold (\tupIn acc -> max acc (newVal tupIn)) minBound relIn
292− where
293− newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
294261
295−relationMin :: Relation -> Atom
296−relationMin relIn = Atom $ relFold (\tupIn acc -> min acc (newVal tupIn)) maxBound relIn
297− where
298− newVal tupIn = castInt $ (tupleAtoms tupIn) V.! 0
ProjectM36/Relation/Show/Gnuplot.hs+2−1
@@ -3,7 +3,8 @@ module ProjectM36.Relation.Show.Gnuplot where
33import ProjectM36.Base
44import ProjectM36.Relation
55import ProjectM36.Tuple
6−import ProjectM36.Atom
6+import ProjectM36.DataTypes.Primitive
7+import ProjectM36.AtomFunctions.Primitive
78import qualified ProjectM36.Attribute as A
89import qualified Data.Vector as V
910
ProjectM36/Relation/Show/HTML.hs+2−4
@@ -3,6 +3,7 @@ module ProjectM36.Relation.Show.HTML where
33import ProjectM36.Base
44import ProjectM36.Relation
55import ProjectM36.Tuple
6+import ProjectM36.Atom
67import qualified Data.List as L
78import ProjectM36.Attribute
89import Data.Text (append, Text, pack)
@@ -26,13 +27,10 @@ writeHTML = TIO.writeFile "/home/agentm/rel.html"
2627writeRel :: Relation -> IO ()
2728writeRel = writeHTML . relationAsHTML
2829
29−atomAsHTML :: Atom -> Text
30−atomAsHTML (Atom atom) = toText atom
31−
3230tupleAsHTML :: RelationTuple -> Text
3331tupleAsHTML tuple = "<tr>" `append` T.concat (L.map tupleFrag (tupleSortedAssocs tuple)) `append` "</tr>"
3432 where
35− tupleFrag tup = "<td>" `append` atomAsHTML (snd tup) `append` "</td>"
33+ tupleFrag tup = "<td>" `append` atomToText (snd tup) `append` "</td>"
3634
3735tupleSetAsHTML :: RelationTupleSet -> Text
3836tupleSetAsHTML tupSet = foldr folder "" (asList tupSet)
ProjectM36/RelationalExpression.hs+61−150
@@ -5,20 +5,19 @@ import ProjectM36.Tuple
55import ProjectM36.TupleSet
66import ProjectM36.Base
77import ProjectM36.Error
8−import ProjectM36.Atom
98import ProjectM36.AtomType
10−import ProjectM36.Key
9+import ProjectM36.DataTypes.Primitive
1110import ProjectM36.AtomFunction
12−import ProjectM36.DataTypes.Interval
1311import qualified ProjectM36.Attribute as A
1412import qualified Data.Map as M
1513import qualified Data.HashSet as HS
16−import qualified Data.Set as S
1714import Control.Monad.State hiding (join)
1815import Data.Maybe
1916import Data.Either
2017import Data.Char (isUpper)
2118import qualified Data.Text as T
19+import qualified Data.Vector as V
20+--import Debug.Trace
2221
2322--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
2423evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
@@ -56,7 +55,27 @@ evalRelationalExpr (MakeStaticRelation attributeSet tupleSet) = do
5655 case mkRelation attributeSet tupleSet of
5756 Right rel -> return $ Right rel
5857 Left err -> return $ Left err
59−
58+
59+evalRelationalExpr (MakeEmptyRelation attrExprs) = do
60+ currentContext <- get
61+ let eAttrs = map (evalAttrExpr (atomTypes currentContext)) attrExprs
62+ case lefts eAttrs of
63+ err:_ -> pure (Left err)
64+ [] -> pure $ mkRelation (A.attributesFromList (rights eAttrs)) emptyTupleSet
65+
66+evalRelationalExpr (MakeRelationFromTupleExprs tupleExprs) = do
67+ currentContext <- get
68+ if null tupleExprs then
69+ pure $ Left CouldNotInferAttributes
70+ else
71+ let eTuples = map (evalTupleExpr currentContext) tupleExprs in
72+ case lefts eTuples of
73+ err:_ -> pure (Left err)
74+ [] -> case head eTuples of
75+ Left err -> error $ "impossible Right err " ++ show err
76+ --extract potential attributes from first tuple
77+ Right firstTuple -> pure $ mkRelation (tupleAttributes firstTuple) (RelationTupleSet (rights eTuples))
78+
6079evalRelationalExpr (ExistingRelation rel) = return (Right rel)
6180
6281evalRelationalExpr (Rename oldAttrName newAttrName relExpr) = do
@@ -112,7 +131,7 @@ evalRelationalExpr (Extend tupleExpression relExpr) = do
112131 case evald of
113132 Left err -> return $ Left err
114133 Right rel -> do
115− case tupleExpressionProcessor rel tupleExpression context of
134+ case extendTupleExpressionProcessor rel tupleExpression context of
116135 Left err -> return $ Left err
117136 Right (newAttrs, tupProc) -> return $ relMogrify tupProc newAttrs rel
118137
@@ -124,91 +143,7 @@ emptyDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
124143 atomTypes = M.empty
125144 }
126145
127−basicDatabaseContext :: DatabaseContext
128−basicDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
129− relationVariables = M.fromList [("true", relationTrue),
130− ("false", relationFalse)],
131− atomFunctions = basicAtomFunctions,
132− notifications = M.empty,
133− atomTypes = basicAtomTypes
134− }
135146
136−dateExamples :: DatabaseContext
137−dateExamples = DatabaseContext { inclusionDependencies = dateIncDeps,
138− relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars,
139− notifications = M.empty,
140− atomFunctions = basicAtomFunctions,
141− atomTypes = basicAtomTypes }
142− where
143− dateRelVars = M.fromList [("S", suppliers),
144− ("P", products),
145− ("SP", supplierProducts)]
146− suppliers = suppliersRel
147− products = productsRel
148− supplierProducts = supplierProductsRel
149− dateIncDeps = M.fromList [("S_pkey", simplePKey ["S#"] "S"),
150− ("P_pkey", simplePKey ["P#"] "P"),
151− ("SP_pkey", simplePKey ["S#", "P#"] "SP")
152− ]
153− simplePKey attrNames relvarName = inclusionDependencyForKey (AttributeNames $ S.fromList attrNames) (RelationVariable relvarName)
154−
155−suppliersRel :: Relation
156−suppliersRel = case mkRelationFromList attrs atomMatrix of
157− Left _ -> undefined
158− Right rel -> rel
159− where
160− attrs = A.attributesFromList [Attribute "S#" stringAtomType,
161− Attribute "SNAME" stringAtomType,
162− Attribute "STATUS" intAtomType,
163− Attribute "CITY" stringAtomType]
164− atomMatrix = [
165− [stringAtom "S1", stringAtom "Smith", intAtom 20, stringAtom "London"],
166− [stringAtom "S2", stringAtom "Jones", intAtom 10, stringAtom "Paris"],
167− [stringAtom "S3", stringAtom "Blake", intAtom 30, stringAtom "Paris"],
168− [stringAtom "S4", stringAtom "Clark", intAtom 20, stringAtom "London"],
169− [stringAtom "S5", stringAtom "Adams", intAtom 30, stringAtom "Athens"]]
170−
171−supplierProductsRel :: Relation
172−supplierProductsRel = case mkRelationFromList attrs matrix of
173− Left _ -> undefined
174− Right rel -> rel
175− where
176− attrs = A.attributesFromList [Attribute "S#" stringAtomType,
177− Attribute "P#" stringAtomType,
178− Attribute "QTY" intAtomType]
179− matrix = [
180− [stringAtom "S1", stringAtom "P1", intAtom 300],
181− [stringAtom "S1", stringAtom "P2", intAtom 200],
182− [stringAtom "S1", stringAtom "P3", intAtom 400],
183− [stringAtom "S1", stringAtom "P4", intAtom 200],
184− [stringAtom "S1", stringAtom "P5", intAtom 100],
185− [stringAtom "S1", stringAtom "P6", intAtom 100],
186− [stringAtom "S2", stringAtom "P1", intAtom 300],
187− [stringAtom "S2", stringAtom "P2", intAtom 400],
188− [stringAtom "S3", stringAtom "P2", intAtom 200],
189− [stringAtom "S4", stringAtom "P2", intAtom 200],
190− [stringAtom "S4", stringAtom "P4", intAtom 300],
191− [stringAtom "S4", stringAtom "P5", intAtom 400]
192− ]
193−
194−productsRel :: Relation
195−productsRel = case mkRelationFromList attrs matrix of
196− Left _ -> undefined
197− Right rel -> rel
198− where
199− attrs = A.attributesFromList [Attribute "P#" stringAtomType,
200− Attribute "PNAME" stringAtomType,
201− Attribute "COLOR" stringAtomType,
202− Attribute "WEIGHT" intAtomType,
203− Attribute "CITY" stringAtomType]
204− matrix = [
205− [stringAtom "P1", stringAtom "Nut", stringAtom "Red", intAtom 12, stringAtom "London"],
206− [stringAtom "P2", stringAtom "Bolt", stringAtom "Green", intAtom 17, stringAtom "Paris"],
207− [stringAtom "P3", stringAtom "Screw", stringAtom "Blue", intAtom 17, stringAtom "Oslo"],
208− [stringAtom "P4", stringAtom "Screw", stringAtom "Red", intAtom 14, stringAtom "London"],
209− [stringAtom "P5", stringAtom "Cam", stringAtom "Blue", intAtom 12, stringAtom "Paris"],
210− [stringAtom "P6", stringAtom "Cog", stringAtom "Red", intAtom 19, stringAtom "London"]
211− ]
212147
213148--helper function to process relation variable creation/assignment
214149setRelVar :: RelVarName -> Relation -> DatabaseState (Maybe RelationalError)
@@ -231,13 +166,18 @@ deleteRelVar relVarName = do
231166 return Nothing
232167
233168evalContextExpr :: DatabaseExpr -> DatabaseState (Maybe RelationalError)
234−evalContextExpr (Define relVarName attrs) = do
169+evalContextExpr (Define relVarName attrExprs) = do
235170 relvars <- liftM relationVariables get
236− case M.member relVarName relvars of
237− True -> return (Just (RelVarAlreadyDefinedError relVarName))
238− False -> setRelVar relVarName emptyRelation
239− where
240− emptyRelation = Relation attrs emptyTupleSet
171+ aTypes <- liftM atomTypes get
172+ let eAttrs = map (evalAttrExpr aTypes) attrExprs
173+ case lefts eAttrs of
174+ err:_ -> pure (Just err)
175+ [] -> case M.member relVarName relvars of
176+ True -> return (Just (RelVarAlreadyDefinedError relVarName))
177+ False -> setRelVar relVarName emptyRelation
178+ where
179+ attrs = A.attributesFromList (rights eAttrs)
180+ emptyRelation = Relation attrs emptyTupleSet
241181
242182evalContextExpr (Undefine relVarName) = do
243183 deleteRelVar relVarName
@@ -335,16 +275,18 @@ evalContextExpr (RemoveNotification notName) = do
335275
336276-- | Adds type and data constructors to the database context.
337277-- validate that the type *and* constructor names are unique! not yet implemented!
338−evalContextExpr (AddAtomConstructor tConsName atomConstructor) = do
278+evalContextExpr (AddAtomConstructor tConsName atomC@(AtomConstructor atomConsMap)) = do
339279 currentContext <- get
340280 let oldAtomTypes = atomTypes currentContext
281+ -- validate that the constructor's types exist
282+ -- atomAndArgsTypesForDataConstructorName oldAtomTypes
341283 if T.length tConsName < 1 || not (isUpper (T.head tConsName)) then
342284 pure $ Just (InvalidAtomTypeName tConsName)
343285 else if M.member tConsName oldAtomTypes then
344286 pure $ Just (AtomTypeNameInUseError tConsName)
345287 else do
346288 let newAtomTypes = M.insert tConsName newType oldAtomTypes
347− newType = (ConstructedAtomType tConsName, atomConstructor)
289+ newType = (ConstructedAtomType tConsName, atomC)
348290 put $ currentContext { atomTypes = newAtomTypes }
349291 pure Nothing
350292
@@ -475,8 +417,8 @@ tupleExprCheckNewAttrName attrName rel = if isRight $ attributeForName attrName
475417 else
476418 Right rel
477419
478−tupleExpressionProcessor :: Relation -> TupleExpr -> DatabaseContext -> Either RelationalError (Attributes, RelationTuple -> RelationTuple)
479−tupleExpressionProcessor relIn
420+extendTupleExpressionProcessor :: Relation -> ExtendTupleExpr -> DatabaseContext -> Either RelationalError (Attributes, RelationTuple -> RelationTuple)
421+extendTupleExpressionProcessor relIn
480422 (AttributeExtendTupleExpr newAttrName atomExpr) context = do
481423 _ <- tupleExprCheckNewAttrName newAttrName relIn
482424 atomExprType <- typeFromAtomExpr (attributes relIn) context atomExpr
@@ -525,7 +467,7 @@ typeFromAtomExpr attrs context (ConstructedAtomExpr dConsName dConsArgs) = do
525467 else
526468 pure tConsType
527469
528−-- | Validae that the
470+-- | Validate that the type of the AtomExpr matches the expected type.
529471verifyAtomExprTypes :: Relation -> DatabaseContext -> AtomExpr -> AtomType -> Either RelationalError AtomType
530472verifyAtomExprTypes relIn _ (AttributeAtomExpr attrName) expectedType = do
531473 attrType <- A.atomTypeForAttributeName attrName (attributes relIn)
@@ -553,52 +495,21 @@ verifyAtomExprTypes rel context cons@(ConstructedAtomExpr _ _) expectedType = do
553495 atomTypeVerify expectedType cType
554496
555497
556−
557−basicAtomFunctions :: AtomFunctions
558−basicAtomFunctions = HS.fromList $ [
559− --match on any relation type
560− AtomFunction { atomFuncName = "add",
561− atomFuncType = [intAtomType, intAtomType, intAtomType],
562− atomFunc = (\(i1:i2:_) -> Atom $ ((unsafeCast i1)::Int) + unsafeCast i2)},
563− AtomFunction { atomFuncName = "id",
564− atomFuncType = [AnyAtomType, AnyAtomType],
565− atomFunc = (\(x:_) -> x)},
566− AtomFunction { atomFuncName = "sum",
567− atomFuncType = foldAtomFuncType intAtomType intAtomType,
568− atomFunc = (\(relAtom:_) -> relationSum $ unsafeCast relAtom)},
569− AtomFunction { atomFuncName = "count",
570− atomFuncType = foldAtomFuncType AnyAtomType intAtomType,
571− atomFunc = (\((relIn):_) -> relationCount (castRelation relIn))},
572− AtomFunction { atomFuncName = "max",
573− atomFuncType = foldAtomFuncType intAtomType intAtomType,
574− atomFunc = (\((relIn):_) -> relationMax (castRelation relIn))},
575− AtomFunction { atomFuncName = "min",
576− atomFuncType = foldAtomFuncType intAtomType intAtomType,
577− atomFunc = (\((relIn):_) -> relationMin (castRelation relIn))},
578− AtomFunction { atomFuncName = "lt",
579− atomFuncType = [intAtomType, intAtomType, boolAtomType],
580− atomFunc = intAtomFuncLessThan False},
581− AtomFunction { atomFuncName = "lte",
582− atomFuncType = [intAtomType, intAtomType, boolAtomType],
583− atomFunc = intAtomFuncLessThan True},
584− AtomFunction { atomFuncName = "gte",
585− atomFuncType = [intAtomType, intAtomType, boolAtomType],
586− atomFunc = boolAtomNot . (:[]) . intAtomFuncLessThan False},
587− AtomFunction { atomFuncName = "gt",
588− atomFuncType = [intAtomType, intAtomType, boolAtomType],
589− atomFunc = boolAtomNot . (:[]) . intAtomFuncLessThan True},
590− AtomFunction { atomFuncName = "not",
591− atomFuncType = [boolAtomType, boolAtomType],
592− atomFunc = boolAtomNot}
593− ] ++ intervalFunctions
594−
595−intAtomFuncLessThan :: Bool -> [Atom] -> Atom
596−intAtomFuncLessThan equality (iatom1:iatom2:_) = (\i1 i2 -> Atom $ ((unsafeCast i1)::Int) `op` unsafeCast i2) iatom1 iatom2
597− where
598− op = if equality then (<=) else (<)
599−intAtomFuncLessThan _ _= Atom False
600−
601−boolAtomNot :: [Atom] -> Atom
602−boolAtomNot (bool:_) = Atom $ not (unsafeCast bool)
603−boolAtomNot _ = Atom False
604−
498+-- | Look up the type's name and create a new attribute.
499+evalAttrExpr :: AtomTypes -> AttributeExpr -> Either RelationalError Attribute
500+evalAttrExpr aTypes (AttributeAndTypeNameExpr attrName tConsName) = do
501+ aType <- atomTypeForTypeConstructor tConsName aTypes
502+ Right (Attribute attrName aType)
503+
504+evalTupleExpr :: DatabaseContext -> TupleExpr -> Either RelationalError RelationTuple
505+evalTupleExpr context (TupleExpr tupMap) = do
506+ -- it's not possible for AtomExprs in tuple constructors to reference other Attributes' atoms due to the necessary order-of-operations (need a tuple to pass to evalAtomExpr)- it may be possible with some refactoring of type usage or delayed evaluation- needs more thought, but not a priority
507+ attrAtoms <- mapM (\(attrName, aExpr) -> do
508+ newAtom <- evalAtomExpr emptyTuple context aExpr
509+ newAtomType <- typeFromAtomExpr A.emptyAttributes context aExpr
510+ pure (attrName, newAtom, newAtomType)
511+ ) (M.toList tupMap)
512+ let attrs = map (\(attrName, _, aType) -> Attribute attrName aType) attrAtoms
513+ atoms = V.fromList $ map (\(_, atom, _) -> atom) attrAtoms
514+ pure $ mkRelationTuple (A.attributesFromList attrs) atoms
515+
ProjectM36/Sessions.hs+5−4
@@ -5,8 +5,9 @@ import qualified STMContainers.Map as STMMap
55import ListT
66import ProjectM36.Attribute
77import ProjectM36.Base
8−import ProjectM36.Atom
8+import ProjectM36.DataTypes.Primitive
99import ProjectM36.Session
10+import ProjectM36.Atom
1011import ProjectM36.Relation
1112import ProjectM36.Error
1213import qualified Data.UUID as U
@@ -17,13 +18,13 @@ stmMapToList :: STMMap.Map k v -> STM [(k, v)]
1718stmMapToList = ListT.fold (\l -> return . (:l)) [] . STMMap.stream
1819
1920uuidAtom :: U.UUID -> Atom
20−uuidAtom = stringAtom . U.toText
21+uuidAtom = textAtom . U.toText
2122
2223sessionsAsRelation :: Sessions -> STM (Either RelationalError Relation)
2324sessionsAsRelation sessions = do
2425 sessionAssocs <- stmMapToList sessions
2526 let atomMatrix = map (\(sessionId, (Session (DisconnectedTransaction parentUUID _))) -> [uuidAtom sessionId, uuidAtom parentUUID]) sessionAssocs
26− pure $ mkRelationFromList (attributesFromList [Attribute "sessionid" stringAtomType,
27− Attribute "parentCommit" stringAtomType]) atomMatrix
27+ pure $ mkRelationFromList (attributesFromList [Attribute "sessionid" textAtomType,
28+ Attribute "parentCommit" textAtomType]) atomMatrix
2829
2930
ProjectM36/StaticOptimizer.hs+7
@@ -15,8 +15,12 @@ import Data.Either (rights, lefts)
1515applyStaticRelationalOptimization :: RelationalExpr -> DatabaseState (Either RelationalError RelationalExpr)
1616applyStaticRelationalOptimization e@(MakeStaticRelation _ _) = return $ Right e
1717
18+applyStaticRelationalOptimization e@(MakeRelationFromTupleExprs _) = return $ Right e
19+
1820applyStaticRelationalOptimization e@(ExistingRelation _) = return $ Right e
1921
22+applyStaticRelationalOptimization e@(MakeEmptyRelation _) = return $ Right e
23+
2024applyStaticRelationalOptimization e@(RelationVariable _) = return $ Right e
2125
2226--remove project of attributes which removes no attributes
@@ -133,6 +137,9 @@ applyStaticDatabaseOptimization (AddNotification name triggerExpr resultExpr) =
133137
134138applyStaticDatabaseOptimization notif@(RemoveNotification _) = pure (Right notif)
135139
140+applyStaticDatabaseOptimization c@(AddAtomConstructor _ _) = pure (Right c)
141+applyStaticDatabaseOptimization c@(RemoveAtomConstructor _) = pure (Right c)
142+
136143--optimization: from pgsql lists- check for join condition referencing foreign key- if join projection project away the referenced table, then it does not need to be scanned
137144
138145--applyStaticDatabaseOptimization (MultipleExpr exprs) = return $ Right $ MultipleExpr exprs
ProjectM36/Transaction/Persist.hs+16−2
@@ -11,7 +11,7 @@ import System.FilePath
1111import System.Directory
1212import qualified Data.Text as T
1313import Control.Monad
14−import ProjectM36.RelationalExpression (basicAtomFunctions)
14+import ProjectM36.AtomFunctions.Basic (basicAtomFunctions)
1515
1616getDirectoryNames :: FilePath -> IO [FilePath]
1717getDirectoryNames path = do
@@ -36,6 +36,9 @@ incDepsDir transdir = transdir </> "incdeps"
3636atomFuncsDir :: FilePath -> FilePath
3737atomFuncsDir transdir = transdir </> "atomfuncs"
3838
39+atomTypesPath :: FilePath -> FilePath
40+atomTypesPath transdir = transdir </> "atomtypes"
41+
3942readTransaction :: FilePath -> U.UUID -> IO (Either PersistenceError Transaction)
4043readTransaction dbdir transUUID = do
4144 let transDir = transactionDir dbdir transUUID
@@ -46,10 +49,12 @@ readTransaction dbdir transUUID = do
4649 relvars <- readRelVars transDir
4750 transInfo <- liftM B.decode $ BS.readFile (transactionInfoPath transDir)
4851 incDeps <- readIncDeps transDir
52+ atomtypes <- readAtomTypes transDir
4953 --atomFuncs <- readAtomFuncs transDir -- not yet supported since there is no bytecode to serialize yet
5054 let atomFuncs = basicAtomFunctions
5155 let newContext = DatabaseContext { inclusionDependencies = incDeps,
5256 relationVariables = relvars,
57+ atomTypes = atomtypes,
5358 notifications = M.empty,
5459 atomFunctions = atomFuncs }
5560
@@ -67,6 +72,7 @@ writeTransaction sync dbdir trans = do
6772 writeRelVars sync tempTransDir (relationVariables context)
6873 writeIncDeps sync tempTransDir (inclusionDependencies context)
6974 writeAtomFuncs sync tempTransDir (atomFunctions context)
75+ writeAtomTypes sync tempTransDir (atomTypes context)
7076 BS.writeFile (transactionInfoPath tempTransDir) (B.encode $ transactionInfo trans)
7177 --move the temp directory to final location
7278 renameSync sync tempTransDir finalTransDir
@@ -130,4 +136,12 @@ readIncDeps transDir = do
130136 let incDepsPath = incDepsDir transDir
131137 incDepNames <- getDirectoryNames incDepsPath
132138 incDeps <- mapM (readIncDep transDir) (map T.pack incDepNames)
133− return $ M.fromList incDeps
139+ return $ M.fromList incDeps
140+
141+writeAtomTypes :: DiskSync -> FilePath -> AtomTypes -> IO ()
142+writeAtomTypes sync path aTypes = writeBSFileSync sync path $ B.encode aTypes
143+
144+readAtomTypes :: FilePath -> IO (AtomTypes)
145+readAtomTypes path = do
146+ let atPath = atomTypesPath path
147+ liftM B.decode (BS.readFile atPath)
ProjectM36/TransactionGraph.hs+5−5
@@ -6,7 +6,7 @@ import ProjectM36.Transaction
66import ProjectM36.Relation
77import ProjectM36.TupleSet
88import ProjectM36.Tuple
9−import ProjectM36.Atom
9+import ProjectM36.DataTypes.Primitive
1010import qualified Data.Vector as V
1111import qualified ProjectM36.Attribute as A
1212import qualified Data.UUID as U
@@ -213,12 +213,12 @@ graphAsRelation (DisconnectedTransaction parentUUID _) graph@(TransactionGraph _
213213 tupleMatrix <- mapM tupleGenerator (S.toList transSet)
214214 mkRelationFromList attrs tupleMatrix
215215 where
216− attrs = A.attributesFromList [Attribute "id" stringAtomType,
216+ attrs = A.attributesFromList [Attribute "id" textAtomType,
217217 Attribute "parents" (RelationAtomType parentAttributes),
218218 Attribute "current" boolAtomType,
219− Attribute "head" stringAtomType
219+ Attribute "head" textAtomType
220220 ]
221− parentAttributes = A.attributesFromList [Attribute "id" stringAtomType]
221+ parentAttributes = A.attributesFromList [Attribute "id" textAtomType]
222222 tupleGenerator transaction = case transactionParentsRelation transaction graph of
223223 Left err -> Left err
224224 Right parentTransRel -> Right [Atom $ T.pack $ show (transactionUUID transaction),
@@ -238,7 +238,7 @@ transactionParentsRelation trans graph = do
238238 let tuples = map trans2tuple (S.toList parentTransSet)
239239 mkRelationFromTuples attrs tuples
240240 where
241− attrs = A.attributesFromList [Attribute "id" stringAtomType]
241+ attrs = A.attributesFromList [Attribute "id" textAtomType]
242242 trans2tuple trans2 = mkRelationTuple attrs $ V.singleton (Atom (T.pack (show $ transactionUUID trans2)))
243243
244244{-
TutorialD/Interpreter/Base.hs+5−3
@@ -10,7 +10,7 @@ import qualified Data.List as L
1010import qualified Data.Vector as V
1111import qualified Data.Text.IO as TIO
1212import System.IO
13−import ProjectM36.Atom
13+import ProjectM36.DataTypes.Primitive
1414
1515lexer :: Token.TokenParser ()
1616lexer = Token.makeTokenParser tutD
@@ -39,6 +39,9 @@ identifier = Token.identifier lexer
3939comma :: Parser String
4040comma = Token.comma lexer
4141
42+pipe :: Parser String
43+pipe = Token.symbol lexer "|"
44+
4245semi :: Parser String
4346semi = Token.semi lexer
4447
@@ -53,10 +56,9 @@ float = Token.float lexer
5356
5457atomTypeToTutDType :: AtomType -> Maybe T.Text
5558atomTypeToTutDType atomType = case atomType of
56− aType@(AtomType _) -> lookup aType [(stringAtomType, "char"),
59+ aType@(AtomType _) -> lookup aType [(textAtomType, "char"),
5760 (intAtomType, "int"),
5861 (boolAtomType, "bool"),
59− (dateTimeAtomType, "datetime"),
6062 (doubleAtomType, "double")]
6163 (RelationAtomType attrs) -> Just $ "relation" `T.append` showRelationAttributes attrs
6264 _ -> Nothing
TutorialD/Interpreter/DatabaseExpr.hs+2−2
@@ -56,7 +56,7 @@ defineP = do
5656 relVarName <- identifier
5757 reservedOp "::"
5858 return relVarName
59− attributeSet <- makeAttributesP
59+ attributeSet <- makeAttributeExprsP
6060 return $ Define (T.pack relVarName) attributeSet
6161
6262undefineP :: Parser DatabaseExpr
@@ -132,7 +132,7 @@ addAtomConstructorP = do
132132 reserved "data"
133133 typeConstructorName <- identifier
134134 reservedOp "="
135− dataConstructors <- sepBy1 dataConstructorP comma
135+ dataConstructors <- sepBy1 dataConstructorP pipe
136136 let aCons = AtomConstructor (M.fromList dataConstructors)
137137 pure (AddAtomConstructor (T.pack typeConstructorName) aCons)
138138
TutorialD/Interpreter/RelationalExpr.hs+24−106
@@ -5,36 +5,15 @@ import ProjectM36.Base
55import Text.Parsec.String
66import TutorialD.Interpreter.Base
77import qualified Data.Text as T
8−import qualified ProjectM36.Attribute as A
9−import ProjectM36.TupleSet
10−import ProjectM36.Tuple
11−import ProjectM36.Relation
12−import ProjectM36.Atom
13−import qualified Data.Vector as V
148import qualified Data.Set as S
9+import qualified Data.Map as M
1510import Data.Functor.Identity (Identity)
1611import Data.Time.Format
1712import Control.Applicative (liftA)
1813import Data.ByteString.Base64 as B64
1914import Data.Text.Encoding as TE
20−import TutorialD.Interpreter.DataTypes.DateTime
21−import TutorialD.Interpreter.DataTypes.Interval
22−
2315import Data.Time.Calendar (Day)
2416
25−--nuke this
26−{-
27−atomTypeP :: Parser AtomType
28−atomTypeP = (reserved "char" *> return stringAtomType) <|>
29− (reserved "int" *> return intAtomType) <|>
30− (reserved "datetime" *> return dateTimeAtomType) <|>
31− (reserved "date" *> return dateAtomType) <|>
32− (reserved "double" *> return doubleAtomType) <|>
33− (reserved "bool" *> return boolAtomType) <|>
34− (reserved "bytestring" *> return byteStringAtomType) <|>
35− (RelationAtomType <$> (reserved "relation" *> makeAttributesP))
36−-}
37−
3817--used in projection
3918attributeListP :: Parser AttributeNames
4019attributeListP = do
@@ -46,40 +25,29 @@ attributeListP = do
4625makeRelationP :: Parser RelationalExpr
4726makeRelationP = do
4827 reserved "relation"
49− attrs <- (try makeAttributesP <|> return A.emptyAttributes)
50− if not (A.null attrs) then do
51− case mkRelation attrs emptyTupleSet of
52− Left err -> fail (show err)
53− Right rel -> pure (ExistingRelation rel)
54− else do -- empty attributes
28+ attrExprs <- (try makeAttributeExprsP <|> pure [])
29+ if not (null attrExprs) then do
30+ pure $ MakeEmptyRelation attrExprs
31+ else do -- empty attributes, assume tuple expressions
5532 tupleExprs <- try (braces (sepBy tupleExprP comma)) <|> pure []
56− pure $ MakeRelationFromAtomExprs attrs
57−
58−
59−makeAttributeExprsP :: Parser [AttributeExpr]
60−makeAttributeExprsP = do
61− attrList <- bra
33+ pure $ MakeRelationFromTupleExprs tupleExprs
6234
6335--used in relation creation
64−makeAttributeExprsP :: Parser [AttributeExprs]
65−makeAttributeExprsP = do
66− attrList <- braces (sepBy attributeAndTypeNameP comma)
67− return $ A.attributesFromList attrList
68−
36+makeAttributeExprsP :: Parser [AttributeExpr]
37+makeAttributeExprsP = braces (sepBy attributeAndTypeNameP comma)
6938
7039attributeAndTypeNameP :: Parser AttributeExpr
7140attributeAndTypeNameP = do
7241 attrName <- identifier
7342 --convert type name into type
7443 atomType <- identifier
75− return $ AttributeAndTypeNameExpr (T.pack attrName) atomType
44+ return $ AttributeAndTypeNameExpr (T.pack attrName) (T.pack atomType)
7645
7746tupleExprP :: Parser TupleExpr
7847tupleExprP = do
7948 reservedOp "tuple"
8049 attrAssocs <- braces (sepBy tupleAtomExprP comma)
81− let attrs = A.attributesFromList $ map fst attrAssocs
82− pure (TupleExpr attrs (map snd attrAssocs))
50+ pure (TupleExpr (M.fromList attrAssocs))
8351
8452tupleAtomExprP :: Parser (AttributeName, AtomExpr)
8553tupleAtomExprP = do
@@ -137,33 +105,6 @@ extendP = do
137105 tupleExpr <- braces extendTupleExpressionP
138106 return $ Extend tupleExpr
139107
140−{-
141−rewrite summarize as extend as evaluate
142−it turns out that summarize must be a relational expression primitive because it requires
143−
144−summarize SP per (SP{SNO}) add (sum(@QTY) as SUMQ) === ((SP rename {QTY as _}) group ({_} as x)) : {QTY:=sum(@x)}{S#,QTY}
145−so, in general,
146−summarize rX per (relExpr) add (func(@attr) as funcd) === ((rX rename {attr as _}) group ({_} as _)) : {QTY:=sum(@_)}{relExpr, _}
147−-}
148−{-
149−summarizeP :: Parser (RelationalExpr -> RelationalExpr)
150−summarizeP = do
151− reservedOp "per"
152− -- "summarize in Tutorial D requires the heading of the per relation to be a subset of that of the relation to be summarized"
153− perExpr <- parens relExpr
154− reservedOp "add"
155− (funcAtomExpr, newAttrName) <- parens summaryP
156− --rewrite summarize as extend
157− --return $ Summarize funcAtomExpr newAttrName perExpr
158−
159−summaryP :: Parser (AtomExpr, AttributeName)
160−summaryP = do
161− expr <- atomExprP
162− reserved "as"
163− attrName <- identifier
164− return (expr, T.pack attrName)
165−-}
166−
167108relOperators :: [[Operator String () Identity RelationalExpr]]
168109relOperators = [
169110 [Postfix projectP],
@@ -234,10 +175,10 @@ attributeExtendTupleExpressionP = do
234175
235176atomExprP :: Parser AtomExpr
236177atomExprP = try functionAtomExprP <|>
237− attributeAtomExprP <|>
238− nakedAtomExprP <|>
239− relationalAtomExprP <|>
240− constructedAtomP
178+ try constructedAtomExprP <|>
179+ attributeAtomExprP <|>
180+ nakedAtomExprP <|>
181+ relationalAtomExprP
241182
242183attributeAtomExprP :: Parser AtomExpr
243184attributeAtomExprP = do
@@ -249,26 +190,20 @@ nakedAtomExprP :: Parser AtomExpr
249190nakedAtomExprP = NakedAtomExpr <$> atomP
250191
251192-- | Uses square brackets for TutorialD support.
252−constructedAtomP :: Parser AtomExpr
253−constructedAtomP = do
254− reserved "["
255− dConsName <- identifier
256− dConsArgs <- sepBy atomExprP spaces
257− reserved "]"
193+constructedAtomExprP :: Parser AtomExpr
194+constructedAtomExprP = do
195+ dConsName <- identifier
196+ _ <- char '['
197+ dConsArgs <- sepBy atomExprP comma
198+ _ <- char ']'
258199 pure $ ConstructedAtomExpr (T.pack dConsName) dConsArgs
259200
201+-- used only for primitive type parsing ?
260202atomP :: Parser Atom
261−atomP = dateTimeAtomP <|>
262− intervalDateTimeAtomP <|>
263− dateAtomP <|>
264− maybeTextAtomP <|>
265− maybeIntAtomP <|>
266− byteStringAtomP <|>
267− stringAtomP <|>
203+atomP = stringAtomP <|>
268204 doubleAtomP <|>
269205 intAtomP <|>
270− boolAtomP <|>
271− relationAtomP
206+ boolAtomP
272207
273208functionAtomExprP :: Parser AtomExpr
274209functionAtomExprP = do
@@ -321,7 +256,7 @@ boolAtomP = do
321256 return $ Atom (val == 't')
322257
323258relationAtomExprP :: Parser AtomExpr
324−relationAtomExprP = RelationAtomExpr <$> relationExprP
259+relationAtomExprP = RelationAtomExpr <$> makeRelationP
325260
326261-- deprecated for removal- use constructors
327262byteStringAtomP :: Parser Atom
@@ -334,20 +269,3 @@ byteStringAtomP = do
334269 Left err -> fail err
335270 Right bsVal -> return $ Atom bsVal
336271
337−{-
338−--relation constructor -- no choice but to propagate relation-construction errors as parse errors. Perhaps this could be improved in the future
339−relationP :: Parser Relation
340−relationP = do
341− reserved "relation"
342− attrs <- (try makeAttributesP <|> return A.emptyAttributes)
343− if not (A.null attrs) then do
344− case mkRelation attrs emptyTupleSet of
345− Left err -> fail (show err)
346− Right rel -> return rel
347− else do -- empty attributes
348− tuples <- try (braces (sepBy tupleP comma)) <|> pure []
349− let tupleAttrs = if null tuples then A.emptyAttributes else tupleAttributes (head tuples)
350− case mkRelationFromTuples tupleAttrs tuples of
351− Left err -> fail (show err)
352− Right rel -> return rel
353−-}
benchmark/bigrel.hs+10
@@ -92,3 +92,13 @@ vectorMatrixRelation attributeCount tupleCount = HS.fromList $ map mapper [0..tu
9292
9393instance Hash.Hashable (V.Vector Atom) where
9494 hashWithSalt salt vec = Hash.hashWithSalt salt (show vec)
95+
96+-- returns a relation with tupleCount tuples with a set of integer attributes attributesCount long
97+-- this is useful for performance and resource usage testing
98+matrixRelation :: Int -> Int -> Either RelationalError Relation
99+matrixRelation attributeCount tupleCount = do
100+ let attrs = A.attributesFromList $ map (\c-> Attribute (T.pack $ "a" ++ show c) intAtomType) [0 .. attributeCount-1]
101+ tuple tupleX = RelationTuple attrs (V.generate attributeCount (\_ -> Atom tupleX))
102+ tuples = map (\c -> tuple c) [0 .. tupleCount]
103+ mkRelationDeferVerify attrs (RelationTupleSet tuples)
104+