@@ -56,22 +56,30 @@ instance Atomable Relation
56instance (Atomable a) => Atomable (Maybe a)
56instance (Atomable a) => Atomable (Maybe a)
58-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
58-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
59−data Atom = forall a. Atomable a => Atom a
59+data Atom = forall a. Atomable a => Atom a |
60−
60+ ConstructedAtom DataConstructorName AtomType [Atom]
61instance Eq Atom where
62instance Eq Atom where
62 (Atom a) == (Atom b) = Just a == cast b
63 (Atom a) == (Atom b) = Just a == cast b
64+ (ConstructedAtom dConsNameA aTypeA atomListA) == (ConstructedAtom dConsNameB aTypeB atomListB) = aTypeA == aTypeB &&
65+ atomListA == atomListB &&
66+ dConsNameA == dConsNameB
64instance Show Atom where
69instance Show Atom where
65 show (Atom atom) = "Atom " ++ show atom
70 show (Atom atom) = "Atom " ++ show atom
71+ show (ConstructedAtom dConsName _ atomList) = unpack dConsName ++ " " ++ L.concat (L.intersperse " " (map show atomList))
67instance Binary Atom where
73instance Binary Atom where
68 put atom@(Atom val) = put (atomTypeForAtom atom) >> put val
74 put atom@(Atom val) = put (atomTypeForAtom atom) >> put val
75+ put (ConstructedAtom dConsName aType atomList) = put aType >> put dConsName >> put atomList
70 atomtype <- get
77 atomtype <- get
71 --not-so-great for this to be hardcoded here- it would be nicer to have a dispatch table linked to the instances themselves
78 --not-so-great for this to be hardcoded here- it would be nicer to have a dispatch table linked to the instances themselves
72 --http://stackoverflow.com/questions/8101067/binary-instance-for-an-existential
79 --http://stackoverflow.com/questions/8101067/binary-instance-for-an-existential
73 case atomtype of
80 case atomtype of
74 AnyAtomType -> error "unsupported serialization AnyAtomType"
81 AnyAtomType -> error "unsupported serialization AnyAtomType"
82+ caType@(ConstructedAtomType _) -> ConstructedAtom <$> (get :: Get DataConstructorName) <*> pure caType <*> (get :: Get [Atom]) --we really should verify the type with the atoms
75 (RelationAtomType _) -> Atom <$> (get :: Get Relation)
83 (RelationAtomType _) -> Atom <$> (get :: Get Relation)
76 (AtomType cTypeRep) -> if unCTR cTypeRep == typeRep (Proxy :: Proxy Int) then
84 (AtomType cTypeRep) -> if unCTR cTypeRep == typeRep (Proxy :: Proxy Int) then
77 Atom <$> (get :: Get Int)
85 Atom <$> (get :: Get Int)
@@ -92,15 +100,19 @@ instance Binary Atom where
93instance NFData Atom where
101instance NFData Atom where
94 rnf !(Atom a) = rnf a
102 rnf !(Atom a) = rnf a
103+ rnf !(ConstructedAtom dConsName aType atomList) = rnf (dConsName, atomList, aType)
96instance Hashable Atom where
105instance Hashable Atom where
97 hashWithSalt salt (Atom a) = hashWithSalt salt a
106 hashWithSalt salt (Atom a) = hashWithSalt salt a
107+ hashWithSalt salt (ConstructedAtom dConsName _ atomList) = salt `hashWithSalt` atomList
108+ `hashWithSalt` dConsName --AtomType is not hashable
99-- | Return the type of an 'Atom'.
110-- | Return the type of an 'Atom'.
100atomTypeForAtom :: Atom -> AtomType
111atomTypeForAtom :: Atom -> AtomType
101atomTypeForAtom (Atom atom) = case cast atom of
112atomTypeForAtom (Atom atom) = case cast atom of
102 Just (Relation attrs _) -> RelationAtomType attrs
113 Just (Relation attrs _) -> RelationAtomType attrs
103 Nothing -> AtomType $ CTR (typeOf atom)
114 Nothing -> AtomType $ CTR (typeOf atom)
115+atomTypeForAtom (ConstructedAtom _ aType _) = aType
105instance Binary UTCTime where
117instance Binary UTCTime where
106 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
118 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
@@ -113,9 +125,12 @@ instance Binary Day where
114 (y,m,d) <- get :: Get (Integer, Int, Int)
126 (y,m,d) <- get :: Get (Integer, Int, Int)
115 return (fromGregorian y m d)
127 return (fromGregorian y m d)
129+-- I suspect the definition of ConstructedAtomType with its name alone is insufficient to disambiguate the cases; for example, one could create a type named X, remove a type named X, and re-add it using different constructors. However, as long as requests are served from only one DatabaseContext at-a-time, the type name is unambiguous. This will become a problem for time-travel, however.
130+-- | The AtomType must uniquely identify the type of a atom.
117data AtomType = AtomType ConcreteTypeRep |
131data AtomType = AtomType ConcreteTypeRep |
118 RelationAtomType Attributes |
132 RelationAtomType Attributes |
133+ ConstructedAtomType TypeConstructorName |
119 AnyAtomType --wildcard used in Atom Functions
134 AnyAtomType --wildcard used in Atom Functions
120 deriving (Eq,NFData,Generic,Binary,Show)
135 deriving (Eq,NFData,Generic,Binary,Show)
@@ -124,6 +139,7 @@ isRelationAtomType :: AtomType -> Bool
124isRelationAtomType (RelationAtomType _) = True
139isRelationAtomType (RelationAtomType _) = True
125isRelationAtomType _ = False
140isRelationAtomType _ = False
142+-- | The AttributeName is the name of an attribute in a relation.
127type AttributeName = StringType
143type AttributeName = StringType
129-- | A relation's type is composed of attribute names and types.
145-- | A relation's type is composed of attribute names and types.
@@ -256,12 +272,15 @@ data Notification = Notification {
257 deriving (Show, Eq, Binary, Generic)
273 deriving (Show, Eq, Binary, Generic)
275+type AtomTypes = M.Map TypeConstructorName (AtomType, AtomConstructor)
259-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
277-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
260data DatabaseContext = DatabaseContext {
278data DatabaseContext = DatabaseContext {
261 inclusionDependencies :: M.Map IncDepName InclusionDependency,
279 inclusionDependencies :: M.Map IncDepName InclusionDependency,
262 relationVariables :: M.Map RelVarName Relation,
280 relationVariables :: M.Map RelVarName Relation,
263 atomFunctions :: AtomFunctions,
281 atomFunctions :: AtomFunctions,
264− notifications :: Notifications
282+ notifications :: Notifications,
283+ atomTypes :: AtomTypes
265 } deriving (Show, Generic)
284 } deriving (Show, Generic)
267type IncDepName = StringType
286type IncDepName = StringType
@@ -285,10 +304,24 @@ data DatabaseExpr where
286 AddNotification :: NotificationName -> RelationalExpr -> RelationalExpr -> DatabaseExpr
305 AddNotification :: NotificationName -> RelationalExpr -> RelationalExpr -> DatabaseExpr
287 RemoveNotification :: NotificationName -> DatabaseExpr
306 RemoveNotification :: NotificationName -> DatabaseExpr
308+ -- this may be generalized to AddAtomFunction in the future
309+ AddAtomConstructor :: TypeConstructorName -> AtomConstructor -> DatabaseExpr
310+ RemoveAtomConstructor :: TypeConstructorName -> DatabaseExpr
312+ -- to implement this, I likely need to implement a DSL for constructing arbitrary functions to operate on atoms at runtime
313+ --AddAtomFunction :: AtomFunction -> DatabaseExpr
314+ --RemoveAtomFunction :: AtomFunctionName -> DatabaseExpr
289 MultipleExpr :: [DatabaseExpr] -> DatabaseExpr
316 MultipleExpr :: [DatabaseExpr] -> DatabaseExpr
290 deriving (Show, Eq, Binary, Generic)
317 deriving (Show, Eq, Binary, Generic)
319+type TypeConstructorName = StringType
320+type DataConstructorName = StringType
321+type AtomTypeName = StringType
323+data AtomConstructor = AtomConstructor (M.Map DataConstructorName [AtomTypeName]) deriving (Eq, Show, Binary, Generic)
292type DatabaseState a = State DatabaseContext a
325type DatabaseState a = State DatabaseContext a
294-- | Restriction predicate are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.
327-- | Restriction predicate are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.