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