con colMeta = fn (db :: Type, state :: Type) =>
{Nam : string,
Show : db -> xbody,
Inject : sql_injectable db,
NewState : transaction state,
Widget : state -> xbody,
ReadState : state -> transaction db}
con colsMeta = fn cols => $(map colMeta cols)
fun default [t] (sh : show t) (rd : read t) (inj : sql_injectable t)
name : colMeta (t, source string) =
{Nam = name,
Show = txt,
Inject = _,
NewState = source "",
Widget = fn s => ,
ReadState = fn s => v <- get s; return (readError v)}
val int = default
val float = default
val string = default
functor Make(M : sig
con cols :: {(Type * Type)}
constraint [Id] ~ cols
val fl : folder cols
table tab : ([Id = int] ++ map fst cols)
val title : string
val cols : colsMeta cols
end) = struct
val t = M.tab
datatype list t = Nil | Cons of t * list t
fun allRows () =
query (SELECT * FROM t)
(fn r acc => return (Cons (r.T, acc)))
Nil
fun add r =
dml (insert t
(@foldR2 [fst] [colMeta]
[fn cols => $(map (fn t => sql_exp [] [] [] t.1) cols)]
(fn [nm :: Name] [t ::_] [rest ::_] [[nm] ~ rest] input col acc =>
acc ++ {nm = @sql_inject col.Inject input})
{} M.fl (r -- #Id) M.cols
++ {Id = (SQL {[r.Id]})}))
fun doBatch ls =
case ls of
Nil => return ()
| Cons (r, ls') =>
add r;
doBatch ls'
fun del id =
dml (DELETE FROM t WHERE t.Id = {[id]})
fun show withDel lss =
let
fun show' ls =
case ls of
Nil =>
| Cons (r, ls) =>
{[r.Id]}
{@mapX2 [colMeta] [fst] [_]
(fn [nm :: Name] [p ::_] [rest ::_] [[nm] ~ rest] m v =>