summaryrefslogtreecommitdiff
path: root/demo/more/orm.ur
blob: f976fcb2cec75639ef5099e9923af8140507e545 (plain)
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
con link = fn t :: Type => unit

con meta = fn col :: Type => {
              Link : link col,
              Inj : sql_injectable col
              }

functor Table(M : sig
                  con cols :: {Type}
                  val cols : $(map meta cols)
                  constraint [Id] ~ cols
                  val folder : folder cols
              end) = struct
    type id = int
    val inj = _
    val id : meta id = {Link = (),
                        Inj = inj}

    con fs = [Id = id] ++ M.cols

    sequence s
    table t : fs

    type row = $fs

    fun ensql [avail] (r : $M.cols) : $(map (sql_exp avail [] []) M.cols) =
        map2 [meta] [Top.id] [sql_exp avail [] []]
             (fn [t] meta v => @sql_inject meta.Inj v)
             [_] M.folder M.cols r

    fun create (r : $M.cols) =
        id <- nextval s;
        dml (insert t ({Id = sql_inject id} ++ ensql r));
        return ({Id = id} ++ r)

    fun delete r = dml (DELETE FROM t WHERE t.Id = {[r.Id]})

    fun save r = dml (update [M.cols] ! (ensql (r -- #Id)) t (WHERE T.Id = {[r.Id]}))

    fun lookup id =
        ro <- oneOrNoRows (SELECT * FROM t WHERE t.Id = {[id]});
        return (Option.mp (fn r => r.T) ro)

    fun resultsOut q = query q (fn r ls => return (r.T :: ls)) []

    val list = resultsOut (SELECT * FROM t)

    con col = fn t => {Exp : sql_exp [T = fs] [] [] t,
                       Inj : sql_injectable t}
    val idCol = {Exp = sql_field [#T] [#Id], Inj = _}
    val cols = foldR [meta] [fn before => after :: {Type} -> [before ~ after] =>
                                $(map (fn t => {Exp : sql_exp [T = before ++ after] [] [] t,
                                                Inj : sql_injectable t}) before)]
               (fn [nm :: Name] [t :: Type] [before :: {Type}] [[nm] ~ before] (meta : meta t)
                                (acc : after :: {Type} -> [before ~ after] =>
                                 $(map (fn t => {Exp : sql_exp [T = before ++ after] [] [] t,
                                                 Inj : sql_injectable t}) before))
                                [after :: {Type}] [[nm = t] ++ before ~ after] =>
                   {nm = {Exp = sql_field [#T] [nm],
                          Inj = meta.Inj}} ++ acc [[nm = t] ++ after] !)
               (fn [after :: {Type}] [[] ~ after] => {})
               [_] M.folder M.cols
               [[Id = id]] !

    type filter = sql_exp [T = fs] [] [] bool
    fun search (f : filter) = resultsOut (SELECT * FROM t WHERE {f})

    fun bin (b : t ::: Type -> sql_binary t t bool) [t] (c : col t) (v : t) =
        sql_binary b c.Exp (@sql_inject c.Inj v)
    val eq = bin @@sql_eq
    val ne = bin @@sql_ne
    val lt = bin @@sql_lt
    val le = bin @@sql_le
    val gt = bin @@sql_gt
    val ge = bin @@sql_ge

    fun bb (b : sql_binary bool bool bool) (f1 : filter) (f2 : filter) =
        sql_binary b f1 f2
    val _and = bb sql_and
    val or = bb sql_or
end