Skip to content
This repository
Newer
Older
100644 306 lines (253 sloc) 9.239 kb
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
1 %%%-------------------------------------------------------------------
2 %%% Created : 14 Oct 2005 by Torbjorn Tornkvist <tobbe@tornkvist.org>
3 %%% Desc. : A naive Mnesia table viewer Yaws-app interface.
4 %%%
558e5250 » Tobbe Tornquist
2008-05-15 Minor Edoc fixes.
5 %%% @author Torbjorn Tornkvist <tobbe@tornkvist.org>
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
6 %%%
7 %%% @doc Ymnesia is a Yaws appmod to view Mnesia tables.
8 %%% Add <b>ymnesia</b> as an appmod to your Yaws configuration.
9 %%% Point your browser to: &lt;url&gt;/ymnesia
10 %%%
11 %%% <ul>
12 %%% <li> You can search on arbitrary Erlang terms.
13 %%% <br/>(<i>atoms need to be single-quoted</i>)</li>
14 %%% <li> The checkbox control if the attribute should be shown in
15 %%% the result. <br/>No checkbox means: <i>show all attributes</i>.</li>
16 %%% </ul>
17 %%%
558e5250 » Tobbe Tornquist
2008-05-15 Minor Edoc fixes.
18 %%% <p>
19 %%% To test it, add it as an appmod to you Yaws configuration, e.g:
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
20 %%%
21 %%% appmods = [{"showdb", ymnesia}}
22 %%%
558e5250 » Tobbe Tornquist
2008-05-15 Minor Edoc fixes.
23 %%% then point your browser to: http://&lt;host>/showdb/
24 %%% </p>
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
25 %%% @end
26 %%%
27 %%%-------------------------------------------------------------------
28 -module(ymnesia).
29
30 -export([out/1]).
31
32 -import(lists, [map/2, foldl/3, reverse/1]).
33
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
34 -include("../include/yaws_api.hrl").
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
35
36
37 -define(elog(X,Y), error_logger:info_msg("*elog ~p:~p: " X,
0be3c7e8 »
2008-02-14 untabified all of yaws
38 [?MODULE, ?LINE | Y])).
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
39
40 %%% Possible to call mnesia in another way
41 -define(MNESIA(Mod, Args), apply(mnesia, Mod, Args)).
42 %%-define(MNESIA(Mod, Args), fdapi:call_in_master(mnesia, Mod, Args)).
43
44
45 %%% @private
46 out(A) ->
47 %%?elog("Inside Ymnesia~n", []),
48 case string:tokens(A#arg.appmoddata, "/.") of
0be3c7e8 »
2008-02-14 untabified all of yaws
49 ["table" | _] ->
50 case is_post(A) of
51 true ->
52 L = yaws_api:parse_post(A),
53 {Cbox, Rest} = extract_cbox(L),
54 Name = lk("tablename", Rest),
55 Ls = select_fields(Rest),
56 Sp = (catch select_pattern(Name, Ls)),
57 case catch table(Cbox, Sp, l2a(Name)) of
58 {'EXIT', Reason} ->
59 ?elog("Error , reason: ~p~n", [Reason]),
60 error_page("table not found: "++Name);
61 Else ->
62 Else
63 end;
64 false ->
65 return_top_page()
66 end;
67 _ ->
68 return_top_page()
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
69 end.
70
71 %%% Get the fields to be part of the select
72 select_fields([{"tablename",_}|T]) -> select_fields(T);
73 select_fields([{_,undefined}|T]) -> select_fields(T);
74 select_fields([H|T]) -> [H|select_fields(T)];
75 select_fields([]) -> [].
0be3c7e8 »
2008-02-14 untabified all of yaws
76
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
77 select_pattern(Name, Ls) ->
78 Wp = ?MNESIA(table_info, [l2a(Name), wild_pattern]),
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
79 mk_select_pattern(map(fun(A) -> a2l(A) end,get_attributes(l2a(Name))),
6e96a140 »
2011-03-03 indendation cleanup
80 Ls, Wp, 2).
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
81
82 mk_select_pattern([A|As], [{A,V}|T], Wp, N) ->
83 mk_select_pattern(As, T, setelement(N, Wp, be_smart(V)), N+1);
84 mk_select_pattern([_|As], L, Wp, N) ->
85 mk_select_pattern(As, L, Wp, N+1);
86 mk_select_pattern([], [], Wp, _) ->
87 Wp.
88
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
89 %%% Try to be intelligent and convert the Key to the datatype that
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
90 %%% could be expected. Note: atom is anything between single quotes.
91 be_smart([$'|T]) -> l2a(eat_until($', T));
92 be_smart([$[|_] = L) -> str2term(L);
6e96a140 »
2011-03-03 indendation cleanup
93 be_smart([${|_] = L) -> str2term(L);
94 be_smart(L) ->
95 case be_smart(L, false) of
96 integer -> list_to_integer(L);
97 float -> list_to_float(L);
98 _ -> L
99 end.
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
100
101 eat_until(H, [H|_]) -> [];
102 eat_until(X, [H|T]) -> [H|eat_until(X,T)].
103
104
105 be_smart([H|T], false) when H>$0, H=<$9 ->
106 be_smart(T, integer);
107 be_smart([H|T], integer) when H>$0, H=<$9 ->
108 be_smart(T, integer);
109 be_smart([H|T], integer) when H>$. ->
110 be_smart(T, float);
111 be_smart([_|T], _) ->
112 be_smart(T, list);
113 be_smart([], Type) ->
114 Type.
115
116 return_top_page() ->
117 {ehtml,
118 [{head, [],
119 [meta() ++
6e96a140 »
2011-03-03 indendation cleanup
120 style()]},
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
121 {body, [],
122 mk_table_tab()}]}.
123
124 is_post(A) ->
125 case (A#arg.req)#http_request.method of
0be3c7e8 »
2008-02-14 untabified all of yaws
126 'GET' -> false;
127 'POST' -> true
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
128 end.
129
130 meta() ->
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
131 [{pre_html,
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
132 "<META HTTP-EQUIV=\"EXPIRES\" CONTENT=\""
133 "Sun, 16 Oct 2004 11:12:01 GMT\">"}].
134
135 style() ->
136 [{style, [{type, "text/css"}],
137 [{pre_html,
0be3c7e8 »
2008-02-14 untabified all of yaws
138 ["table {border-collapse: collapse; border: solid black 1px;}\n"
139 "p {padding: 5px; font-weight: bold;}\n"
140 "input[type=text] {vertical-align: bottom; width: 100%; font-size: 80%;}\n"
141 "input[type=checkbox] {vertical-align: top; font-size: 80%;}\n"
142 "span.attribute {vertical-align: top; font-size: 80%;}\n"
143 "th {padding: 5px; border: solid black 1px;}\n"
144 "td {padding: 5px; border: solid black 1px;}\n"
145 ]}]}].
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
146
147
148 %%% Build the result page.
ca1c8b1b » karlsson
2010-07-01 Fixed a number of compiler warnings and html validation errors
149 table(Cbox, Sp, Table) when is_atom(Table) ->
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
150 case catch ?MNESIA(table_info, [Table, attributes]) of
ca1c8b1b » karlsson
2010-07-01 Fixed a number of compiler warnings and html validation errors
151 Headers when is_list(Headers) ->
0be3c7e8 »
2008-02-14 untabified all of yaws
152 Vp = view_pattern(Cbox, map(fun(X) -> a2l(X) end, Headers)),
153 {Q, Result} = do_query(Sp),
154 {ehtml,
155 [{head, [],
156 [meta() ++
6e96a140 »
2011-03-03 indendation cleanup
157 style()]},
0be3c7e8 »
2008-02-14 untabified all of yaws
158 {body, [],
159 [{'div', [],
160 {p, [], "Query: "++Q}},
161 {'div', [],
162 {p, [], "Table: "++a2l(Table)}} |
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
163 mk_tab(Vp, Headers, t2l(Result))]}]};
0be3c7e8 »
2008-02-14 untabified all of yaws
164 Else ->
165 Else
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
166 end.
167
168 %%% Create a pattern denoting which fields to show in the result.
169 view_pattern(Cs, L) -> view_pattern(Cs, L, 1).
170
171 view_pattern([Cbox|Cs], [Cbox|T], N) -> [N | view_pattern(Cs, T, N+1)];
172 view_pattern(Cs, [_|T], N) -> view_pattern(Cs, T, N+1);
173 view_pattern([], [], _) -> [].
174
175
176
177 %%% Create a table of: Table | Table-attribute-1 | ... | Table-attribute-N
178 %%% where each table is a Form
179 mk_table_tab() ->
180 Rows = get_tables(),
181 [{'div', [],
182 [{table, [],
0be3c7e8 »
2008-02-14 untabified all of yaws
183 map(fun(Row) ->
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
184 {tr, [],
185 {form, [{action, "table.yaws"},
0be3c7e8 »
2008-02-14 untabified all of yaws
186 {method, "post"},
187 {name, Row}],
188 [{td, [], sublnk(a2l(Row))} |
189 mk_input_fields(Row)]}}
190 end, Rows)}]}].
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
191
192 %%% Create each table cell; consisting of the attribute name and an input field.
193 mk_input_fields(Table) ->
194 As = get_attributes(Table),
195 Max = max_noof_attrs(),
196 map(fun(0) ->
0be3c7e8 »
2008-02-14 untabified all of yaws
197 {td, [], []};
198 (Attribute) ->
199 A = a2l(Attribute),
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
200 {td, [],
0be3c7e8 »
2008-02-14 untabified all of yaws
201 [{input, [{type, "checkbox"}, {name, "cbox_"++A}]},
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
202 {span, [{class, "attribute"}], A},
0be3c7e8 »
2008-02-14 untabified all of yaws
203 {input, [{type, "text"}, {name, A}]}]}
204 end, As ++ lists:duplicate(Max-length(As), 0)).
205
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
206
207 extract_cbox(L) ->
208 extract_cbox(L, [], []).
209
210 extract_cbox([{"cbox_"++Cbox,_}|T], Cs, Rs) ->
211 extract_cbox(T, [Cbox|Cs], Rs);
212 extract_cbox([H|T], Cs, Rs) ->
213 extract_cbox(T, Cs, [H|Rs]);
214 extract_cbox([], Cs, Rs) ->
215 {reverse(Cs), reverse(Rs)}.
216
217
218 %%% Build the result table.
219 mk_tab(Vp, Headers, Rows) ->
220 [{'div', [],
221 [{table, [],
0be3c7e8 »
2008-02-14 untabified all of yaws
222 [{tr, [],
223 [{th, [], a2l(X)} || X <- vp(Vp,Headers)]} |
224 map(fun(Row) ->
225 {tr, [],
226 [{td, [], massage(W)} || W <- vp(Vp,Row)]}
227 end, Rows)]}]}].
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
228
229 %%% Match the view pattern to select which entries to let through.
230 vp([], L) -> L;
231 vp(Vp, L) -> vp(Vp, L, 1).
232
233 vp([N|Vp], [H|T], N) -> [H|vp(Vp, T, N+1)];
234 vp(Vp, [_|T], N) -> vp(Vp, T, N+1);
235 vp([], [], _) -> [].
236
237 %%% Create a link that submit the form: onclick
455578a2 » vinoski
2011-04-19 major trailing whitespace cleanup
238 sublnk(E) ->
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
239 {a, [{href, "#"},
0be3c7e8 »
2008-02-14 untabified all of yaws
240 {onclick, E++".submit();"}],
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
241 [E,
242 {input, [{type, "hidden"},
0be3c7e8 »
2008-02-14 untabified all of yaws
243 {name, "tablename"},
244 {value, E}]}]}.
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
245
246 massage(W) ->
247 lists:flatten(io_lib:format("~p",[W])).
248
249 do_query(Sp) ->
250 {lists:flatten(io_lib:format("mnesia:match_object(~p)", [Sp])),
251 lists:keysort(2, ?MNESIA(dirty_match_object, [Sp]))}.
252
253 error_page(Msg) ->
254 {html,
255 [Msg]}.
256
257
258 get_tables() ->
259 ?MNESIA(system_info, [tables]) -- [schema].
260
261 get_attributes(Table) ->
262 ?MNESIA(table_info, [Table, attributes]).
263
264 max_noof_attrs() ->
265 foldl(fun(Table, Max) ->
ca1c8b1b » karlsson
2010-07-01 Fixed a number of compiler warnings and html validation errors
266 erlang:max(length(get_attributes(Table)), Max)
0be3c7e8 »
2008-02-14 untabified all of yaws
267 end, 0, get_tables()).
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
268
269
ca1c8b1b » karlsson
2010-07-01 Fixed a number of compiler warnings and html validation errors
270 a2l(A) when is_atom(A) -> atom_to_list(A);
271 a2l(L) when is_list(L) -> L.
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
272
ca1c8b1b » karlsson
2010-07-01 Fixed a number of compiler warnings and html validation errors
273 l2a(L) when is_list(L) -> list_to_atom(L);
274 l2a(A) when is_atom(A) -> A.
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
275
276 lk(Key, L) ->
277 {value, {_,Val}} = lists:keysearch(Key, 1, L),
278 Val.
279
280 t2l(L) ->
281 map(fun(T) -> tail(tuple_to_list(T)) end, L).
0be3c7e8 »
2008-02-14 untabified all of yaws
282
39d264c3 » Tobbe Tornquist
2006-09-06 Added the ymnesia.erl appmod.
283 tail([]) -> [];
284 tail(L) -> tl(L).
285
286
287 str2term(Str) ->
288 hd(str2terms(Str ++ ". ")).
289
290 %% str2tokens:str2terms("{hello,23}. [arne,43]. 5.6. {5.5,1.0}. ").
291 %% ==> [{hello,23},[arne,43],5.60000,{5.50000,1.00000}]
292 str2terms(String) ->
293 tokenlists2terms(str2tokenlists(String)).
294
295 str2tokenlists("") -> [];
296 str2tokenlists(String) ->
297 case erl_scan:tokens([], String, 1) of
298 {done, {ok, Tokens, _}, Rest} ->
299 [Tokens | str2tokenlists(Rest)]
300 end.
301
302 tokenlists2terms(Lists) ->
303 lists:map(fun(L) ->
304 {ok, Term} = erl_parse:parse_term(L),
305 Term
306 end, Lists).
307
Something went wrong with that request. Please try again.