comparison demo/more/versioned.ur @ 993:10114d7b7477

SELECT DISTINCT; eta expansion during Cjrization
author Adam Chlipala <adamc@hcoop.net>
date Tue, 06 Oct 2009 15:39:27 -0400
parents
children 166ea3944b91
comparison
equal deleted inserted replaced
992:b825d843b22d 993:10114d7b7477
1 functor Make(M : sig
2 con key :: {Type}
3 con data :: {Type}
4 constraint key ~ data
5 constraint [When] ~ (key ++ data)
6
7 val key : $(map sql_injectable key)
8 val data : $(map (fn t => {Inj : sql_injectable_prim t,
9 Eq : eq t}) data)
10
11 val keyFolder : folder key
12 val dataFolder : folder data
13 end) = struct
14 con all = [When = time] ++ M.key ++ map option M.data
15 table t : all
16
17 val keys = List.mapQuery (SELECT DISTINCT t.{{M.key}} FROM t) (fn r => r.T)
18
19 con dmeta = fn t => {Inj : sql_injectable_prim t,
20 Eq : eq t}
21
22 fun keyRecd (r : $(M.key ++ M.data)) =
23 map2 [sql_injectable] [id] [sql_exp [] [] []]
24 (fn [t] => @sql_inject)
25 [_] M.keyFolder M.key (r --- M.data)
26
27 fun insert r = dml (Basis.insert t
28 ({When = (SQL CURRENT_TIMESTAMP)}
29 ++ keyRecd r
30 ++ map2 [dmeta] [id]
31 [fn t => sql_exp [] [] [] (option t)]
32 (fn [t] x v => @sql_inject (@sql_option_prim x.Inj)
33 (Some v))
34 [_] M.dataFolder M.data (r --- M.key)))
35
36 fun keyExp (r : $M.key) : sql_exp [T = all] [] [] bool =
37 foldR2 [sql_injectable] [id] [fn before => after :: {Type} -> [before ~ after]
38 => sql_exp [T = before ++ after] [] [] bool]
39 (fn [nm :: Name] [t :: Type] [before :: {Type}] [[nm] ~ before]
40 (inj : sql_injectable t) (v : t)
41 (e : after :: {Type} -> [before ~ after]
42 => sql_exp [T = before ++ after] [] [] bool)
43 [after :: {Type}] [[nm = t] ++ before ~ after] =>
44 (SQL t.{nm} = {[v]} AND {e [[nm = t] ++ after] !}))
45 (fn [after :: {Type}] [[] ~ after] => (SQL TRUE))
46 [_] M.keyFolder M.key r
47 [_] !
48
49 fun current k =
50 let
51 fun current' timeOpt r =
52 let
53 val complete = foldR [option] [fn ts => option $ts]
54 (fn [nm :: Name] [v :: Type] [r :: {Type}] [[nm] ~ r]
55 v r =>
56 case (v, r) of
57 (Some v, Some r) => Some ({nm = v} ++ r)
58 | _ => None)
59 (Some {}) [_] M.dataFolder r
60 in
61 case complete of
62 Some r => return (Some r)
63 | None =>
64 let
65 val filter = case timeOpt of
66 None => (WHERE TRUE)
67 | Some time => (WHERE t.When < {[time]})
68 in
69 ro <- oneOrNoRows (SELECT t.When, t.{{map option M.data}}
70 FROM t
71 WHERE {filter}
72 AND {keyExp k}
73 ORDER BY t.When DESC
74 LIMIT 1);
75 case ro of
76 None => return None
77 | Some r' =>
78 let
79 val r = map2 [option] [option] [option]
80 (fn [t ::: Type] old new =>
81 case old of
82 None => new
83 | Some _ => old)
84 [_] M.dataFolder r (r'.T -- #When)
85 in
86 current' (Some r'.T.When) r
87 end
88 end
89 end
90 in
91 current' None (map0 [option] (fn [t :: Type] => None : option t) [_] M.dataFolder)
92 end
93
94 fun update r =
95 cur <- current (r --- M.data);
96 case cur of
97 None => error <xml>Tried to update nonexistent key</xml>
98 | Some cur =>
99 let
100 val r' = map3 [dmeta] [id] [id] [fn t => sql_exp [] [] [] (option t)]
101 (fn [t] (meta : dmeta t) old new =>
102 @sql_inject (@sql_option_prim meta.Inj)
103 (if @@eq [_] meta.Eq old new then
104 None
105 else
106 Some new))
107 [_] M.dataFolder M.data cur (r --- M.key)
108 val r' = {When = (SQL CURRENT_TIMESTAMP)}
109 ++ keyRecd r
110 ++ r'
111 in
112 dml (Basis.insert t r')
113 end
114 end