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
|
module KeyDatabase(existsDBKey,allDBKeys,allDBInfos,allDBKeyInfos,
getDBInfo,getDBInfos,
deleteDBEntry,deleteDBEntries,
updateDBEntry,newDBEntry,newDBKeyEntry,
cleanDB,
index,sortByIndex,groupByIndex,
module Database) where
import Database
import Integer(maxlist)
import Sort
import List
import Maybe(sequenceMaybe)
type Key = Int
type KeyPred a = Key -> a -> Dynamic
existsDBKey :: KeyPred _ -> Key -> Query Bool
existsDBKey db key = seq db $ seq key $
transformQ (/=Nothing) (queryOne (db key))
allDBKeys :: KeyPred _ -> Query [Key]
allDBKeys db = seq db $ queryAll (\key -> db key unknown)
allDBInfos :: KeyPred a -> Query [a]
allDBInfos db = seq db $ queryAll (db unknown)
allDBKeyInfos :: KeyPred a -> Query [(Key,a)]
allDBKeyInfos db = seq db $ queryAll (\ (key,info) -> db key info)
getDBInfo :: KeyPred a -> Key -> Query (Maybe a)
getDBInfo db key = seq db $ seq key $ queryOne (\info -> db key info)
index :: a -> [a] -> Int
index x xs = idx 0 xs
where
idx n (y:ys) = if x==y then n else idx (n+1) ys
sortByIndex :: [(Int,b)] -> [b]
sortByIndex = map snd . mergeSortBy (\x y -> fst x < fst y)
groupByIndex :: [(Int,b)] -> [[b]]
groupByIndex = addEmptyIdxs 0 . groupBy (\x y -> fst x == fst y)
. mergeSortBy (\x y -> fst x < fst y)
where
addEmptyIdxs _ [] = []
addEmptyIdxs n (((m,x):xs):ys) =
if n==m then (x:map snd xs) : addEmptyIdxs (n+1) ys
else []:addEmptyIdxs (n+1) (((m,x):xs):ys)
getDBInfos :: KeyPred a -> [Key] -> Query (Maybe [a])
getDBInfos db keys = seq db $ seq (normalForm keys) $
transformQ sortByKeys
(queryAll (\ (key,info) -> db key info |> key `elem` keys))
where
sortByKeys keyinfos = sequenceMaybe (map (\k -> lookup k keyinfos) keys)
deleteDBEntry :: KeyPred _ -> Key -> Transaction ()
deleteDBEntry db key = seq db $ seq key $
getDB (queryAll (\infos -> db key infos)) |>>= \entries ->
mapT_ (\infos -> deleteDB (db key infos)) entries
deleteDBEntries :: KeyPred _ -> [Key] -> Transaction ()
deleteDBEntries db keys = seq db $ seq keys $ mapT_ (deleteDBEntry db) keys
updateDBEntry :: KeyPred a -> Key -> a -> Transaction ()
updateDBEntry db key info =
getDB (existsDBKey db key) |>>= \b ->
if b then deleteDBEntry db key |>> addDB (db key info)
else errorT (TError KeyNotExistsError
("updateDBEntry: key " ++ show key++" does not exist"))
newDBKey :: KeyPred _ -> Query Key
newDBKey db =
transformQ (\ids -> if null ids then 1 else maxlist ids + 1)
(queryAll (\i -> db i unknown))
newDBEntry :: KeyPred a -> a -> Transaction Key
newDBEntry db info =
getDB (newDBKey db) |>>= \i -> addDB (db i info) |>> returnT i
newDBKeyEntry :: KeyPred a -> Key -> a -> Transaction ()
newDBKeyEntry db key info =
getDB (existsDBKey db key) |>>= \b ->
if b then errorT (TError DuplicateKeyError
("database already contains entry with key: "++show key))
else addDB (db key info) |>> doneT
cleanDB :: KeyPred _ -> Transaction ()
cleanDB db = getDB (queryAll (\i -> db i unknown)) |>>= deleteDBEntries db
|