1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
{-# OPTIONS_CYMAKE -Wno-incomplete-patterns #-}
module Database.ERD.Transformation ( transform )
where
import Database.ERD
import Database.ERD.Goodies
transform :: ERD -> ERD
transform (ERD name entities relationships) =
let (es,rs) = transformRel (map addKey entities,[]) relationships
in ERD name es rs
addKey :: Entity -> Entity
addKey (Entity en attrs) =
Entity en ((Attribute ("Key") (IntDom Nothing) PKey False)
: (map deleteKey attrs))
where
deleteKey :: Attribute -> Attribute
deleteKey a@(Attribute an d k null)
| k == PKey = Attribute an d Unique null
| otherwise = a
transformRel :: ([Entity], [Relationship]) -> [Relationship]
-> ([Entity], [Relationship])
transformRel (ens,rels) [] = (ens,rels)
transformRel (ens,rels) (r@(Relationship _ [(REnd e1 _ c1), (REnd e2 _ c2)]) : rs) = case c1 of
(Exactly i1) -> case c2 of
(Exactly _) -> error "2 minima"
(Between _ Infinite) -> transformRel (eRN i1 e1 e2 (ens, rels) r) rs
(Between i2 (Max i3)) -> transformRel (eRJ i1 i2 i3 e1 e2 (ens, rels) r) rs
(Between i1 Infinite) -> case c2 of
(Exactly i2) -> transformRel (eRN i2 e2 e1 (ens, rels) r) rs
(Between _ Infinite) -> transformRel (rNRN ens rels r) rs
(Between i2 (Max i3)) -> transformRel (rNRJ i1 i2 i3 e1 e2 ens rels r) rs
(Between i1 (Max i2)) -> case c2 of
(Exactly i3) -> transformRel (eRJ i3 i1 i2 e2 e1 (ens, rels) r) rs
(Between i3 Infinite) -> transformRel (rNRJ i3 i1 i2 e1 e2 ens rels r) rs
(Between i3 (Max i4)) -> transformRel (rJRJ i1 i2 i3 i4 e1 e2 ens rels r) rs
eRN :: Int -> String -> String -> ([Entity],[Relationship]) -> Relationship
-> ([Entity],[Relationship])
eRN i1 e1 e2 (ens,rels) r@(Relationship rname _)
| i1==1 = (addFKey e1 e2 rname False False ens ens, (r:rels))
| otherwise = let (r1,e,r2) = addExtraEntity r ens
in
(e:ens, r1:r2:rels)
eRJ :: Int -> Int -> Int -> String -> String -> ([Entity],[Relationship]) -> Relationship
-> ([Entity],[Relationship])
eRJ i1 _ i3 e1 e2 (ens, rels) r@(Relationship rname _)
| i1==1 = (addFKey e1 e2 rname False (i3==1) ens ens, (r:rels))
| otherwise = if i3==1
then (addFKey e2 e1 rname True False ens ens, (r:rels))
else let (r1,e,r2) = addExtraEntity r ens
in
(e:ens, r1:r2:rels)
rNRN :: [Entity] -> [Relationship] -> Relationship -> ([Entity],[Relationship])
rNRN ens rels r =
let (r1,e,r2) = addExtraEntity r ens
in
(e:ens, r1:r2:rels)
rNRJ :: a -> Int -> Int -> String -> String -> [Entity]
-> [Relationship] -> Relationship -> ([Entity], [Relationship])
rNRJ _ i2 i3 e1 e2 ens rels r@(Relationship rname _)
| i2==0 && i3==1 = (addFKey e1 e2 rname True False ens ens, (r:rels))
| otherwise = let (r1,e,r2) = addExtraEntity r ens
in
(e:ens, r1:r2:rels)
rJRJ :: Int -> Int -> a -> Int -> String -> String -> [Entity]
-> [Relationship] -> Relationship -> ([Entity], [Relationship])
rJRJ i1 i2 _ i4 e1 e2 ens rels r@(Relationship rname _)
| i1==0 && i2==1 = (addFKey e1 e2 rname True (i4==1) ens ens, (r:rels))
| otherwise = let (r1,e,r2) = addExtraEntity r ens
in
(e:ens, r1:r2:rels)
addFKey :: String -> String -> String -> Bool -> Bool -> [Entity] -> [Entity]
-> [Entity]
addFKey _ _ _ _ _ [] ens = ens
addFKey e1 e2 rname null unique (e@(Entity n (a:attrs)) : ens) ens'
| e2 == n =
let aname = attributeName (getKeyAttribute e1 ens')
in
(Entity n
(a:attrs++[Attribute (fKeyName e1 rname aname) (KeyDom e1)
(if unique then Unique else NoKey) null]))
: ens
| otherwise = e : addFKey e1 e2 rname null unique ens ens'
addFKey' :: String -> String -> Bool -> Entity -> [Entity] -> Entity
addFKey' ename rname null (Entity n attrs) es = ensureUniqueAttributeNames $
Entity n
((Attribute (fKeyName ename rname
(attributeName (getKeyAttribute ename es)))
(KeyDom ename) PKey null) : attrs)
getKeyAttribute :: String -> [Entity] -> Attribute
getKeyAttribute ename ((Entity n attrs) : ens)
| ename == n = getKey attrs
| otherwise = getKeyAttribute ename ens
getKey :: [Attribute] -> Attribute
getKey (a@(Attribute _ _ k _):attrs)
| PKey == k = a
| otherwise = getKey attrs
addExtraEntity :: Relationship -> [Entity]
-> (Relationship, Entity, Relationship)
(Relationship r [(REnd e1 r1 c1), (REnd e2 r2 c2)]) es =
(Relationship "" [(REnd e1 "" (Exactly 1)), (REnd r r2 c2)],
addFKey' e1 r False (addFKey' e2 r False (Entity r []) es) es,
Relationship "" [(REnd e2 "" (Exactly 1)), (REnd r r1 c1)])
fKeyName :: String -> String -> String -> String
fKeyName ename rname kname = combineIds [ename,rname,kname]
ensureUniqueAttributeNames :: Entity -> Entity
ensureUniqueAttributeNames (Entity ename attrs) =
Entity ename (uniqueNames [] attrs)
uniqueNames :: [Attribute] -> [Attribute] -> [Attribute]
uniqueNames oldattrs [] = reverse oldattrs
uniqueNames oldattrs (attr@(Attribute aname dom key nll) : attrs) =
if aname `elem` names
then uniqueNames (Attribute (makeUnique 1 aname) dom key nll : oldattrs) attrs
else uniqueNames (attr:oldattrs) attrs
where
names = map attributeName (oldattrs++attrs)
makeUnique i name = let newname = name++show i in
if newname `elem` names then makeUnique (i+1) name else newname
|