on cfa7253 help sign in
67 lines 3.5 kB history raw
1module ProjectM36.Key where
2import ProjectM36.Base
3import ProjectM36.Relation
4import qualified Data.Set as S
5--import Data.Monoid
7{-
8keys can be implemented using inclusion dependencies as well: the count of the projection of the keys' attributes must be equal to the count of the tuples- p. 120 Database in Depth
10example:
11:showexpr ((relation{tuple{}}:{a:=S}):{b:=count(@a)}){b}
12┌─┐
13│b│
14├─┤
15│5│
16└─┘
17((relation{tuple{}}:{a:=S{S#}}):{b:=count(@a)}){b}
18┌─┐
19│b│
20├─┤
21│5│
22└─┘
23-}
25-- | Create a uniqueness constraint for the attribute names and relational expression. Note that constraint can span multiple relation variables.
26inclusionDependencyForKey :: AttributeNames -> RelationalExpr -> InclusionDependency
27inclusionDependencyForKey attrNames relExpr = --InclusionDependency name (exprCount relExpr) (exprCount (projectedOnKeys relExpr))
28 InclusionDependency equalityExpr (ExistingRelation relationFalse)
29 where
30 projectedOnKeys = Project attrNames
31 exprAsSubRelation expr = Extend (AttributeExtendTupleExpr "a" (RelationAtomExpr expr)) (ExistingRelation relationTrue)
32 exprCount expr = projectionForCount (Extend (AttributeExtendTupleExpr "b" (FunctionAtomExpr "count" [AttributeAtomExpr "a"] () )) (exprAsSubRelation expr))
33 projectionForCount = Project (AttributeNames $ S.fromList ["b"])
34 equalityExpr = NotEquals (exprCount relExpr) (exprCount (projectedOnKeys relExpr))
36-- | Create a 'DatabaseContextExpr' which can be used to add a uniqueness constraint to attributes on one relation variable.
37databaseContextExprForUniqueKey :: RelVarName -> [AttributeName] -> DatabaseContextExpr
38databaseContextExprForUniqueKey rvName attrNames = AddInclusionDependency (rvName <> "_key") $ inclusionDependencyForKey (AttributeNames (S.fromList attrNames)) (RelationVariable rvName ())
40-- | Create a foreign key constraint from the first relation variable and attributes to the second.
41databaseContextExprForForeignKey :: IncDepName -> (RelVarName, [AttributeName]) -> (RelVarName, [AttributeName]) -> DatabaseContextExpr
42databaseContextExprForForeignKey fkName infoA infoB =
43 AddInclusionDependency fkName (inclusionDependencyForForeignKey infoA infoB)
45inclusionDependencyForForeignKey :: (RelVarName, [AttributeName]) -> (RelVarName, [AttributeName]) -> InclusionDependency
46inclusionDependencyForForeignKey (rvA, attrsA) (rvB, attrsB) =
47 InclusionDependency (
48 renameIfNecessary attrsB attrsA (Project (attrsL attrsA)
49 (RelationVariable rvA ()))) (
50 Project (attrsL attrsB) (RelationVariable rvB ()))
51 where
52 attrsL = AttributeNames . S.fromList
53 renameIfNecessary attrsExpected attrsExisting expr = foldr folder expr (zip attrsExpected attrsExisting)
54 folder (attrExpected, attrExisting) expr = if attrExpected == attrExisting then
55 expr
56 else
57 Rename attrExisting attrExpected expr
59-- if the constraint is a foreign key constraint, then return the relations and attributes involved - this only detects foreign keys created with `databaseContextExprForForeignKey`
60isForeignKeyFor :: InclusionDependency -> (RelVarName, [AttributeName]) -> (RelVarName, [AttributeName]) -> Bool
61isForeignKeyFor incDep infoA infoB = incDep == checkIncDep
62 where
63 checkIncDep = inclusionDependencyForForeignKey infoA infoB