adamc@990: con link = fn col_parent :: (Type * Type) => col_parent.1 -> transaction (option col_parent.2)
adam@1304: fun noParent [t ::: Type] (_ : t) : transaction (option unit) = return None
adamc@987: 
adamc@1002: con meta = fn (col :: Type, parent :: Type) => {
adamc@1002: 	      Link : link (col, parent),
adamc@1002: 	      Inj : sql_injectable col
adamc@990: 	      }
adamc@987: 
adam@1304: fun local [t :: Type] (inj : sql_injectable t) : meta (t, unit) =
adam@1304:     {Link = noParent,
adam@1304:      Inj = inj}
adamc@991: 
adamc@987: functor Table(M : sig
adamc@990:                   con cols :: {(Type * Type)}
adamc@987:                   val cols : $(map meta cols)
adamc@987:                   constraint [Id] ~ cols
adamc@987:                   val folder : folder cols
adamc@987:               end) = struct
adamc@987:     type id = int
adamc@990:     con fs' = map fst M.cols
adamc@990:     con fs = [Id = id] ++ fs'
adamc@990:     type row' = $fs'
adamc@990:     type row = $fs
adamc@987: 
adamc@990:     fun resultsOut q = query q (fn r ls => return (r.T :: ls)) []
adamc@990:     fun resultOut q = ro <- oneOrNoRows q; return (Option.mp (fn r => r .T) ro)
adamc@989: 
adamc@987:     sequence s
adamc@989:     table t : fs
adamc@987: 
adamc@990:     val inj = _
adamc@990:     val id = {Link = fn id => resultOut (SELECT * FROM t WHERE t.Id = {[id]}),
adamc@990:               Inj = inj}
adamc@988: 
adam@1778:     fun ensql [avail ::_] (r : row') : $(map (sql_exp avail [] []) fs') =
adam@1778:         @map2 [meta] [fst] [fn ts :: (Type * Type) => sql_exp avail [] [] ts.1]
adamc@1093:          (fn [ts] meta v => @sql_inject meta.Inj v)
adamc@1093:          M.folder M.cols r
adamc@988: 
adamc@990:     fun create (r : row') =
adamc@987:         id <- nextval s;
adam@1304:         dml (insert t ({Id = sql_inject id} ++ ensql [[]] r));
adamc@988:         return ({Id = id} ++ r)
adamc@988: 
adamc@988:     fun delete r = dml (DELETE FROM t WHERE t.Id = {[r.Id]})
adamc@988: 
adam@1304:     fun save r = dml (update [fs'] (ensql [[T = [Id = int] ++ map fst M.cols]] (r -- #Id)) t (WHERE T.Id = {[r.Id]}))
adamc@988: 
adamc@988:     fun lookup id =
adamc@988:         ro <- oneOrNoRows (SELECT * FROM t WHERE t.Id = {[id]});
adamc@988:         return (Option.mp (fn r => r.T) ro)
adamc@988: 
adamc@989: 
adamc@989:     val list = resultsOut (SELECT * FROM t)
adamc@989: 
adam@1778:     con col = fn t => {Exp : sql_exp [T = fs] [] [] t,
adamc@989:                        Inj : sql_injectable t}
adamc@989:     val idCol = {Exp = sql_field [#T] [#Id], Inj = _}
adamc@1002:     con meta' = fn (fs :: {Type}) (col :: Type, parent :: Type) =>
adam@1778:                    {Col : {Exp : sql_exp [T = fs] [] [] col,
adamc@1002:                            Inj : sql_injectable col},
adamc@1002:                     Parent : $fs -> transaction (option parent)}
adamc@1093:     val cols = @foldR [meta] [fn before => after :: {(Type * Type)} -> [before ~ after] =>
adamc@1093:                                  $(map (meta' (map fst (before ++ after))) before)]
adamc@1093:                 (fn [nm :: Name] [ts :: (Type * Type)] [before :: {(Type * Type)}]
adamc@1093:                                  [[nm] ~ before] (meta : meta ts)
adamc@1093:                                  (acc : after :: {(Type * Type)} -> [before ~ after] =>
adamc@1093:                                   $(map (meta' (map fst (before ++ after))) before))
adamc@1093:                                  [after :: {(Type * Type)}] [[nm = ts] ++ before ~ after] =>
adamc@1093:                     {nm = {Col = {Exp = sql_field [#T] [nm],
adamc@1093:                                   Inj = meta.Inj},
adamc@1093:                            Parent = fn r => meta.Link r.nm}}
adam@1488:                         ++ acc [[nm = ts] ++ after])
adamc@1093:                 (fn [after :: {(Type * Type)}] [[] ~ after] => {})
adamc@1093:                 M.folder M.cols
adamc@1093:                 [[Id = (id, row)]] !
adamc@989: 
adam@1778:     type filter = sql_exp [T = fs] [] [] bool
adamc@990:     fun find (f : filter) = resultOut (SELECT * FROM t WHERE {f})
adamc@989:     fun search (f : filter) = resultsOut (SELECT * FROM t WHERE {f})
adamc@989: 
adamc@989:     fun bin (b : t ::: Type -> sql_binary t t bool) [t] (c : col t) (v : t) =
adamc@989:         sql_binary b c.Exp (@sql_inject c.Inj v)
adamc@1093:     val eq = @@bin @@sql_eq
adamc@1093:     val ne = @@bin @@sql_ne
adamc@1093:     val lt = @@bin @@sql_lt
adamc@1093:     val le = @@bin @@sql_le
adamc@1093:     val gt = @@bin @@sql_gt
adamc@1093:     val ge = @@bin @@sql_ge
adamc@989: 
adamc@989:     fun bb (b : sql_binary bool bool bool) (f1 : filter) (f2 : filter) =
adamc@989:         sql_binary b f1 f2
adamc@989:     val _and = bb sql_and
adamc@989:     val or = bb sql_or
adamc@987: end