Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/encoding/sparql-results-html-table.lisp

KindCoveredAll%
expression0313 0.0
branch08 0.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.implementation; -*-
2
 
3
 (in-package :org.datagraph.spocq.implementation)
4
 
5
 ;;; solutions serialized in an html document as a
6
 ;;; each query is one line
7
 
8
 ;;; no reading
9
 
10
 (defparameter *html-host-properties*
11
   '((:name "de1" :hostname "de1.dydra.com")
12
     (:name "de2" :hostname "de2.dydra.com")
13
     (:name "de3" :hostname "de3.dydra.com")
14
     (:name "de4" :hostname "de4.dydra.com")
15
     (:name "dev" :hostname "dev.dydra.com")))
16
 
17
 (defparameter *html-header*
18
   "<meta charset='UTF-8'>
19
 <title>
20
 Dydra [~a] - Query Log
21
 </title>
22
 <meta content='Dydra.com' name='description'>
23
 <meta content='Dydra' name='author'>
24
 <meta content='width=device-width, initial-scale=1.0' name='viewport'>
25
 <link href='https://s3.amazonaws.com/public.dydra.com/favicon.ico?1317813968' rel='shortcut icon'>
26
 <link href='https://s3.amazonaws.com/public.dydra.com/apple-touch-icon.png?1317813968' rel='apple-touch-icon'>
27
 <link href='http://feeds.feedburner.com/dydra' rel='alternate' title='Dydra Blog' type='application/rss+xml'>
28
 <link href='https://s3.amazonaws.com/public.dydra.com/stylesheets/jquery-ui/aristo/jquery-ui-1.8.7.custom_compiled.css?1317814233' media='screen' rel='stylesheet' type='text/css' />
29
 <link href='https://s3.amazonaws.com/public.dydra.com/stylesheets/style.css?1337867890' media='screen' rel='stylesheet' type='text/css' />
30
 
31
 
32
 <meta name='csrf-param' content='authenticity_token'/>
33
 <meta name='csrf-token' content='lAMMP/Pw12reZIu3XN6Lgc99I9wGjgRxYGeoPWcrcoQ='/>
34
 ")
35
 
36
 (defparameter *html-body-prologue*
37
   "<body class='usage_stats index no-aside'>
38
 <div id='flash' style='display:none'>
39
 <div class='wrapper'>
40
 </div>
41
 </div>
42
 
43
 <div id='header'>
44
 <div class='wrapper'>
45
 <a href='http://de4.dydra.com/' id='logo'>Dydra</a>
46
 <div id='nav'  style='display: none;'>
47
 <ul class='nav' id='dydra-header-logged-out'>
48
 <li><a href='http://de4.dydra.com/signup' class='dydra-link-signup'>Signup</a></li>
49
 <li><a href='http://de4.dydra.com/login' class='dydra-link-login'>Login</a></li>
50
 </ul>
51
 <ul class='nav' id='dydra-header-logged-in'>
52
 <li><a href='http://de4.dydra.com/account' class='dydra-link-my-account'>My Account</a></li>
53
 <li><a href='http://de4.dydra.com/logout' class='dydra-link-logout'>Logout</a></li>
54
 </ul>
55
 <ul class='nav'>
56
 <li><a href='http://de4.dydra.com/' class='dydra-link-home'>Home</a></li>
57
 <li><a href='http://de4.dydra.com/about' class='dydra-link-about'>About</a></li>
58
 <li><a href='http://docs.dydra.com/' class='dydra-link-docs'>Docs</a></li>
59
 <li><a href='http://blog.dydra.com/' class='dydra-link-blog'>Blog</a></li>
60
 </ul>
61
 </div>
62
 <script>
63
   //<![CDATA[
64
     if(document.cookie.indexOf('dydra_session') != -1) {
65
       document.getElementById('dydra-header-logged-out').style.display = 'none';
66
     }
67
     else {
68
       document.getElementById('dydra-header-logged-in').style.display = 'none';
69
     }
70
   //]]>
71
 </script>
72
 
73
 </div>
74
 </div>
75
 
76
 ")
77
 
78
 (defparameter *html-body-epilogue*
79
   "</div>
80
 </div>
81
 </div>
82
 </div>
83
 ")
84
 ;;; writing - either boolean or bindings
85
 
86
 (defun write-sparql-results-html (stream &key head body)
87
   (format stream "<!DOCTYPE html>~%<html lang='en'>")
88
   (format stream "~%<head>")
89
   (format stream *html-header* (host-name))
90
   (when head (funcall head stream))
91
   (format stream "~% <link rel='stylesheet' href='/css/bootstrap.min.css'>")
92
   (format stream "~% <link rel='stylesheet' href='/css/bootstrap-theme.min.css'>")
93
   (format stream "~% <link rel='stylesheet' href='/css/bootstrap-datepicker.css'>")
94
   (format stream "~% <link rel='stylesheet' href='/css/tablesorter/theme.bootstrap.css'>")
95
   (format stream "~% <link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/select2/3.5.0/select2.min.css'>")
96
   (format stream "~% <link rel='stylesheet' href='//fk.github.io/select2-bootstrap-css/css/select2-bootstrap.css'>")
97
   (format stream "~% <link rel='stylesheet' href='/css/dydra.admin.css'>")
98
   (format stream "~%</head>")
99
   
100
   (format stream *html-body-prologue*)
101
   (format stream "~%<div id='main'>")
102
   
103
   (when body (funcall body stream))
104
   (format stream "~%</body>~%</html>"))
105
 
106
 (defun write-sparql-results-table (stream columns row-encoder)
107
   (let ((styles (task-property *task* :styles)))
108
     (format stream "~%<table class='admintable-striped table-hover tablesorter table-bordered table-sorter-bootstrap' role='grid'>~%<colgroup>")
109
     (format stream "~%<style type='text/css'><!-- ~{ ~{ td.~a { ~a }~}~} --></style>"
110
             (loop for column in columns
111
                   for style = (getf styles column)
112
                   when style collect (list column style)))
113
     (loop for column in columns
114
           for style = (getf styles column)
115
           do (format stream "~%<col ~@[style='~a'~]/>" style))
116
     (format stream "~%<col />~%</colgroup>")
117
     (format stream "~%<tr>")
118
     (loop for column in columns
119
           do (format stream "~%<th style='text-align: center;' class='tablesorder-header tablesorter-headerDesc bootstrap-header'>~a</th>" column))
120
     (format stream "~%</tr>")
121
     (funcall row-encoder stream)
122
     (format stream "~%</table>")))
123
 
124
 (defun write-query-parameter-form (stream parameters &key (submit "Refresh") (href "") (input nil))
125
   (format stream "
126
   <form href='~@[~a~]'>
127
     <div><input type='submit' value='~a'/></div>"
128
           href submit)
129
   (loop for (parameter value) on parameters by #'cddr
130
         do (case parameter
131
              (:end-time
132
               (format stream "~%~6t<div><label>end:</label><input type='text' name='end-time' value='~@[~a~]' style:'width: 20em;' /></div>"
133
                       (term-lexical-form value)))
134
              (:host
135
               (format stream "~%~6t<div><label>host:</label><select name='host' style:'position: absolute; right: 2px'>~{~{<option value='~a'~:[~; selected='selected'~]>~a</option>~}~}</select></div>"
136
                       (loop for host-spec in *html-host-properties*
137
                             collect (destructuring-bind (&key name hostname) host-spec
138
                                       (list hostname (equalp hostname value) name)))))
139
              (t
140
               (format stream "~%~6t<div><label>~a:</label><input type='text' name='~a' value='~@[~a~]' style:'width: 8em' /></div>"
141
                       (string-downcase parameter) parameter value))))
142
   (when input (funcall input stream))
143
   (format stream "~%</form>"))
144
              
145
 
146
 (defgeneric write-sparql-results+html+table (results stream)
147
   (:documentation "Encode the result field to the stream as a table in an html document.
148
  The results are one solutions per 'tr' element, with each binding in a 'td'.
149
  The first element is a 'hr', which specifies the variable names.
150
  If a string is blank, empty td element appears.")
151
   
152
   (:method ((result symbol) (stream t))
153
     (flet ((write-body (stream)
154
              (format stream "
155
 <div id='table_container'>
156
   <div style='display: inline-block; vertical-align: top; margin-top: 10px; margin-left: 10px; border: solid gray 1px;'>")
157
              (write-query-parameter-form stream (task-property *task* :query-parameters))
158
              (format stream "~%
159
   </div>
160
   <div style='display: inline-block; padding: 10px;'>
161
     <div id='table' style='display: inline-block; vertical-align: top;'>")
162
              (write-sparql-results-table stream
163
                                          '("result")
164
                                          #'(lambda (stream)
165
                                              (format stream "~%<tr><td>")
166
                                              (encode-csv-object result stream)
167
                                              (format stream "</td></tr>")))
168
              (format stream "~%</div>
169
   </div>
170
 </div>")))
171
       (write-sparql-results-html stream :body #'write-body))
172
     (terpri stream)
173
     (incf-stat *statements-returned*))
174
   
175
   (:method ((results list-solution-field) (stream t))
176
     (write-sparql-results+html+table (cons (solution-field-dimensions results)
177
                                            (solution-field-solutions results))
178
                                      stream))
179
 
180
   (:method ((results cons) (stream t))
181
     (let ((dimensions (first results))
182
           (solutions (rest results))
183
           (count 0))
184
       (flet ((write-body (stream)
185
                (format stream "
186
 <div id='table_container'>
187
   <style type='text/css'>
188
    <!-- label { display: inline-block; width: 80px; text-align: right; }-->
189
   </style>
190
   <div style='display: inline-block; vertical-align: top; margin: 10px; border: solid gray 1px;'>")
191
                (write-query-parameter-form stream (task-property *task* :query-parameters))
192
                (format stream "~%
193
   </div>
194
   <div style='display: inline-block; vertical-align: top; margin: 10px;'>
195
     <div id='table' style='display: inline-block; vertical-align: top;'>")
196
                (write-sparql-results-table stream
197
                                            dimensions
198
                                            #'(lambda (stream)
199
                                                (dolist (result solutions)
200
                                                  (format stream "~%<tr>")
201
                                                  (incf count)
202
                                                  (loop for value in result
203
                                                        for dimension in dimensions
204
                                                        do (progn (format stream "~%<td class='~a'>" dimension)
205
                                                                  (encode-csv-object value stream)
206
                                                                  (format stream "</td>")))
207
                                                  (format stream "~%</tr>"))))
208
                (format stream "
209
     </div>
210
   </div>
211
 </div>")))
212
         (write-sparql-results-html stream :body #'write-body))
213
       (terpri stream)
214
       (incf-stat *statements-returned* count)))
215
   
216
   (:method ((results boolean-generator) (stream t))
217
     (let* ((channel (boolean-generator-channel results)))
218
       (write-sparql-results-html stream
219
                                  :body #'(lambda (stream)
220
                                            (write-sparql-results-table stream
221
                                                                        '("result")
222
                                                                        #'(lambda (stream)
223
                                                                            (format stream "~%<tr><td>")
224
                                                                            (write-string (spocq:literal-lexical-form (if (get-field-page channel) spocq.a:|true| spocq.a:|false|))
225
                                                                                          stream)
226
                                                                            (format stream "</td></tr>")))))
227
       (terpri stream)
228
       (incf-stat *statements-returned*)))
229
   
230
   (:method ((results solution-generator) (stream t))
231
     (let* ((dimensions (solution-generator-dimensions results))
232
            (channel (solution-generator-channel results))
233
            (variable-count (length dimensions)))
234
       (write-sparql-results+html+table (cons dimensions
235
                                              (let ((solutions nil))
236
                                                (loop for page = (get-field-page channel)
237
                                                      until (null page)
238
                                                      do (if (= variable-count (array-dimension page 1))
239
                                                           (let ((solution-count (array-dimension page 0)))
240
                                                             (dotimes (page-index solution-count)
241
                                                               (push (loop for value-index from 0 below variable-count
242
                                                                           collect (let ((term-id (aref page page-index value-index)))
243
                                                                                     (unless (= term-id +null-term-id+)
244
                                                                                       (term-number-object term-id))))
245
                                                                     solutions)))
246
                                                           (log-warn "field width mismatch: ~s : ~s."
247
                                                                     dimensions (array-dimension page 1))))
248
                                                (nreverse solutions)))
249
                                        stream))))
250
 
251
 
252
 ;;;;;;;
253
 
254
 (defmethod send-response-message (operation (message-body t) (stream t)
255
                                             (content-type mime:application/VND.DYDRA.SPARQL-RESULTS+HTML+TABLE))
256
   "Given a MESSAGE, and a STREAM with the application/sparql-results+html+table CONTENT-TYPE,
257
  encode the results as a table in an html document."
258
   (when *encoding-trace-output*
259
     (setf stream (make-broadcast-stream *encoding-trace-output* stream)))
260
   (let ((*package* *spocq-reader-package*))
261
     (write-sparql-results+html+table message-body stream)))
262
 
263
 (defmethod send-response-message (operation (message-body t) (stream t) (content-type mime:text/html))
264
   "the default method generates a table"
265
   (send-response-message operation message-body stream mime:application/VND.DYDRA.SPARQL-RESULTS+HTML+TABLE))
266
 
267
 
268
 
269
 #|
270
 (let ((?::s '(:minimum 0 :maximum 10)))
271
   (declare (special ?::s))
272
   (send-response-message :test
273
                          '((?::a ?::s ?::z) (1 2 3) (<http://example/1> <http://example/2> <http://example/3>))
274
                          *trace-output*
275
                          mime:application/VND.DYDRA.SPARQL-RESULTS+HTML+TABLE))
276
 |#
277