comparison demo/more/dbgrid.ur @ 944:da3ec6014d2f

Filters implementation type-checking
author Adam Chlipala <adamc@hcoop.net>
date Tue, 15 Sep 2009 15:48:53 -0400
parents 37dd42935dad
children 2412cb10c97c
comparison
equal deleted inserted replaced
943:e2194a6793ae 944:da3ec6014d2f
1 con rawMeta = fn t :: Type => 1 con rawMeta = fn t :: Type =>
2 {New : transaction t, 2 {New : transaction t,
3 Inj : sql_injectable t} 3 Inj : sql_injectable t}
4 4
5 con colMeta' = fn (row :: {Type}) (t :: Type) => 5 con colMeta' = fn (row :: {Type}) (input :: Type) (filter :: Type) =>
6 {Header : string, 6 {Header : string,
7 Project : $row -> transaction t, 7 Project : $row -> transaction input,
8 Update : $row -> t -> transaction ($row), 8 Update : $row -> input -> transaction ($row),
9 Display : t -> xbody, 9 Display : input -> xbody,
10 Edit : t -> xbody, 10 Edit : input -> xbody,
11 Validate : t -> signal bool} 11 Validate : input -> signal bool,
12 12 CreateFilter : transaction filter,
13 con colMeta = fn (row :: {Type}) (global_t :: (Type * Type)) => 13 DisplayFilter : filter -> xbody,
14 {Initialize : transaction global_t.1, 14 Filter : filter -> $row -> signal bool}
15 Handlers : global_t.1 -> colMeta' row global_t.2} 15
16 con colMeta = fn (row :: {Type}) (global_input_filter :: (Type * Type * Type)) =>
17 {Initialize : transaction global_input_filter.1,
18 Handlers : global_input_filter.1 -> colMeta' row global_input_filter.2 global_input_filter.3}
16 19
17 con aggregateMeta = fn (row :: {Type}) (acc :: Type) => 20 con aggregateMeta = fn (row :: {Type}) (acc :: Type) =>
18 {Initial : acc, 21 {Initial : acc,
19 Step : $row -> acc -> acc, 22 Step : $row -> acc -> acc,
20 Display : acc -> xbody} 23 Display : acc -> xbody}
21 24
22 structure Direct = struct 25 structure Direct = struct
23 con metaBase = fn actual_input :: (Type * Type) => 26 con metaBase = fn actual_input_filter :: (Type * Type * Type) =>
24 {Display : actual_input.2 -> xbody, 27 {Display : actual_input_filter.2 -> xbody,
25 Edit : actual_input.2 -> xbody, 28 Edit : actual_input_filter.2 -> xbody,
26 Initialize : actual_input.1 -> transaction actual_input.2, 29 Initialize : actual_input_filter.1 -> transaction actual_input_filter.2,
27 Parse : actual_input.2 -> signal (option actual_input.1)} 30 Parse : actual_input_filter.2 -> signal (option actual_input_filter.1),
28 31 CreateFilter : transaction actual_input_filter.3,
29 datatype metaBoth actual input = 32 DisplayFilter : actual_input_filter.3 -> xbody,
30 NonNull of metaBase (actual, input) * metaBase (option actual, input) 33 Filter : actual_input_filter.3 -> actual_input_filter.1 -> signal bool}
31 | Nullable of metaBase (actual, input) 34
32 35 datatype metaBoth actual input filter =
33 con meta = fn global_actual_input :: (Type * Type * Type) => 36 NonNull of metaBase (actual, input, filter) * metaBase (option actual, input, filter)
34 {Initialize : transaction global_actual_input.1, 37 | Nullable of metaBase (actual, input, filter)
35 Handlers : global_actual_input.1 38
36 -> metaBoth global_actual_input.2 global_actual_input.3} 39 con meta = fn global_actual_input_filter :: (Type * Type * Type * Type) =>
37 40 {Initialize : transaction global_actual_input_filter.1,
38 con editableState (ts :: (Type * Type * Type)) = (ts.1, ts.3) 41 Handlers : global_actual_input_filter.1
42 -> metaBoth global_actual_input_filter.2 global_actual_input_filter.3
43 global_actual_input_filter.4}
44
45 con editableState (ts :: (Type * Type * Type * Type)) = (ts.1, ts.3, ts.4)
39 fun editable [ts] [rest] [nm :: Name] [[nm] ~ rest] name (m : meta ts) : colMeta ([nm = ts.2] ++ rest) 46 fun editable [ts] [rest] [nm :: Name] [[nm] ~ rest] name (m : meta ts) : colMeta ([nm = ts.2] ++ rest)
40 (editableState ts) = 47 (editableState ts) =
41 let 48 let
42 fun doMr mr = {Header = name, 49 fun doMr mr = {Header = name,
43 Project = fn r => mr.Initialize r.nm, 50 Project = fn r => mr.Initialize r.nm,
46 return (case vo of 53 return (case vo of
47 None => r 54 None => r
48 | Some v => r -- nm ++ {nm = v}), 55 | Some v => r -- nm ++ {nm = v}),
49 Display = mr.Display, 56 Display = mr.Display,
50 Edit = mr.Edit, 57 Edit = mr.Edit,
51 Validate = fn s => vo <- mr.Parse s; return (Option.isSome vo)} 58 Validate = fn s => vo <- mr.Parse s; return (Option.isSome vo),
59 CreateFilter = mr.CreateFilter,
60 DisplayFilter = mr.DisplayFilter,
61 Filter = fn i r => mr.Filter i r.nm}
52 in 62 in
53 {Initialize = m.Initialize, 63 {Initialize = m.Initialize,
54 Handlers = fn data => case m.Handlers data of 64 Handlers = fn data => case m.Handlers data of
55 NonNull (mr, _) => doMr mr 65 NonNull (mr, _) => doMr mr
56 | Nullable mr => doMr mr} 66 | Nullable mr => doMr mr}
57 end 67 end
58 68
59 con readOnlyState (ts :: (Type * Type * Type)) = (ts.1, ts.3) 69 con readOnlyState (ts :: (Type * Type * Type * Type)) = (ts.1, ts.3, ts.4)
60 fun readOnly [ts] [rest] [nm :: Name] [[nm] ~ rest] name (m : meta ts) : colMeta ([nm = ts.2] ++ rest) 70 fun readOnly [ts] [rest] [nm :: Name] [[nm] ~ rest] name (m : meta ts) : colMeta ([nm = ts.2] ++ rest)
61 (readOnlyState ts) = 71 (readOnlyState ts) =
62 let 72 let
63 fun doMr mr = {Header = name, 73 fun doMr mr = {Header = name,
64 Project = fn r => mr.Initialize r.nm, 74 Project = fn r => mr.Initialize r.nm,
65 Update = fn r _ => return r, 75 Update = fn r _ => return r,
66 Display = mr.Display, 76 Display = mr.Display,
67 Edit = mr.Display, 77 Edit = mr.Display,
68 Validate = fn _ => return True} 78 Validate = fn _ => return True,
79 CreateFilter = mr.CreateFilter,
80 DisplayFilter = mr.DisplayFilter,
81 Filter = fn i r => mr.Filter i r.nm}
69 in 82 in
70 {Initialize = m.Initialize, 83 {Initialize = m.Initialize,
71 Handlers = fn data => case m.Handlers data of 84 Handlers = fn data => case m.Handlers data of
72 NonNull (mr, _) => doMr mr 85 NonNull (mr, _) => doMr mr
73 | Nullable mr => doMr mr} 86 | Nullable mr => doMr mr}
74 end 87 end
75 88
76 con metaBasic = fn actual_input :: (Type * Type) => 89 con metaBasic = fn actual_input_filter :: (Type * Type * Type) =>
77 {Display : actual_input.2 -> xbody, 90 {Display : actual_input_filter.2 -> xbody,
78 Edit : source actual_input.2 -> xbody, 91 Edit : source actual_input_filter.2 -> xbody,
79 Initialize : actual_input.1 -> actual_input.2, 92 Initialize : actual_input_filter.1 -> actual_input_filter.2,
80 InitializeNull : actual_input.2, 93 InitializeNull : actual_input_filter.2,
81 IsNull : actual_input.2 -> bool, 94 IsNull : actual_input_filter.2 -> bool,
82 Parse : actual_input.2 -> option actual_input.1} 95 Parse : actual_input_filter.2 -> option actual_input_filter.1,
96 CreateFilter : actual_input_filter.3,
97 DisplayFilter : source actual_input_filter.3 -> xbody,
98 Filter : actual_input_filter.3 -> actual_input_filter.1 -> bool,
99 FilterIsNull : actual_input_filter.3 -> bool}
83 100
84 con basicState = source 101 con basicState = source
85 fun basic [ts ::: (Type * Type)] (m : metaBasic ts) : meta (unit, ts.1, basicState ts.2) = 102 con basicFilter = source
103 fun basic [ts ::: (Type * Type * Type)] (m : metaBasic ts) : meta (unit, ts.1, basicState ts.2, basicFilter ts.3) =
86 {Initialize = return (), 104 {Initialize = return (),
87 Handlers = fn () => NonNull ( 105 Handlers = fn () => NonNull (
88 {Display = fn s => <xml><dyn signal={v <- signal s; return (m.Display v)}/></xml>, 106 {Display = fn s => <xml><dyn signal={v <- signal s; return (m.Display v)}/></xml>,
89 Edit = m.Edit, 107 Edit = m.Edit,
90 Initialize = fn v => source (m.Initialize v), 108 Initialize = fn v => source (m.Initialize v),
91 Parse = fn s => v <- signal s; return (m.Parse v)}, 109 Parse = fn s => v <- signal s; return (m.Parse v),
110 CreateFilter = source m.CreateFilter,
111 DisplayFilter = m.DisplayFilter,
112 Filter = fn f v => f <- signal f; return (m.Filter f v)},
92 {Display = fn s => <xml><dyn signal={v <- signal s; return (m.Display v)}/></xml>, 113 {Display = fn s => <xml><dyn signal={v <- signal s; return (m.Display v)}/></xml>,
93 Edit = m.Edit, 114 Edit = m.Edit,
94 Initialize = fn v => source (case v of 115 Initialize = fn v => source (case v of
95 None => m.InitializeNull 116 None => m.InitializeNull
96 | Some v => m.Initialize v), 117 | Some v => m.Initialize v),
98 return (if m.IsNull v then 119 return (if m.IsNull v then
99 Some None 120 Some None
100 else 121 else
101 case m.Parse v of 122 case m.Parse v of
102 None => None 123 None => None
103 | Some v' => Some (Some v'))})} 124 | Some v' => Some (Some v')),
104 125 CreateFilter = source m.CreateFilter,
105 fun nullable [global] [actual] [input] (m : meta (global, actual, input)) = 126 DisplayFilter = m.DisplayFilter,
127 Filter = fn f v => f <- signal f;
128 return (if m.FilterIsNull f then
129 Option.isNone v
130 else
131 case v of
132 None => False
133 | Some v => m.Filter f v) : signal bool})}
134
135 fun nullable [global] [actual] [input] [filter] (m : meta (global, actual, input, filter)) =
106 {Initialize = m.Initialize, 136 {Initialize = m.Initialize,
107 Handlers = fn d => case m.Handlers d of 137 Handlers = fn d => case m.Handlers d of
108 Nullable _ => error <xml>Don't stack calls to Direct.nullable!</xml> 138 Nullable _ => error <xml>Don't stack calls to Direct.nullable!</xml>
109 | NonNull (_, ho) => Nullable ho} 139 | NonNull (_, ho) => Nullable ho}
110 140
111 type intGlobal = unit 141 type intGlobal = unit
112 type intInput = basicState string 142 type intInput = basicState string
113 val int : meta (intGlobal, int, intInput) = 143 type intFilter = basicFilter string
144 val int : meta (intGlobal, int, intInput, intFilter) =
114 basic {Display = fn s => <xml>{[s]}</xml>, 145 basic {Display = fn s => <xml>{[s]}</xml>,
115 Edit = fn s => <xml><ctextbox source={s}/></xml>, 146 Edit = fn s => <xml><ctextbox source={s}/></xml>,
116 Initialize = fn n => show n, 147 Initialize = fn n => show n,
117 InitializeNull = "", 148 InitializeNull = "",
118 IsNull = eq "", 149 IsNull = eq "",
119 Parse = fn v => read v} 150 Parse = fn v => read v,
151 CreateFilter = "",
152 DisplayFilter = fn s => <xml><ctextbox source={s}/></xml> : xbody,
153 Filter = fn s n =>
154 case read s of
155 None => True
156 | Some n' => n' = n,
157 FilterIsNull = eq ""}
120 158
121 type stringGlobal = unit 159 type stringGlobal = unit
122 type stringInput = basicState string 160 type stringInput = basicState string
123 val string : meta (stringGlobal, string, stringInput) = 161 type stringFilter = basicFilter string
162 val string : meta (stringGlobal, string, stringInput, stringFilter) =
124 basic {Display = fn s => <xml>{[s]}</xml>, 163 basic {Display = fn s => <xml>{[s]}</xml>,
125 Edit = fn s => <xml><ctextbox source={s}/></xml>, 164 Edit = fn s => <xml><ctextbox source={s}/></xml>,
126 Initialize = fn s => s, 165 Initialize = fn s => s,
127 InitializeNull = "", 166 InitializeNull = "",
128 IsNull = eq "", 167 IsNull = eq "",
129 Parse = fn s => Some s} 168 Parse = fn s => Some s,
169 CreateFilter = "",
170 DisplayFilter = fn s => <xml><ctextbox source={s}/></xml> : xbody,
171 Filter = fn s n =>
172 case read s of
173 None => True
174 | Some n' => n' = n,
175 FilterIsNull = eq ""}
130 176
131 type boolGlobal = unit 177 type boolGlobal = unit
132 type boolInput = basicState bool 178 type boolInput = basicState bool
133 val bool : meta (boolGlobal, bool, boolInput) = 179 type boolFilter = basicFilter string
180 val bool : meta (boolGlobal, bool, boolInput, boolFilter) =
134 basic {Display = fn b => <xml>{[b]}</xml>, 181 basic {Display = fn b => <xml>{[b]}</xml>,
135 Edit = fn s => <xml><ccheckbox source={s}/></xml>, 182 Edit = fn s => <xml><ccheckbox source={s}/></xml>,
136 Initialize = fn b => b, 183 Initialize = fn b => b,
137 InitializeNull = False, 184 InitializeNull = False,
138 IsNull = fn _ => False, 185 IsNull = fn _ => False,
139 Parse = fn b => Some b} 186 Parse = fn b => Some b,
187 CreateFilter = "",
188 DisplayFilter = fn s => <xml><cselect source={s}>
189 <coption/>
190 <coption value="0">False</coption>
191 <coption value="1">True</coption>
192 </cselect></xml> : xbody,
193 Filter = fn s b =>
194 case s of
195 "0" => b = False
196 | "1" => b = True
197 | _ => True,
198 FilterIsNull = eq ""}
140 199
141 functor Foreign (M : sig 200 functor Foreign (M : sig
142 con row :: {Type} 201 con row :: {Type}
143 con t :: Type 202 con t :: Type
144 val show_t : show t 203 val show_t : show t
150 table tab : ([nm = t] ++ row) 209 table tab : ([nm = t] ++ row)
151 val render : $([nm = t] ++ row) -> string 210 val render : $([nm = t] ++ row) -> string
152 end) = struct 211 end) = struct
153 open M 212 open M
154 213
155 con global = list (t * string) 214 type global = list (t * string)
156 con input = source string * option (t * $row) 215 type input = source string * option (t * $row)
216 type filter = source string
157 217
158 val getChoices = List.mapQuery (SELECT * FROM tab AS T) 218 val getChoices = List.mapQuery (SELECT * FROM tab AS T)
159 (fn r => (r.T.nm, render r.T)) 219 (fn r => (r.T.nm, render r.T))
160 220
161 fun getChoice k = 221 fun getChoice k =
162 r <- oneRow (SELECT T.{{row}} FROM tab AS T WHERE T.{nm} = {[k]}); 222 r <- oneRow (SELECT T.{{row}} FROM tab AS T WHERE T.{nm} = {[k]});
163 return r.T 223 return r.T
164 224
165 val meta : meta (global, M.t, input) = 225 val meta : meta (global, M.t, input, filter) =
166 {Initialize = getChoices, 226 {Initialize = getChoices,
167 Handlers = fn choices => 227 Handlers = fn choices =>
168 NonNull ( 228 NonNull (
169 {Display = fn (_, kr) => case kr of 229 {Display = fn (_, kr) => case kr of
170 None => error <xml>Unexpected Foreign null</xml> 230 None => error <xml>Unexpected Foreign null</xml>
180 choices} 240 choices}
181 </cselect></xml>, 241 </cselect></xml>,
182 Initialize = fn k => s <- source (show k); 242 Initialize = fn k => s <- source (show k);
183 r <- rpc (getChoice k); 243 r <- rpc (getChoice k);
184 return (s, Some (k, r)), 244 return (s, Some (k, r)),
185 Parse = fn (s, _) => k <- signal s; return (read k : option t)}, 245 Parse = fn (s, _) => k <- signal s; return (read k : option t),
246 CreateFilter = source "",
247 DisplayFilter = fn s =>
248 <xml><cselect source={s}>
249 <coption/>
250 {List.mapX (fn (k, rend) =>
251 <xml><coption value={show k}>{[rend]}</coption></xml>)
252 choices}
253 </cselect></xml> : xbody,
254 Filter = fn s k => s <- signal s;
255 return (case read s : option t of
256 None => True
257 | Some k' => k' = k)},
186 {Display = fn (_, kr) => case kr of 258 {Display = fn (_, kr) => case kr of
187 None => <xml>NULL</xml> 259 None => <xml>NULL</xml>
188 | Some (k, r) => <xml>{[render ({nm = k} ++ r)]}</xml>, 260 | Some (k, r) => <xml>{[render ({nm = k} ++ r)]}</xml>,
189 Edit = fn (s, kr) => 261 Edit = fn (s, kr) =>
190 <xml><cselect source={s}> 262 <xml><cselect source={s}>
210 Parse = fn (s, _) => ks <- signal s; 282 Parse = fn (s, _) => ks <- signal s;
211 return (case ks of 283 return (case ks of
212 "" => Some None 284 "" => Some None
213 | _ => case read ks : option t of 285 | _ => case read ks : option t of
214 None => None 286 None => None
215 | Some k => Some (Some k))})} 287 | Some k => Some (Some k)),
288 CreateFilter = source "",
289 DisplayFilter = fn s =>
290 <xml><cselect source={s}>
291 <coption/>
292 <coption value="0">NULL</coption>
293 {List.mapX (fn (k, rend) =>
294 <xml><coption value={"1" ^ show k}>{[rend]}</coption>
295 </xml>)
296 choices}
297 </cselect></xml> : xbody,
298 Filter = fn s ko => s <- signal s;
299 return (case s of
300 "" => True
301 | "0" => ko = None
302 | _ =>
303 case read (String.substring s {Start = 1,
304 Len = String.length s - 1})
305 : option t of
306 None => True
307 | Some k => ko = Some k)})}
216 end 308 end
217 end 309 end
218 310
219 con computedState = (unit, xbody) 311 con computedState = (unit, xbody, unit)
220 fun computed [row] [t] (_ : show t) name (f : $row -> t) : colMeta row computedState = 312 fun computed [row] [t] (_ : show t) name (f : $row -> t) : colMeta row computedState =
221 {Initialize = return (), 313 {Initialize = return (),
222 Handlers = fn () => {Header = name, 314 Handlers = fn () => {Header = name,
223 Project = fn r => return <xml>{[f r]}</xml>, 315 Project = fn r => return <xml>{[f r]}</xml>,
224 Update = fn r _ => return r, 316 Update = fn r _ => return r,
225 Display = fn x => x, 317 Display = fn x => x,
226 Edit = fn _ => <xml>...</xml>, 318 Edit = fn _ => <xml>...</xml>,
227 Validate = fn _ => return True}} 319 Validate = fn _ => return True,
320 CreateFilter = return (),
321 DisplayFilter = fn _ => <xml/>,
322 Filter = fn _ _ => return True}}
228 fun computedHtml [row] name (f : $row -> xbody) : colMeta row computedState = 323 fun computedHtml [row] name (f : $row -> xbody) : colMeta row computedState =
229 {Initialize = return (), 324 {Initialize = return (),
230 Handlers = fn () => {Header = name, 325 Handlers = fn () => {Header = name,
231 Project = fn r => return (f r), 326 Project = fn r => return (f r),
232 Update = fn r _ => return r, 327 Update = fn r _ => return r,
233 Display = fn x => x, 328 Display = fn x => x,
234 Edit = fn _ => <xml>...</xml>, 329 Edit = fn _ => <xml>...</xml>,
235 Validate = fn _ => return True}} 330 Validate = fn _ => return True,
331 CreateFilter = return (),
332 DisplayFilter = fn _ => <xml/>,
333 Filter = fn _ _ => return True}}
236 334
237 functor Make(M : sig 335 functor Make(M : sig
238 con key :: {Type} 336 con key :: {Type}
239 con row :: {Type} 337 con row :: {Type}
240 constraint key ~ row 338 constraint key ~ row
241 table tab : (key ++ row) 339 table tab : (key ++ row)
242 340
243 val raw : $(map rawMeta (key ++ row)) 341 val raw : $(map rawMeta (key ++ row))
244 342
245 con cols :: {(Type * Type)} 343 con cols :: {(Type * Type * Type)}
246 val cols : $(map (colMeta (key ++ row)) cols) 344 val cols : $(map (colMeta (key ++ row)) cols)
247 345
248 val keyFolder : folder key 346 val keyFolder : folder key
249 val rowFolder : folder row 347 val rowFolder : folder row
250 val colsFolder : folder cols 348 val colsFolder : folder cols