34
35:- module(swish_csv, []). 36:- use_module(library(pengines), []). 37:- use_module(library(pairs)). 38:- use_module(library(csv), [csv_write_stream/3]). 39:- use_module(library(apply)). 40:- use_module(library(pprint)). 41:- use_module(library(option)). 42:- use_module(library(http/http_cors)).
54:- multifile
55 pengines:write_result/3,
56 write_answers/2, 57 write_answers/3.
64pengines:write_result(csv, Event, OptionDict) :-
65 ( Disposition = OptionDict.get(disposition)
66 -> Options = [disposition(Disposition)]
67 ; Options = []
68 ),
69 csv(Event, Options).
70
71csv(create(_Id, Features), Options) :- !,
72 memberchk(answer(Answer), Features),
73 csv(Answer, Options).
74csv(destroy(_Id, Wrapped), Options) :- !,
75 csv(Wrapped, Options).
76csv(success(_Id, Answers, Projection, _Time, More), Options) :- !,
77 VarTerm =.. [row|Projection],
78 success(Answers, VarTerm, [more(More)|Options]).
79csv(error(_Id, Error), _Options) :- !,
80 message_to_string(Error, Msg),
81 format('Status: 400 Bad request~n'),
82 format('Content-type: text/plain~n~n'),
83 format('ERROR: ~w~n', [Msg]).
84csv(output(_Id, message(_Term, _Class, HTML, _Where)), _Opts) :- !,
85 format('Status: 400 Bad request~n'),
86 format('Content-type: text/html~n~n'),
87 format('<html>~n~s~n</html>~n', [HTML]).
88csv(page(Page, Event), Options) :-
89 csv(Event, [page(Page)|Options]).
90csv(failure(_Id, _Time), Options) :- !,
91 success([], -, [more(false)|Options]).
92csv(Event, _) :-
93 print_term(Event, [output(user_error)]).
94
95success(Answers, VarTerm, Options) :-
96 write_answers(Answers, VarTerm, Options), !.
97success(Answers, VarTerm, Options) :-
98 write_answers(Answers, VarTerm), !,
99 assertion(\+option(page(_), Options)).
100success(Answers, _VarTerm, Options) :-
101 option(page(Page), Options),
102 Page > 1, !,
103 maplist(csv_answer, Answers, Rows),
104 forall(paginate(100, OutPage, Rows),
105 csv_write_stream(current_output, OutPage, [])).
106success(Answers, VarTerm, Options) :-
107 option(disposition(Disposition), Options, 'swish-result.csv'),
108 maplist(csv_answer, Answers, Rows),
109 cors_enable,
110 format('Content-encoding: chunked~n'),
111 format('Content-disposition: attachment; filename="~w"~n', [Disposition]),
112 format('Content-type: text/csv~n~n'),
113 projection_row(VarTerm),
114 forall(paginate(100, Page, Rows),
115 csv_write_stream(current_output, Page, [])).
116
117projection_row(-) :- !.
118projection_row(row) :- !.
119projection_row(VarTerm) :-
120 csv_write_stream(current_output, [VarTerm], []).
121
122paginate(Len, Page, List) :-
123 length(Page0, Len),
124 ( append(Page0, Rest, List)
125 -> ( Page = Page0
126 ; paginate(Len, Page, Rest)
127 )
128 ; Page = List
129 ).
130
131
132csv_answer(JSON, Row) :-
133 is_dict(JSON), !,
134 dict_pairs(JSON, _, Pairs),
135 pairs_values(Pairs, Values),
136 maplist(csv_value, Values, CVSValues),
137 Row =.. [row|CVSValues].
138csv_answer(RowIn, Row) :-
139 compound(RowIn), !,
140 RowIn =.. [_|Values],
141 maplist(csv_value, Values, CVSValues),
142 Row =.. [row|CVSValues].
143
144csv_value(Var, '') :-
145 var(Var), !.
146csv_value(Number, Number) :-
147 number(Number), !.
148csv_value(Atom, Atom) :-
149 atom(Atom), !.
150csv_value(String, String) :-
151 string(String), !.
152csv_value(Term, Value) :-
153 term_string(Term, Value)
Support CSV output from a Pengines server
This module defines the result-format
csv
for Pengines. It allows SWISH users to post a query against the core Prolog system or a saved SWISH program and obtain the results using a simple web client such ascurl
. An example shell script is provided inclient/swish-ask.sh
.