-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtodo.urs
219 lines (200 loc) · 10.7 KB
/
todo.urs
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
(* Extensible todo lists: read assigned tasks out of database tables *)
(* Generators of todo entries *)
con t :: {Type} (* Dictionary of all key fields used across all sources of events *)
-> {Type} (* Mapping user-meaningful tags (for event kinds) to associated data *)
-> Type
(* Every user in a certain set must submit something associated with every row of a certain table. *)
functor WithDueDate(M : sig
con tag :: Name
con key :: {Type}
con due :: Name
con other :: {Type}
con user :: Name
con dother :: {Type}
con ukey :: Name
con uother :: {Type}
constraint key ~ other
constraint key ~ dother
constraint [due] ~ (key ++ other)
constraint [user] ~ (key ++ dother)
constraint [ukey] ~ uother
constraint [Assignee, Due, Done, Kind] ~ key
val fl : folder key
val inj : $(map sql_injectable_prim key)
table items : (key ++ [due = time] ++ other)
(* The set of items that must be done *)
table done : (key ++ [user = string] ++ dother)
(* Recording which users have done which items *)
table users : ([ukey = string] ++ uother)
(* Full set of users *)
val ucond : sql_exp [Users = [ukey = string] ++ uother] [] [] bool
(* Condition to narrow down to the ones who need to do these items *)
val title : string
val render : $key -> string (* username *) -> xbody
val allowAnyUser : bool
(* Only one user, not necessarily this one, needs to have done the task. *)
end) : sig
con private
con tag = M.tag
val todo : t M.key [tag = private]
end
(* Like above, but we need to follow a foreign-key link to find the due date. *)
functor WithForeignDueDate(M : sig
con tag :: Name
con key :: {Type}
con due :: Name
con other :: {Type}
con subkey :: {Type}
con pother :: {Type}
con user :: Name
con dother :: {Type}
con ukey :: Name
con uother :: {Type}
constraint key ~ other
constraint key ~ dother
constraint key ~ pother
constraint (key ++ other) ~ subkey
constraint [due] ~ (key ++ pother)
constraint [user] ~ (key ++ dother)
constraint [user] ~ other
constraint [ukey] ~ uother
constraint subkey ~ dother
constraint subkey ~ [user]
constraint [Assignee, Due, Done, Kind] ~ (key ++ subkey)
constraint [user] ~ (key ++ subkey)
val fl : folder key
val sfl : folder subkey
val inj : $(map sql_injectable_prim key)
val sinj : $(map sql_injectable_prim subkey)
table items : (key ++ [user = string] ++ subkey ++ other)
(* The set of items that must be done *)
table parent : (key ++ [due = time] ++ pother)
(* Look here for due dates. *)
table done : (key ++ subkey ++ [user = string] ++ dother)
(* Recording which users have done which items *)
table users : ([ukey = string] ++ uother)
(* Full set of users *)
val ucond : sql_exp [Users = [ukey = string] ++ uother] [] [] bool
(* Condition to narrow down to the ones who need to do these items *)
val title : string
val render : $(key ++ subkey) -> string (* username *) -> xbody
end) : sig
con private
con tag = M.tag
val todo : t (M.key ++ M.subkey) [tag = private]
end
(* Every row in a table, whose Boolean flag is not set, must be done by the associated users, indicated by other table rows. *)
functor WithCompletionFlag(M : sig
con tag :: Name
con key :: {Type}
con subkey :: {Type}
con done :: Name
con other :: {Type}
con user :: Name
con aother :: {Type}
constraint key ~ subkey
constraint (key ++ subkey) ~ other
constraint key ~ aother
constraint [done] ~ (key ++ subkey ++ other)
constraint [user] ~ (key ++ aother)
constraint [Assignee, Due, Done, Kind] ~ (key ++ subkey)
val fl : folder key
val sfl : folder subkey
val inj : $(map sql_injectable_prim key)
val sinj : $(map sql_injectable_prim subkey)
table items : (key ++ subkey ++ [done = bool] ++ other)
(* The set of items that must be done *)
table assignments : (key ++ [user = option string] ++ aother)
(* Recording who is responsible for which items *)
val title : string
val render : $(key ++ subkey) -> string (* username *) -> xbody
end) : sig
con private
con tag = M.tag
val todo : t (M.key ++ M.subkey) [tag = private]
end
(* Every user in a certain set should be aware of the contents of a certain table, interpreted as todos. *)
functor Happenings(M : sig
con tag :: Name
con key :: {Type}
con when :: Name
con other :: {Type}
con ukey :: Name
con uother :: {Type}
constraint key ~ other
constraint [when] ~ (key ++ other)
constraint [ukey] ~ uother
constraint [Assignee, Due, Done, Kind] ~ key
val fl : folder key
val inj : $(map sql_injectable_prim key)
table items : (key ++ [when = time] ++ other)
(* The set of items that must be done *)
table users : ([ukey = string] ++ uother)
(* Full set of users *)
val ucond : sql_exp [Users = [ukey = string] ++ uother] [] [] bool
(* Condition to narrow down to the ones who need to do these items *)
val title : string
val render : $key -> xbody
end) : sig
con private
con tag = M.tag
val todo : t M.key [tag = private]
end
(* For every combination of rows from two tables, a row must exist in another table.
* If it doesn't, then every user in a given set has a todo!
* The canonical example is grading assignments. *)
functor Grading(M : sig
con tag :: Name
con akey :: {Type}
con due :: Name
con aother :: {Type}
con ukey :: Name
con uother :: {Type}
con guser :: Name
con gother :: {Type}
constraint akey ~ aother
constraint [due] ~ (akey ++ aother)
constraint [ukey] ~ uother
constraint akey ~ gother
constraint [guser] ~ (akey ++ gother)
constraint [guser] ~ akey
constraint [Assignee, Due, Done, Kind] ~ ([guser = string] ++ akey)
val fl : folder akey
val inj : $(map sql_injectable_prim akey)
table assignments : (akey ++ [due = time] ++ aother)
(* The set of assignments to be graded *)
val acond : sql_exp [Assignments = akey ++ [due = time] ++ aother] [] [] bool
(* Condition to narrow down to the ones ready for grading *)
table users : ([ukey = string] ++ uother)
(* Full set of users *)
val ucond : sql_exp [Users = [ukey = string] ++ uother] [] [] bool
(* Condition to narrow down to the ones who get graded *)
table grades : ([guser = string] ++ akey ++ gother)
(* Recorded grades; if missing, generate a todo. *)
val gcond : sql_exp [Graders = [ukey = string] ++ uother] [] [] bool
(* Which users are responsible for grading? *)
val title : string
val render : $([guser = string] ++ akey) -> string (* username *) -> xbody
end) : sig
con private
con tag = M.tag
con guser = M.guser
val todo : t ([guser = string] ++ M.akey) [tag = private]
end
val compose : keys1 ::: {Type} -> keys2 ::: {Type}
-> tags1 ::: {Type} -> tags2 ::: {Type}
-> [keys1 ~ keys2] => [tags1 ~ tags2]
=> folder keys1 -> folder keys2
-> $(map sql_injectable_prim keys1)
-> $(map sql_injectable_prim keys2)
-> t keys1 tags1 -> t keys2 tags2 -> t (keys1 ++ keys2) (tags1 ++ tags2)
functor Make(M : sig
con keys :: {Type}
con tags :: {Type}
constraint [Assignee, Due, Done, Kind] ~ keys
val t : t keys tags
val fl : folder tags
end) : sig
structure AllUsers : Ui.S0
structure OneUser : Ui.S where type input = string
end