on fd05d50 help sign in
519 lines 27 kB history raw
1{-# LANGUAGE ExistentialQuantification,DeriveGeneric,DeriveAnyClass, TypeSynonymInstances, FlexibleInstances #-}
2{-# OPTIONS_GHC -fno-warn-orphans #-}
3module ProjectM36.Base where
4import ProjectM36.DatabaseContextFunctionError
5import ProjectM36.AtomFunctionError
7import qualified Data.Map as M
8import qualified Data.HashSet as HS
9import Data.Hashable (Hashable, hashWithSalt)
10import qualified Data.Set as S
11import Data.UUID (UUID)
12import Control.DeepSeq (NFData, rnf)
13import Control.DeepSeq.Generics (genericRnf)
14import GHC.Generics (Generic)
15import qualified Data.Vector as V
16import qualified Data.List as L
17import Data.Text (Text,unpack)
18import Data.Binary
19import Data.Vector.Binary()
20import Data.Time.Clock
21import Data.Time.Clock.POSIX
22import Data.Time.Calendar (Day,toGregorian,fromGregorian)
23import Data.Hashable.Time ()
24import Data.Typeable
25import Data.ByteString (ByteString)
27type StringType = Text
29-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
30data Atom = IntAtom Int |
31 DoubleAtom Double |
32 TextAtom Text |
33 DayAtom Day |
34 DateTimeAtom UTCTime |
35 ByteStringAtom ByteString |
36 BoolAtom Bool |
37 IntervalAtom Atom Atom OpenInterval OpenInterval |
38 RelationAtom Relation |
39 ConstructedAtom DataConstructorName AtomType [Atom]
40 deriving (Eq, Show, Binary, Typeable, NFData, Generic)
42type OpenInterval = Bool
44instance Hashable Atom where
45 hashWithSalt salt (ConstructedAtom dConsName _ atoms) = salt `hashWithSalt` atoms
46 `hashWithSalt` dConsName --AtomType is not hashable
47 hashWithSalt salt (IntAtom i) = salt `hashWithSalt` i
48 hashWithSalt salt (DoubleAtom d) = salt `hashWithSalt` d
49 hashWithSalt salt (TextAtom t) = salt `hashWithSalt` t
50 hashWithSalt salt (DayAtom d) = salt `hashWithSalt` d
51 hashWithSalt salt (DateTimeAtom dt) = salt `hashWithSalt` dt
52 hashWithSalt salt (ByteStringAtom bs) = salt `hashWithSalt` bs
53 hashWithSalt salt (BoolAtom b) = salt `hashWithSalt` b
54 hashWithSalt salt (IntervalAtom a1 a2 bo be) = salt `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` bo `hashWithSalt` be
55 hashWithSalt salt (RelationAtom r) = salt `hashWithSalt` r
57instance Binary UTCTime where
58 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
59 get = do
60 r <- get :: Get Rational
61 return (posixSecondsToUTCTime (fromRational r))
63instance Binary Day where
64 put day = put $ toGregorian day
65 get = do
66 (y,m,d) <- get :: Get (Integer, Int, Int)
67 return (fromGregorian y m d)
69-- 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.
70-- | The AtomType uniquely identifies the type of a atom.
71data AtomType = IntAtomType |
72 DoubleAtomType |
73 TextAtomType |
74 DayAtomType |
75 DateTimeAtomType |
76 ByteStringAtomType |
77 BoolAtomType |
78 IntervalAtomType AtomType |
79 RelationAtomType Attributes |
80 ConstructedAtomType TypeConstructorName TypeVarMap |
81 TypeVariableType TypeVarName
82 --wildcard used in Atom Functions and tuples for data constructors which don't provide all arguments to the type constructor
83 deriving (Eq, NFData, Generic, Binary, Show)
85type TypeVarMap = M.Map TypeVarName AtomType
87instance Hashable TypeVarMap where
88 hashWithSalt salt tvmap = hashWithSalt salt (M.keys tvmap)
90-- | Return True iff the atom type argument is relation-valued. If True, this indicates that the Atom contains a relation.
91isRelationAtomType :: AtomType -> Bool
92isRelationAtomType (RelationAtomType _) = True
93isRelationAtomType _ = False
95-- | The AttributeName is the name of an attribute in a relation.
96type AttributeName = StringType
98-- | A relation's type is composed of attribute names and types.
99data Attribute = Attribute AttributeName AtomType deriving (Eq, Show, Generic, NFData, Binary)
101instance Hashable Attribute where
102 hashWithSalt salt (Attribute attrName _) = hashWithSalt salt attrName
104-- | 'Attributes' represent the head of a relation.
105type Attributes = V.Vector Attribute
107-- | Equality function for a set of attributes.
108attributesEqual :: Attributes -> Attributes -> Bool
109attributesEqual attrs1 attrs2 = attrsAsSet attrs1 == attrsAsSet attrs2
110 where
111 attrsAsSet = HS.fromList . V.toList
113sortedAttributesIndices :: Attributes -> [(Int, Attribute)]
114sortedAttributesIndices attrs = L.sortBy (\(_, Attribute name1 _) (_,Attribute name2 _) -> compare name1 name2) $ V.toList (V.indexed attrs)
116-- | The relation's tuple set is the body of the relation.
117newtype RelationTupleSet = RelationTupleSet { asList :: [RelationTuple] } deriving (Hashable, Show, Generic, Binary)
119instance Read Relation where
120 readsPrec = error "relation read not supported"
122instance Eq RelationTupleSet where
123 set1 == set2 = hset set1 == hset set2
124 where
125 hset = HS.fromList . asList
127instance NFData RelationTupleSet where rnf = genericRnf
129--the same hash must be generated for equal tuples so that the hashset equality works
130instance Hashable RelationTuple where
131 --sanity check the tuple for attribute and tuple counts
132 --this bit me when tuples were being hashed before being verified
133 hashWithSalt salt (RelationTuple attrs tupVec) = if V.length attrs /= V.length tupVec then
134 error "invalid tuple: attributes and tuple count mismatch"
135 else
136 salt `hashWithSalt`
137 sortedAttrs `hashWithSalt`
138 V.toList sortedTupVec
139 where
140 sortedAttrsIndices = sortedAttributesIndices attrs
141 sortedAttrs = map snd sortedAttrsIndices
142 sortedTupVec = V.map (\(index, _) -> tupVec V.! index) $ V.fromList sortedAttrsIndices
144-- | A tuple is a set of attributes mapped to their 'Atom' values.
145data RelationTuple = RelationTuple Attributes (V.Vector Atom) deriving (Show, Generic)
147instance Binary RelationTuple
149instance Eq RelationTuple where
150 (==) tuple1@(RelationTuple attrs1 _) tuple2@(RelationTuple attrs2 _) = attributesEqual attrs1 attrs2 && atomsEqual
151 where
152 atomForAttribute attr (RelationTuple attrs tupVec) = case V.findIndex (== attr) attrs of
153 Nothing -> Nothing
154 Just index -> tupVec V.!? index
155 atomsEqual = V.all (== True) $ V.map (\attr -> atomForAttribute attr tuple1 == atomForAttribute attr tuple2) attrs1
157instance NFData RelationTuple where rnf = genericRnf
159data Relation = Relation Attributes RelationTupleSet deriving (Show, Generic,Typeable)
161instance Eq Relation where
162 Relation attrs1 tupSet1 == Relation attrs2 tupSet2 = attributesEqual attrs1 attrs2 && tupSet1 == tupSet2
164instance NFData Relation where rnf = genericRnf
166instance Hashable Relation where
167 hashWithSalt salt (Relation attrs tupSet) = salt `hashWithSalt`
168 sortedAttrs `hashWithSalt`
169 asList tupSet
170 where
171 sortedAttrs = map snd (sortedAttributesIndices attrs)
173instance Binary Relation
175-- | Used to represent the number of tuples in a relation.
176data RelationCardinality = Countable | Finite Int deriving (Eq, Show, Generic, Ord)
178-- | Relation variables are identified by their names.
179type RelVarName = StringType
181type RelationalExpr = RelationalExprBase ()
183-- | A relational expression represents query (read) operations on a database.
184data RelationalExprBase a =
185 --- | Create a relation from tuple expressions.
186 MakeRelationFromExprs (Maybe [AttributeExprBase a]) [TupleExprBase a] |
187 --- | Create and reference a relation from attributes and a tuple set.
188 MakeStaticRelation Attributes RelationTupleSet |
189 --- | Reference an existing relation in Haskell-space.
190 ExistingRelation Relation |
191 --MakeFunctionalRelation (creates a relation from a tuple-generating function, potentially infinite)
192 --in Tutorial D, relational variables pick up the type of the first relation assigned to them
193 --relational variables should also be able to be explicitly-typed like in Haskell
194 --- | Reference a relation variable by its name.
195 RelationVariable RelVarName a |
196 --- | Create a projection over attribute names. (Note that the 'AttributeNames' structure allows for the names to be inverted.)
197 Project AttributeNames (RelationalExprBase a) |
198 --- | Create a union of two relational expressions. The expressions should have identical attributes.
199 Union (RelationalExprBase a) (RelationalExprBase a) |
200 --- | Create a join of two relational expressions. The join occurs on attributes which are identical. If the expressions have no overlapping attributes, the join becomes a cross-product of both tuple sets.
201 Join (RelationalExprBase a) (RelationalExprBase a) |
202 --- | Rename an attribute (first argument) to another (second argument).
203 Rename AttributeName AttributeName (RelationalExprBase a) |
204 --- | Return a relation containing all tuples of the first argument which do not appear in the second argument (minus).
205 Difference (RelationalExprBase a) (RelationalExprBase a) |
206 --- | Create a sub-relation composed of the first argument's attributes which will become an attribute of the result expression. The unreferenced attributes are not altered in the result but duplicate tuples in the projection of the expression minus the attribute names are compressed into one. For more information, <https://github.com/agentm/project-m36/blob/master/docs/introduction_to_the_relational_algebra.markdown#group read the relational algebra tutorial.>
207 Group AttributeNames AttributeName (RelationalExprBase a) |
208 --- | Create an expression to unwrap a sub-relation contained within at an attribute's name. Note that this is not always an inverse of a group operation.
209 Ungroup AttributeName (RelationalExprBase a) |
210 --- | Filter the tuples of the relational expression to only retain the tuples which evaluate against the restriction predicate to true.
211 Restrict (RestrictionPredicateExprBase a) (RelationalExprBase a) |
212 --- | Returns the true relation iff
213 Equals (RelationalExprBase a) (RelationalExprBase a) |
214 NotEquals (RelationalExprBase a) (RelationalExprBase a) |
215 Extend (ExtendTupleExprBase a) (RelationalExprBase a)
216 --Summarize :: AtomExpr -> AttributeName -> RelationalExpr -> RelationalExpr -> RelationalExpr -- a special case of Extend
217 deriving (Show, Eq, Generic, NFData)
219instance Binary RelationalExpr
221type NotificationName = StringType
222type Notifications = M.Map NotificationName Notification
224-- | When the changeExpr returns a different result in the database context, then the reportExpr is triggered and sent asynchronously to all clients.
225data Notification = Notification {
226 changeExpr :: RelationalExpr,
227 reportExpr :: RelationalExpr
228 }
229 deriving (Show, Eq, Binary, Generic, NFData)
231type TypeVarName = StringType
233-- | Metadata definition for type constructors such as @data Either a b@.
234data TypeConstructorDef = ADTypeConstructorDef TypeConstructorName [TypeVarName] |
235 PrimitiveTypeConstructorDef TypeConstructorName AtomType
236 deriving (Show, Generic, Binary, Eq, NFData)
238-- | Found in data constructors and type declarations: Left (Either Int Text) | Right Int
239data TypeConstructor = ADTypeConstructor TypeConstructorName [TypeConstructor] |
240 PrimitiveTypeConstructor TypeConstructorName AtomType |
241 TypeVariable TypeVarName
242 deriving (Show, Generic, Binary, Eq, NFData)
244type TypeConstructorMapping = [(TypeConstructorDef, DataConstructorDefs)]
246type TypeConstructorName = StringType
247type TypeConstructorArgName = StringType
248type DataConstructorName = StringType
249type AtomTypeName = StringType
251-- | Used to define a data constructor in a type constructor context such as @Left a | Right b@
252data DataConstructorDef = DataConstructorDef DataConstructorName [DataConstructorDefArg] deriving (Eq, Show, Binary, Generic, NFData)
254type DataConstructorDefs = [DataConstructorDef]
256data DataConstructorDefArg = DataConstructorDefTypeConstructorArg TypeConstructor |
257 DataConstructorDefTypeVarNameArg TypeVarName
258 deriving (Show, Generic, Binary, Eq, NFData)
260type InclusionDependencies = M.Map IncDepName InclusionDependency
261type RelationVariables = M.Map RelVarName Relation
263type SchemaName = StringType
265type Subschemas = M.Map SchemaName Schema
267-- | Every transaction has one concrete database context and any number of isomorphic subschemas.
268data Schemas = Schemas DatabaseContext Subschemas
270-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
271-- I spent some time thinking about whether the VirtualDatabaseContext/Schema and DatabaseContext data constructors should be the same constructor, but that would allow relation variables to be created in a "virtual" context which would appear to defeat the isomorphisms of the contexts. It should be possible to switch to an alternative schema to view the same equivalent information without information loss. However, allowing all contexts to reference another context while maintaining its own relation variables, new types, etc. could be interesting from a security perspective. For example, if a user creates a new relvar in a virtual context, then does it necessarily appear in all linked contexts? After deliberation, I think the relvar should appear in *all* linked contexts to retain the isomorphic properties, even when the isomorphism is for a subset of the context. This hints that the IsoMorphs should allow for "fall-through"; that is, when a relvar is not defined in the virtual context (for morphing), then the lookup should fall through to the underlying context.
272newtype Schema = Schema SchemaIsomorphs
273 deriving (Generic, Binary)
275data SchemaIsomorph = IsoRestrict RelVarName RestrictionPredicateExpr (RelVarName, RelVarName) |
276 IsoRename RelVarName RelVarName |
277 IsoUnion (RelVarName, RelVarName) RestrictionPredicateExpr RelVarName --maps two relvars to one relvar
278 -- IsoTypeConstructor in morphAttrExpr
279 deriving (Generic, Binary, Show)
281type SchemaIsomorphs = [SchemaIsomorph]
283data DatabaseContext = DatabaseContext {
284 inclusionDependencies :: InclusionDependencies,
285 relationVariables :: RelationVariables,
286 atomFunctions :: AtomFunctions,
287 dbcFunctions :: DatabaseContextFunctions,
288 notifications :: Notifications,
289 typeConstructorMapping :: TypeConstructorMapping
290 } deriving (NFData, Generic)
292type IncDepName = StringType
294-- | Inclusion dependencies represent every possible database constraint. Constraints enforce specific, arbitrarily-complex rules to which the database context's relation variables must adhere unconditionally.
295data InclusionDependency = InclusionDependency RelationalExpr RelationalExpr deriving (Show, Eq, Generic, NFData)
297instance Binary InclusionDependency
299type AttributeNameAtomExprMap = M.Map AttributeName AtomExpr
301--used for returning information about individual expressions
302type DatabaseContextExprName = StringType
304-- | Database context expressions modify the database context.
305data DatabaseContextExpr =
306 NoOperation |
307 Define RelVarName [AttributeExpr] |
308 Undefine RelVarName | --forget existence of relvar X
309 Assign RelVarName RelationalExpr |
310 Insert RelVarName RelationalExpr |
311 Delete RelVarName RestrictionPredicateExpr |
312 Update RelVarName AttributeNameAtomExprMap RestrictionPredicateExpr |
314 AddInclusionDependency IncDepName InclusionDependency |
315 RemoveInclusionDependency IncDepName |
317 AddNotification NotificationName RelationalExpr RelationalExpr |
318 RemoveNotification NotificationName |
320 AddTypeConstructor TypeConstructorDef [DataConstructorDef] |
321 RemoveTypeConstructor TypeConstructorName |
323 --adding an AtomFunction is not a pure operation (required loading GHC modules)
324 RemoveAtomFunction AtomFunctionName |
326 RemoveDatabaseContextFunction DatabaseContextFunctionName |
328 ExecuteDatabaseContextFunction DatabaseContextFunctionName [AtomExpr] |
330 MultipleExpr [DatabaseContextExpr]
331 deriving (Show, Eq, Binary, Generic)
333-- | Adding an atom function should be nominally a DatabaseExpr except for the fact that it cannot be performed purely. Thus, we create the DatabaseContextIOExpr.
334data DatabaseContextIOExpr = AddAtomFunction AtomFunctionName [TypeConstructor] AtomFunctionBodyScript |
335 AddDatabaseContextFunction DatabaseContextFunctionName [TypeConstructor] DatabaseContextFunctionBodyScript
336 deriving (Show, Eq, Generic, Binary)
339type RestrictionPredicateExpr = RestrictionPredicateExprBase ()
341-- | Restriction predicates are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.
342data RestrictionPredicateExprBase a =
343 TruePredicate |
344 AndPredicate (RestrictionPredicateExprBase a) (RestrictionPredicateExprBase a) |
345 OrPredicate (RestrictionPredicateExprBase a) (RestrictionPredicateExprBase a) |
346 NotPredicate (RestrictionPredicateExprBase a) |
347 RelationalExprPredicate (RelationalExprBase a) | --type must be same as true and false relations (no attributes)
348 AtomExprPredicate (AtomExprBase a) | --atom must evaluate to boolean
349 AttributeEqualityPredicate AttributeName (AtomExprBase a) -- relationalexpr must result in relation with single tuple
350 deriving (Show, Eq, Generic, NFData)
352instance Binary RestrictionPredicateExpr
354-- child + parent links
355-- | A transaction graph's head name references the leaves of the transaction graph and can be used during session creation to indicate at which point in the graph commits should persist.
356type HeadName = StringType
358type TransactionHeads = M.Map HeadName Transaction
360-- | The transaction graph is the global database's state which references every committed transaction.
361data TransactionGraph = TransactionGraph TransactionHeads (S.Set Transaction)
363transactionsForGraph :: TransactionGraph -> S.Set Transaction
364transactionsForGraph (TransactionGraph _ t) = t
366transactionHeadsForGraph :: TransactionGraph -> TransactionHeads
367transactionHeadsForGraph (TransactionGraph heads _) = heads
369-- | Every transaction has context-specific information attached to it.
370data TransactionInfo = TransactionInfo TransactionId (S.Set TransactionId) UTCTime | -- 1 parent + n children
371 MergeTransactionInfo TransactionId TransactionId (S.Set TransactionId) UTCTime -- 2 parents, n children
372 deriving(Show, Generic)
374instance Binary TransactionInfo
376-- | Every set of modifications made to the database are atomically committed to the transaction graph as a transaction.
377type TransactionId = UUID
379data Transaction = Transaction TransactionId TransactionInfo Schemas
381--instance Binary Transaction
383type DirtyFlag = Bool
385-- | The disconnected transaction represents an in-progress workspace used by sessions before changes are committed. This is similar to git's "index". After a transaction is committed, it is "connected" in the transaction graph and can no longer be modified.
386data DisconnectedTransaction = DisconnectedTransaction TransactionId Schemas DirtyFlag --parentID, context- the context here represents the singular concrete context from the schema
387--the dirty flag indicates that the database context has diverged from its parent's context
389transactionId :: Transaction -> TransactionId
390transactionId (Transaction tid _ _) = tid
392transactionInfo :: Transaction -> TransactionInfo
393transactionInfo (Transaction _ info _) = info
395instance Eq Transaction where
396 (Transaction uuidA _ _) == (Transaction uuidB _ _) = uuidA == uuidB
398instance Ord Transaction where
399 compare (Transaction uuidA _ _) (Transaction uuidB _ _) = compare uuidA uuidB
401type AtomExpr = AtomExprBase ()
403-- | An atom expression represents an action to take when extending a relation or when statically defining a relation or a new tuple.
404data AtomExprBase a = AttributeAtomExpr AttributeName |
405 NakedAtomExpr Atom |
406 FunctionAtomExpr AtomFunctionName [AtomExprBase a] a |
407 RelationAtomExpr (RelationalExprBase a) |
408 ConstructedAtomExpr DataConstructorName [AtomExprBase a] a
409 deriving (Eq,Show,Generic, NFData)
411instance Binary AtomExpr
413-- | Used in tuple creation when creating a relation.
414data ExtendTupleExprBase a = AttributeExtendTupleExpr AttributeName (AtomExprBase a)
415 deriving (Show, Eq, Generic, NFData)
417type ExtendTupleExpr = ExtendTupleExprBase ()
419instance Binary ExtendTupleExpr
421--enumerates the list of functions available to be run as part of tuple expressions
422type AtomFunctions = HS.HashSet AtomFunction
424type AtomFunctionName = StringType
426type AtomFunctionBodyScript = StringType
428type AtomFunctionBodyType = [Atom] -> Either AtomFunctionError Atom
430data AtomFunctionBody = AtomFunctionBody (Maybe AtomFunctionBodyScript) AtomFunctionBodyType
432instance NFData AtomFunctionBody where
433 rnf (AtomFunctionBody mScript _) = rnf mScript
435instance Show AtomFunctionBody where
436 show (AtomFunctionBody mScript _) = case mScript of
437 Just script -> show (unpack script)
438 Nothing -> "<compiled>"
440-- | An AtomFunction has a name, a type, and a function body to execute when called.
441data AtomFunction = AtomFunction {
442 atomFuncName :: AtomFunctionName,
443 atomFuncType :: [AtomType],
444 atomFuncBody :: AtomFunctionBody
445 } deriving (Generic, NFData)
447instance Hashable AtomFunction where
448 hashWithSalt salt func = salt `hashWithSalt` atomFuncName func
450instance Eq AtomFunction where
451 f1 == f2 = atomFuncName f1 == atomFuncName f2
453instance Show AtomFunction where
454 show aFunc = unpack (atomFuncName aFunc) ++ "::" ++ showArgTypes ++ "; " ++ body
455 where
456 body = show (atomFuncBody aFunc)
457 showArgTypes = L.intercalate "->" (map show (atomFuncType aFunc))
459-- | The 'AttributeNames' structure represents a set of attribute names or the same set of names but inverted in the context of a relational expression. For example, if a relational expression has attributes named "a", "b", and "c", the 'InvertedAttributeNames' of ("a","c") is ("b").
460data AttributeNames = AttributeNames (S.Set AttributeName) |
461 InvertedAttributeNames (S.Set AttributeName) |
462 UnionAttributeNames AttributeNames AttributeNames |
463 IntersectAttributeNames AttributeNames AttributeNames
464 deriving (Eq, Show, Generic, Binary, NFData)
466-- | The persistence strategy is a global database option which represents how to persist the database in the filesystem, if at all.
467data PersistenceStrategy = NoPersistence | -- ^ no filesystem persistence/memory-only database
468 MinimalPersistence FilePath | -- ^ fsync off, not crash-safe
469 CrashSafePersistence FilePath -- ^ full fsync to disk (flushes kernel and physical drive buffers to ensure that the transaction is on non-volatile storage)
470 deriving (Show, Read)
472type AttributeExpr = AttributeExprBase ()
474-- | Create attributes dynamically.
475data AttributeExprBase a = AttributeAndTypeNameExpr AttributeName TypeConstructor a |
476 NakedAttributeExpr Attribute
477 deriving (Eq, Show, Generic, Binary, NFData)
479-- | Dynamically create a tuple from attribute names and 'AtomExpr's.
480newtype TupleExprBase a = TupleExpr (M.Map AttributeName (AtomExprBase a))
481 deriving (Eq, Show, Generic, NFData)
483instance Binary TupleExpr
485type TupleExpr = TupleExprBase ()
487data MergeStrategy =
488 -- | After a union merge, the merge transaction is a result of union'ing relvars of the same name, introducing all uniquely-named relvars, union of constraints, union of atom functions, notifications, and types (unless the names and definitions collide, e.g. two types of the same name with different definitions)
489 UnionMergeStrategy |
490 -- | Similar to a union merge, but, on conflict, prefer the unmerged section (relvar, function, etc.) from the branch named as the argument.
491 UnionPreferMergeStrategy HeadName |
492 -- | Similar to the our/theirs merge strategy in git, the merge transaction's context is identical to that of the last transaction in the selected branch.
493 SelectedBranchMergeStrategy HeadName
494 deriving (Eq, Show, Binary, Generic, NFData)
496type DatabaseContextFunctionName = StringType
498type DatabaseContextFunctionBodyScript = StringType
500type DatabaseContextFunctionBodyType = [Atom] -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext
502data DatabaseContextFunctionBody = DatabaseContextFunctionBody (Maybe DatabaseContextFunctionBodyScript) DatabaseContextFunctionBodyType
504instance NFData DatabaseContextFunctionBody where
505 rnf (DatabaseContextFunctionBody mScript _) = rnf mScript
507data DatabaseContextFunction = DatabaseContextFunction {
508 dbcFuncName :: DatabaseContextFunctionName,
509 dbcFuncType :: [AtomType],
510 dbcFuncBody :: DatabaseContextFunctionBody
511 } deriving (Generic, NFData)
513type DatabaseContextFunctions = HS.HashSet DatabaseContextFunction
515instance Hashable DatabaseContextFunction where
516 hashWithSalt salt func = salt `hashWithSalt` dbcFuncName func
518instance Eq DatabaseContextFunction where
519 f1 == f2 = dbcFuncName f1 == dbcFuncName f2