diff demo/batchFun.ur @ 650:fcf0bd3d1667

BatchG demo
author Adam Chlipala <adamc@hcoop.net>
date Tue, 10 Mar 2009 16:38:38 -0400
parents
children 1fb318c17546
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demo/batchFun.ur	Tue Mar 10 16:38:38 2009 -0400
@@ -0,0 +1,162 @@
+con colMeta = fn t_state :: (Type * Type) =>
+                 {Nam : string,
+                  Show : t_state.1 -> xbody,
+                  Inject : sql_injectable t_state.1,
+
+                  NewState : transaction t_state.2,
+                  Widget : t_state.2 -> xbody,
+                  ReadState : t_state.2 -> transaction t_state.1}
+con colsMeta = fn cols :: {(Type * Type)} => $(map colMeta cols)
+
+fun default (t ::: Type) (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 => <xml><ctextbox source={s}/></xml>,
+     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
+                          
+                 val tab : sql_table ([Id = int] ++ map fst cols)
+                           
+                 val title : string
+                             
+                 val cols : colsMeta cols
+             end) = struct
+
+    open constraints M
+    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 :: (Type * Type) =>
+                                                  sql_exp [] [] [] t.1) cols)]
+                            (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)})
+                                             [[nm] ~ rest] input col acc =>
+                                acc ++ {nm = @sql_inject col.Inject input})
+                            {} [M.cols] 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 => <xml/>
+                  | Cons (r, ls) => <xml>
+                    <tr>
+                      <td>{[r.Id]}</td>
+                      {foldRX2 [colMeta] [fst] [_]
+                               (fn (nm :: Name) (p :: (Type * Type)) (rest :: {(Type * Type)})
+                                                [[nm] ~ rest] m v =>
+                                   <xml><td>{m.Show v}</td></xml>)
+                               [M.cols] M.fl M.cols (r -- #Id)}
+                      {if withDel then
+                           <xml><td><button value="Delete" onclick={del r.Id}/></td></xml>
+                       else
+                           <xml/>}
+                    </tr>
+                    {show' ls}
+                  </xml>
+        in
+            <xml><dyn signal={ls <- signal lss; return <xml><table>
+              <tr>
+                <th>Id</th>
+                {foldRX [colMeta] [_]
+                        (fn (nm :: Name) (p :: (Type * Type)) (rest :: {(Type * Type)})
+                                         [[nm] ~ rest] m =>
+                            <xml><th>{[m.Nam]}</th></xml>)
+                        [M.cols] M.fl M.cols}
+              </tr>
+              {show' ls}
+            </table></xml>}/></xml>
+        end
+
+    fun main () =
+        lss <- source Nil;
+        batched <- source Nil;
+
+        id <- source "";
+        inps <- foldR [colMeta] [fn r => transaction ($(map snd r))]
+                (fn (nm :: Name) (p :: (Type * Type)) (rest :: {(Type * Type)}) [[nm] ~ rest] m acc =>
+                    s <- m.NewState;
+                    r <- acc;
+                    return ({nm = s} ++ r))
+                (return {})
+                [M.cols] M.fl M.cols;
+
+        let
+            fun add () =
+                id <- get id;
+                vs <- foldR2 [colMeta] [snd] [fn r => transaction ($(map fst r))]
+                             (fn (nm :: Name) (p :: (Type * Type)) (rest :: {(Type * Type)})
+                                              [[nm] ~ rest] m s acc =>
+                                 v <- m.ReadState s;
+                                 r <- acc;
+                                 return ({nm = v} ++ r))
+                             (return {})
+                             [M.cols] M.fl M.cols inps;
+                ls <- get batched;
+
+                set batched (Cons ({Id = readError id} ++ vs, ls))
+
+            fun exec () =
+                ls <- get batched;
+
+                doBatch ls;
+                set batched Nil
+        in
+            return <xml><body>
+              <h2>Rows</h2>
+
+              {show True lss}
+
+              <button value="Update" onclick={ls <- allRows (); set lss ls}/><br/>
+              <br/>
+
+              <h2>Batch new rows to add</h2>
+
+              <table>
+                <tr> <th>Id:</th> <td><ctextbox source={id}/></td> </tr>
+                {foldRX2 [colMeta] [snd] [_]
+                 (fn (nm :: Name) (p :: (Type * Type)) (rest :: {(Type * Type)})
+                                  [[nm] ~ rest] m s =>
+                     <xml><tr> <th>{[m.Nam]}:</th> <td>{m.Widget s}</td> </tr></xml>)
+                 [M.cols] M.fl M.cols inps}
+                <tr> <th/> <td><button value="Batch it" onclick={add ()}/></td> </tr>
+              </table>
+
+              <h2>Already batched:</h2>
+              {show False batched}
+              <button value="Execute" onclick={exec ()}/>
+            </body></xml>
+        end
+
+end