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)
19import Data.Vector.Binary()
21import Data.Time.Clock.POSIX
22import Data.Time.Calendar (Day,toGregorian,fromGregorian)
23import Data.Hashable.Time ()
25import Data.ByteString (ByteString)
29-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
30data Atom = IntegerAtom Integer |
35 DateTimeAtom UTCTime |
36 ByteStringAtom ByteString |
38 IntervalAtom Atom Atom OpenInterval OpenInterval |
39 RelationAtom Relation |
40 ConstructedAtom DataConstructorName AtomType [Atom]
41 deriving (Eq, Show, Binary, Typeable, NFData, Generic)
43type OpenInterval = Bool
45instance Hashable Atom where
46 hashWithSalt salt (ConstructedAtom dConsName _ atoms) = salt `hashWithSalt` atoms
47 `hashWithSalt` dConsName --AtomType is not hashable
48 hashWithSalt salt (IntAtom i) = salt `hashWithSalt` i
49 hashWithSalt salt (IntegerAtom i) = salt `hashWithSalt` i
50 hashWithSalt salt (DoubleAtom d) = salt `hashWithSalt` d
51 hashWithSalt salt (TextAtom t) = salt `hashWithSalt` t
52 hashWithSalt salt (DayAtom d) = salt `hashWithSalt` d
53 hashWithSalt salt (DateTimeAtom dt) = salt `hashWithSalt` dt
54 hashWithSalt salt (ByteStringAtom bs) = salt `hashWithSalt` bs
55 hashWithSalt salt (BoolAtom b) = salt `hashWithSalt` b
56 hashWithSalt salt (IntervalAtom a1 a2 bo be) = salt `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` bo `hashWithSalt` be
57 hashWithSalt salt (RelationAtom r) = salt `hashWithSalt` r
59instance Binary UTCTime where
60 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
61 get = posixSecondsToUTCTime . fromRational <$> (get :: Get Rational)
63instance Binary Day where
64 put day = put $ toGregorian day
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 |
79 IntervalAtomType AtomType |
80 RelationAtomType Attributes |
81 ConstructedAtomType TypeConstructorName TypeVarMap |
82 TypeVariableType TypeVarName
83 --wildcard used in Atom Functions and tuples for data constructors which don't provide all arguments to the type constructor
84 deriving (Eq, NFData, Generic, Binary, Show)
86type TypeVarMap = M.Map TypeVarName AtomType
88instance Hashable TypeVarMap where
89 hashWithSalt salt tvmap = hashWithSalt salt (M.keys tvmap)
91-- | Return True iff the atom type argument is relation-valued. If True, this indicates that the Atom contains a relation.
92isRelationAtomType :: AtomType -> Bool
93isRelationAtomType (RelationAtomType _) = True
94isRelationAtomType _ = False
96-- | The AttributeName is the name of an attribute in a relation.
97type AttributeName = StringType
99-- | A relation's type is composed of attribute names and types.
100data Attribute = Attribute AttributeName AtomType deriving (Eq, Show, Generic, NFData, Binary)
102instance Hashable Attribute where
103 hashWithSalt salt (Attribute attrName _) = hashWithSalt salt attrName
105-- | 'Attributes' represent the head of a relation.
106type Attributes = V.Vector Attribute
108-- | Equality function for a set of attributes.
109attributesEqual :: Attributes -> Attributes -> Bool
110attributesEqual attrs1 attrs2 = attrsAsSet attrs1 == attrsAsSet attrs2
112 attrsAsSet = HS.fromList . V.toList
114sortedAttributesIndices :: Attributes -> [(Int, Attribute)]
115sortedAttributesIndices attrs = L.sortBy (\(_, Attribute name1 _) (_,Attribute name2 _) -> compare name1 name2) $ V.toList (V.indexed attrs)
117-- | The relation's tuple set is the body of the relation.
118newtype RelationTupleSet = RelationTupleSet { asList :: [RelationTuple] } deriving (Hashable, Show, Generic, Binary)
120instance Read Relation where
121 readsPrec = error "relation read not supported"
123instance Eq RelationTupleSet where
124 set1 == set2 = hset set1 == hset set2
126 hset = HS.fromList . asList
128instance NFData RelationTupleSet where rnf = genericRnf
130--the same hash must be generated for equal tuples so that the hashset equality works
131instance Hashable RelationTuple where
132 --sanity check the tuple for attribute and tuple counts
133 --this bit me when tuples were being hashed before being verified
134 hashWithSalt salt (RelationTuple attrs tupVec) = if V.length attrs /= V.length tupVec then
135 error "invalid tuple: attributes and tuple count mismatch"
138 sortedAttrs `hashWithSalt`
139 V.toList sortedTupVec
141 sortedAttrsIndices = sortedAttributesIndices attrs
142 sortedAttrs = map snd sortedAttrsIndices
143 sortedTupVec = V.map (\(index, _) -> tupVec V.! index) $ V.fromList sortedAttrsIndices
145-- | A tuple is a set of attributes mapped to their 'Atom' values.
146data RelationTuple = RelationTuple Attributes (V.Vector Atom) deriving (Show, Generic)
148instance Binary RelationTuple
150instance Eq RelationTuple where
151 (==) tuple1@(RelationTuple attrs1 _) tuple2@(RelationTuple attrs2 _) = attributesEqual attrs1 attrs2 && atomsEqual
153 atomForAttribute attr (RelationTuple attrs tupVec) = case V.findIndex (== attr) attrs of
155 Just index -> tupVec V.!? index
156 atomsEqual = V.all (== True) $ V.map (\attr -> atomForAttribute attr tuple1 == atomForAttribute attr tuple2) attrs1
158instance NFData RelationTuple where rnf = genericRnf
160data Relation = Relation Attributes RelationTupleSet deriving (Show, Generic,Typeable)
162instance Eq Relation where
163 Relation attrs1 tupSet1 == Relation attrs2 tupSet2 = attributesEqual attrs1 attrs2 && tupSet1 == tupSet2
165instance NFData Relation where rnf = genericRnf
167instance Hashable Relation where
168 hashWithSalt salt (Relation attrs tupSet) = salt `hashWithSalt`
169 sortedAttrs `hashWithSalt`
172 sortedAttrs = map snd (sortedAttributesIndices attrs)
174instance Binary Relation
176-- | Used to represent the number of tuples in a relation.
177data RelationCardinality = Countable | Finite Int deriving (Eq, Show, Generic, Ord)
179-- | Relation variables are identified by their names.
180type RelVarName = StringType
182type RelationalExpr = RelationalExprBase ()
184-- | A relational expression represents query (read) operations on a database.
185data RelationalExprBase a =
186 --- | Create a relation from tuple expressions.
187 MakeRelationFromExprs (Maybe [AttributeExprBase a]) [TupleExprBase a] |
188 --- | Create and reference a relation from attributes and a tuple set.
189 MakeStaticRelation Attributes RelationTupleSet |
190 --- | Reference an existing relation in Haskell-space.
191 ExistingRelation Relation |
192 --MakeFunctionalRelation (creates a relation from a tuple-generating function, potentially infinite)
193 --in Tutorial D, relational variables pick up the type of the first relation assigned to them
194 --relational variables should also be able to be explicitly-typed like in Haskell
195 --- | Reference a relation variable by its name.
196 RelationVariable RelVarName a |
197 --- | Create a projection over attribute names. (Note that the 'AttributeNames' structure allows for the names to be inverted.)
198 Project (AttributeNamesBase a) (RelationalExprBase a) |
199 --- | Create a union of two relational expressions. The expressions should have identical attributes.
200 Union (RelationalExprBase a) (RelationalExprBase a) |
201 --- | 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.
202 Join (RelationalExprBase a) (RelationalExprBase a) |
203 --- | Rename an attribute (first argument) to another (second argument).
204 Rename AttributeName AttributeName (RelationalExprBase a) |
205 --- | Return a relation containing all tuples of the first argument which do not appear in the second argument (minus).
206 Difference (RelationalExprBase a) (RelationalExprBase a) |
207 --- | 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.>
208 Group (AttributeNamesBase a) AttributeName (RelationalExprBase a) |
209 --- | 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.
210 Ungroup AttributeName (RelationalExprBase a) |
211 --- | Filter the tuples of the relational expression to only retain the tuples which evaluate against the restriction predicate to true.
212 Restrict (RestrictionPredicateExprBase a) (RelationalExprBase a) |
213 --- | Returns the true relation iff
214 Equals (RelationalExprBase a) (RelationalExprBase a) |
215 NotEquals (RelationalExprBase a) (RelationalExprBase a) |
216 Extend (ExtendTupleExprBase a) (RelationalExprBase a)
217 --Summarize :: AtomExpr -> AttributeName -> RelationalExpr -> RelationalExpr -> RelationalExpr -- a special case of Extend
218 deriving (Show, Eq, Generic, NFData)
220instance Binary RelationalExpr
222type NotificationName = StringType
223type Notifications = M.Map NotificationName Notification
225-- | When the changeExpr returns a different result in the database context, then the reportExpr is triggered and sent asynchronously to all clients.
226data Notification = Notification {
227 changeExpr :: RelationalExpr,
228 reportOldExpr :: RelationalExpr, --run the expression in the pre-change context
229 reportNewExpr :: RelationalExpr --run the expression in the post-change context
231 deriving (Show, Eq, Binary, Generic, NFData)
233type TypeVarName = StringType
235-- | Metadata definition for type constructors such as @data Either a b@.
236data TypeConstructorDef = ADTypeConstructorDef TypeConstructorName [TypeVarName] |
237 PrimitiveTypeConstructorDef TypeConstructorName AtomType
238 deriving (Show, Generic, Binary, Eq, NFData)
240-- | Found in data constructors and type declarations: Left (Either Int Text) | Right Int
241data TypeConstructor = ADTypeConstructor TypeConstructorName [TypeConstructor] |
242 PrimitiveTypeConstructor TypeConstructorName AtomType |
243 TypeVariable TypeVarName
244 deriving (Show, Generic, Binary, Eq, NFData)
246type TypeConstructorMapping = [(TypeConstructorDef, DataConstructorDefs)]
248type TypeConstructorName = StringType
249type TypeConstructorArgName = StringType
250type DataConstructorName = StringType
251type AtomTypeName = StringType
253-- | Used to define a data constructor in a type constructor context such as @Left a | Right b@
254data DataConstructorDef = DataConstructorDef DataConstructorName [DataConstructorDefArg] deriving (Eq, Show, Binary, Generic, NFData)
256type DataConstructorDefs = [DataConstructorDef]
258data DataConstructorDefArg = DataConstructorDefTypeConstructorArg TypeConstructor |
259 DataConstructorDefTypeVarNameArg TypeVarName
260 deriving (Show, Generic, Binary, Eq, NFData)
262type InclusionDependencies = M.Map IncDepName InclusionDependency
263type RelationVariables = M.Map RelVarName Relation
265type SchemaName = StringType
267type Subschemas = M.Map SchemaName Schema
269-- | Every transaction has one concrete database context and any number of isomorphic subschemas.
270data Schemas = Schemas DatabaseContext Subschemas
272-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
273-- 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.
274newtype Schema = Schema SchemaIsomorphs
275 deriving (Generic, Binary)
277data SchemaIsomorph = IsoRestrict RelVarName RestrictionPredicateExpr (RelVarName, RelVarName) |
278 IsoRename RelVarName RelVarName |
279 IsoUnion (RelVarName, RelVarName) RestrictionPredicateExpr RelVarName --maps two relvars to one relvar
280 -- IsoTypeConstructor in morphAttrExpr
281 deriving (Generic, Binary, Show)
283type SchemaIsomorphs = [SchemaIsomorph]
285data DatabaseContext = DatabaseContext {
286 inclusionDependencies :: InclusionDependencies,
287 relationVariables :: RelationVariables,
288 atomFunctions :: AtomFunctions,
289 dbcFunctions :: DatabaseContextFunctions,
290 notifications :: Notifications,
291 typeConstructorMapping :: TypeConstructorMapping
292 } deriving (NFData, Generic)
294type IncDepName = StringType
296-- | Inclusion dependencies represent every possible database constraint. Constraints enforce specific, arbitrarily-complex rules to which the database context's relation variables must adhere unconditionally.
297data InclusionDependency = InclusionDependency RelationalExpr RelationalExpr deriving (Show, Eq, Generic, NFData)
299instance Binary InclusionDependency
301type AttributeNameAtomExprMap = M.Map AttributeName AtomExpr
303--used for returning information about individual expressions
304type DatabaseContextExprName = StringType
306-- | Database context expressions modify the database context.
307data DatabaseContextExpr =
309 Define RelVarName [AttributeExpr] |
310 Undefine RelVarName | --forget existence of relvar X
311 Assign RelVarName RelationalExpr |
312 Insert RelVarName RelationalExpr |
313 Delete RelVarName RestrictionPredicateExpr |
314 Update RelVarName AttributeNameAtomExprMap RestrictionPredicateExpr |
316 AddInclusionDependency IncDepName InclusionDependency |
317 RemoveInclusionDependency IncDepName |
319 AddNotification NotificationName RelationalExpr RelationalExpr RelationalExpr |
320 RemoveNotification NotificationName |
322 AddTypeConstructor TypeConstructorDef [DataConstructorDef] |
323 RemoveTypeConstructor TypeConstructorName |
325 --adding an AtomFunction is not a pure operation (required loading GHC modules)
326 RemoveAtomFunction AtomFunctionName |
328 RemoveDatabaseContextFunction DatabaseContextFunctionName |
330 ExecuteDatabaseContextFunction DatabaseContextFunctionName [AtomExpr] |
332 MultipleExpr [DatabaseContextExpr]
333 deriving (Show, Eq, Binary, Generic)
335type ObjModuleName = StringType
336type ObjFunctionName = StringType
338-- | Adding an atom function should be nominally a DatabaseExpr except for the fact that it cannot be performed purely. Thus, we create the DatabaseContextIOExpr.
339data DatabaseContextIOExpr = AddAtomFunction AtomFunctionName [TypeConstructor] AtomFunctionBodyScript |
340 LoadAtomFunctions ObjModuleName ObjFunctionName FilePath |
341 AddDatabaseContextFunction DatabaseContextFunctionName [TypeConstructor] DatabaseContextFunctionBodyScript |
342 LoadDatabaseContextFunctions ObjModuleName ObjFunctionName FilePath
343 deriving (Show, Eq, Generic, Binary)
345type RestrictionPredicateExpr = RestrictionPredicateExprBase ()
347-- | Restriction predicates are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.
348data RestrictionPredicateExprBase a =
350 AndPredicate (RestrictionPredicateExprBase a) (RestrictionPredicateExprBase a) |
351 OrPredicate (RestrictionPredicateExprBase a) (RestrictionPredicateExprBase a) |
352 NotPredicate (RestrictionPredicateExprBase a) |
353 RelationalExprPredicate (RelationalExprBase a) | --type must be same as true and false relations (no attributes)
354 AtomExprPredicate (AtomExprBase a) | --atom must evaluate to boolean
355 AttributeEqualityPredicate AttributeName (AtomExprBase a) -- relationalexpr must result in relation with single tuple
356 deriving (Show, Eq, Generic, NFData)
358instance Binary RestrictionPredicateExpr
360-- child + parent links
361-- | 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.
362type HeadName = StringType
364type TransactionHeads = M.Map HeadName Transaction
366-- | The transaction graph is the global database's state which references every committed transaction.
367data TransactionGraph = TransactionGraph TransactionHeads (S.Set Transaction)
369transactionsForGraph :: TransactionGraph -> S.Set Transaction
370transactionsForGraph (TransactionGraph _ t) = t
372transactionHeadsForGraph :: TransactionGraph -> TransactionHeads
373transactionHeadsForGraph (TransactionGraph heads _) = heads
375-- | Every transaction has context-specific information attached to it.
376data TransactionInfo = TransactionInfo TransactionId (S.Set TransactionId) UTCTime | -- 1 parent + n children
377 MergeTransactionInfo TransactionId TransactionId (S.Set TransactionId) UTCTime -- 2 parents, n children
378 deriving(Show, Generic)
380instance Binary TransactionInfo
382-- | Every set of modifications made to the database are atomically committed to the transaction graph as a transaction.
383type TransactionId = UUID
385data Transaction = Transaction TransactionId TransactionInfo Schemas
387--instance Binary Transaction
391-- | 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.
392data DisconnectedTransaction = DisconnectedTransaction TransactionId Schemas DirtyFlag --parentID, context- the context here represents the singular concrete context from the schema
393--the dirty flag indicates that the database context has diverged from its parent's context
395transactionId :: Transaction -> TransactionId
396transactionId (Transaction tid _ _) = tid
398transactionInfo :: Transaction -> TransactionInfo
399transactionInfo (Transaction _ info _) = info
401instance Eq Transaction where
402 (Transaction uuidA _ _) == (Transaction uuidB _ _) = uuidA == uuidB
404instance Ord Transaction where
405 compare (Transaction uuidA _ _) (Transaction uuidB _ _) = compare uuidA uuidB
407type AtomExpr = AtomExprBase ()
409-- | An atom expression represents an action to take when extending a relation or when statically defining a relation or a new tuple.
410data AtomExprBase a = AttributeAtomExpr AttributeName |
412 FunctionAtomExpr AtomFunctionName [AtomExprBase a] a |
413 RelationAtomExpr (RelationalExprBase a) |
414 ConstructedAtomExpr DataConstructorName [AtomExprBase a] a
415 deriving (Eq,Show,Generic, NFData)
417instance Binary AtomExpr
419-- | Used in tuple creation when creating a relation.
420data ExtendTupleExprBase a = AttributeExtendTupleExpr AttributeName (AtomExprBase a)
421 deriving (Show, Eq, Generic, NFData)
423type ExtendTupleExpr = ExtendTupleExprBase ()
425instance Binary ExtendTupleExpr
427--enumerates the list of functions available to be run as part of tuple expressions
428type AtomFunctions = HS.HashSet AtomFunction
430type AtomFunctionName = StringType
432type AtomFunctionBodyScript = StringType
434type AtomFunctionBodyType = [Atom] -> Either AtomFunctionError Atom
436data AtomFunctionBody = AtomFunctionBody (Maybe AtomFunctionBodyScript) AtomFunctionBodyType
438instance NFData AtomFunctionBody where
439 rnf (AtomFunctionBody mScript _) = rnf mScript
441instance Show AtomFunctionBody where
442 show (AtomFunctionBody mScript _) = case mScript of
443 Just script -> show (unpack script)
444 Nothing -> "<compiled>"
446-- | An AtomFunction has a name, a type, and a function body to execute when called.
447data AtomFunction = AtomFunction {
448 atomFuncName :: AtomFunctionName,
449 atomFuncType :: [AtomType],
450 atomFuncBody :: AtomFunctionBody
451 } deriving (Generic, NFData)
453instance Hashable AtomFunction where
454 hashWithSalt salt func = salt `hashWithSalt` atomFuncName func
456instance Eq AtomFunction where
457 f1 == f2 = atomFuncName f1 == atomFuncName f2
459instance Show AtomFunction where
460 show aFunc = unpack (atomFuncName aFunc) ++ "::" ++ showArgTypes ++ "; " ++ body
462 body = show (atomFuncBody aFunc)
463 showArgTypes = L.intercalate "->" (map show (atomFuncType aFunc))
465-- | 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").
466data AttributeNamesBase a = AttributeNames (S.Set AttributeName) |
467 InvertedAttributeNames (S.Set AttributeName) |
468 UnionAttributeNames (AttributeNamesBase a) (AttributeNamesBase a) |
469 IntersectAttributeNames (AttributeNamesBase a) (AttributeNamesBase a) |
470 RelationalExprAttributeNames (RelationalExprBase a) -- use attribute names from the relational expression's type
471 deriving (Eq, Show, Generic, NFData)
473type AttributeNames = AttributeNamesBase ()
474instance Binary AttributeNames
476-- | The persistence strategy is a global database option which represents how to persist the database in the filesystem, if at all.
477data PersistenceStrategy = NoPersistence | -- ^ no filesystem persistence/memory-only database
478 MinimalPersistence FilePath | -- ^ fsync off, not crash-safe
479 CrashSafePersistence FilePath -- ^ full fsync to disk (flushes kernel and physical drive buffers to ensure that the transaction is on non-volatile storage)
480 deriving (Show, Read)
482type AttributeExpr = AttributeExprBase ()
484-- | Create attributes dynamically.
485data AttributeExprBase a = AttributeAndTypeNameExpr AttributeName TypeConstructor a |
486 NakedAttributeExpr Attribute
487 deriving (Eq, Show, Generic, Binary, NFData)
489-- | Dynamically create a tuple from attribute names and 'AtomExpr's.
490newtype TupleExprBase a = TupleExpr (M.Map AttributeName (AtomExprBase a))
491 deriving (Eq, Show, Generic, NFData)
493instance Binary TupleExpr
495type TupleExpr = TupleExprBase ()
498 -- | 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)
500 -- | Similar to a union merge, but, on conflict, prefer the unmerged section (relvar, function, etc.) from the branch named as the argument.
501 UnionPreferMergeStrategy HeadName |
502 -- | 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.
503 SelectedBranchMergeStrategy HeadName
504 deriving (Eq, Show, Binary, Generic, NFData)
506type DatabaseContextFunctionName = StringType
508type DatabaseContextFunctionBodyScript = StringType
510type DatabaseContextFunctionBodyType = [Atom] -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext
512data DatabaseContextFunctionBody = DatabaseContextFunctionBody (Maybe DatabaseContextFunctionBodyScript) DatabaseContextFunctionBodyType
514instance NFData DatabaseContextFunctionBody where
515 rnf (DatabaseContextFunctionBody mScript _) = rnf mScript
517data DatabaseContextFunction = DatabaseContextFunction {
518 dbcFuncName :: DatabaseContextFunctionName,
519 dbcFuncType :: [AtomType],
520 dbcFuncBody :: DatabaseContextFunctionBody
521 } deriving (Generic, NFData)
523type DatabaseContextFunctions = HS.HashSet DatabaseContextFunction
525instance Hashable DatabaseContextFunction where
526 hashWithSalt salt func = salt `hashWithSalt` dbcFuncName func
528instance Eq DatabaseContextFunction where
529 f1 == f2 = dbcFuncName f1 == dbcFuncName f2
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list