Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/encoding/sparql-query-graphviz.lisp

KindCoveredAll%
expression01175 0.0
branch010 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
 ;;; (load #p"patches/graph.lisp")
3
 
4
 (in-package :org.datagraph.spocq.implementation)
5
 
6
 ;;; (load #p"LIBRARY:org;datagraph;spocq;src;core;encoding;graph.lisp")
7
 
8
 (:documentation "generate a visual graph of a query"
9
   "This is a simple recursive descent .dot generator based on the sse operators")
10
 
11
 (defgeneric graph-query (query destination &rest options)
12
   (:method ((query t) (destination pathname) &rest options)
13
     (with-open-file (stream destination :direction :output :if-exists :supersede :if-does-not-exist :create)
14
       (apply #'graph-query query stream options)))
15
   (:method ((query t) (destination stream) &rest options)
16
     (apply #'encode-graph query destination  mime:text/VND.DYDRA.SPARQL-QUERY-ALGEBRA+GRAPHVIZ
17
            options))
18
   (:method ((query string) (destination t) &rest options)
19
     (apply #'graph-query (parse-sparql query) destination options)))
20
 
21
 
22
 (defmethod context-encode-graph-as (context (task task) (as mime:graphviz))
23
   (context-graph-sse context (task-sse-expression task)))
24
 
25
 (defmethod context-encode-graph-as (context (query list) (as mime:graphviz))
26
   (context-graph-sse context query))
27
 
28
 (defmethod context-encode-graph-as (context (query null) (as mime:graphviz))
29
   nil)
30
 
31
 (defgeneric anonymize-graph-term (term)
32
   (:method ((object spocq:iri))
33
     (or (gethash object *graph-anonymous-map*)
34
         (setf (gethash object *graph-anonymous-map*) (spocq:make-iri (string (gensym "iri-"))))))
35
   (:method ((object string) )
36
     (or (gethash object *graph-anonymous-map*)
37
         (setf (gethash object *graph-anonymous-map*) (string (gensym "string-")))))
38
   (:method ((term t))
39
     term))
40
 
41
 (defun cl-user::format-graph-term (stream term &optional colon at)
42
   (declare (ignore colon at))
43
   (encode-graph-term term stream))
44
 
45
 (defgeneric encode-graph-term (term stream)
46
   (:method ((term spocq:iri) stream)
47
     (let ((q-name (iri-qname (puri:uri term)))
48
           (namestring (iri-lexical-form term)))
49
       (if q-name
50
           (write-string q-name stream)
51
           (format stream "<~/format-turtle-iri-namestring/>" namestring))))
52
   (:method ((term symbol) stream)
53
     (cond ((iri-p term)
54
             (let ((q-name (iri-qname (puri:uri term)))
55
                   (namestring (symbol-uri-namestring term)))
56
               (if q-name
57
                   (write-string q-name stream)
58
                   (format stream "<~/format-turtle-iri-namestring/>" namestring))))
59
           ((variable-p term)
60
            (format stream "?~a" term))
61
           (t
62
            (format stream "~a" term))))
63
   (:method ((term t) (stream t))
64
     (encode-turtle-object (if *graph-anonymous-map* (anonymize-graph-term term) term) stream))
65
   (:method ((term property-path) (stream t))
66
     (print-object term stream)))
67
 
68
 
69
 (defgeneric context-graph-sse-op (context operator arguments)
70
   (:documentation "Graph the expression operator given its arguments.")
71
   (:method ((context t) (operator (eql 'let)) parameters)
72
     (context-graph-sse context (third parameters)))
73
   (:method ((context t) (operator null) parameters)
74
     ))
75
 
76
 (defgeneric context-graph-sse (context query)
77
   (:method ((context t) (sse list))
78
     (context-graph-sse-op context (first sse) (rest sse))))
79
 
80
 #+(or)
81
 (defun graph-term-string (term)
82
   (let ((*encode-turtle-object-as-variable-p* t))
83
     (with-output-to-string (stream)
84
       (encode-graph-term term stream))))
85
 
86
 (defun graph-term-string (term)
87
   (graph-expression-string term))
88
 
89
 (defun graph-expression-string (expression)
90
   (let ((*encode-turtle-object-as-variable-p* t))
91
     (when expression
92
       (with-output-to-string (stream)
93
         (labels ((encode-expression (expression)
94
                    (typecase expression
95
                      (cons (case (first expression)
96
                              (spocq.a:|exprlist| (format-sparql-sse-expression stream expression))
97
                              (locally
98
                                (encode-expression (third expression)))
99
                              (t
100
                               (write-string "(" stream)
101
                               (loop for term in expression
102
                                 do (progn (write-char #\space stream)
103
                                      (encode-expression term)))
104
                               (write-string " )" stream))))
105
                      ((satisfies variable-p) (format stream "?~a" expression))
106
                      (symbol (format stream "~a" expression))
107
                      (t (encode-graph-term expression stream)))))
108
           (encode-expression expression))))))
109
 
110
 (defun test-expression-string (test-expression)
111
   (with-output-to-string (stream)
112
     (loop for char across (with-output-to-string (stream)
113
                             (case (first test-expression)
114
                               (spocq.a:|exprlist|
115
                                        (format stream "~{~/format-sparql-expression/~^ &&~}" (rest test-expression)))
116
                               (t (format stream "~/format-sparql-expression/"  test-expression))))
117
       with count = 0
118
       do (write-char char stream)
119
       do (case char
120
            ((#\& #\|)
121
             (when (= (incf count) 2)
122
               (setf count 0)
123
               (write-string "\\n" stream)))))))
124
 
125
 
126
 (defun graph-triple-string (s p o &rest properties)
127
   (declare (ignore properties))
128
   (let ((*encode-turtle-object-as-variable-p* t))
129
     (with-output-to-string (stream)
130
       (encode-graph-term s stream)
131
       (write-char #\space stream)
132
       (encode-graph-term p stream)
133
       (write-char #\space stream)
134
       (encode-graph-term o stream))))
135
 
136
 (defun graph-quad-string (s p o c &rest properties)
137
   (declare (ignore properties))
138
   (let ((*encode-turtle-object-as-variable-p* t))
139
     (with-output-to-string (stream)
140
       (encode-graph-term s stream)
141
       (write-char #\space stream)
142
       (encode-graph-term p stream)
143
       (write-char #\space stream)
144
       (encode-graph-term o stream)
145
       (write-char #\space stream)
146
       (encode-graph-term c stream))))
147
 
148
 
149
 (macrolet ((def-graph-method (operator lambda-list &body body)
150
              (let* ((body-non-decl (member 'declare body :test-not #'eq :key #'first))
151
                     (decls (ldiff body body-non-decl)))
152
                (declare (ignore decls))
153
                `(defmethod context-graph-sse-op ((context t) (operator (eql ',operator)) parameters)
154
                   (destructuring-bind ,lambda-list parameters
155
                     ,@body)))))
156
   ;; aggregate
157
 
158
   (def-graph-method spocq.a:|agp| (&rest triples)
159
     (let ((id (gensym "agp")))
160
       (encode-sparql-graph-node (id "agp")
161
         (ecase *graph-bgp-mode*
162
           (:graph-patterns
163
            (dot:context-put-node context id :label (format nil "agp~@[ @ ~/format-graph-term/~]~{\\n~a~}"
164
                                                            (second (assoc 'spocq.a:|graph| triples))
165
                                                            (mapcar #'(lambda (triple)
166
                                                                        (case (first triple)
167
                                                                          ((spocq.a:|triple| spocq.a:|quad|)
168
                                                                           (apply #'graph-triple-string (rest triple)))))
169
                                                                    triples))
170
                                  :shape "box"))
171
           (:triple-patterns
172
            (dot:context-put-node context id :label (format nil "agp~@[ @ ~/format-graph-term/~]"
173
                                                            (second (assoc 'spocq.a:|graph| triples))))
174
            (dolist (triple triples)
175
              (case (first triple)
176
                (spocq.a:|declare|)
177
                (spocq.a:|graph| )
178
                (spocq.a:|id|)
179
                ((spocq.a:|triple| spocq.a:|quad|)
180
                 (dot:context-put-edge context id (context-graph-sse context triple)
181
                                       :dir "back")))))))
182
       id))
183
 
184
   (def-graph-method spocq.a:|ask| (expression)
185
     (let ((id (gensym "ask")))
186
       (dot:context-put-node context id :label "ask")
187
       (dot:context-put-edge context id (context-graph-sse context expression))
188
       id))
189
 
190
   (def-graph-method spocq.e:ask (expression)
191
     (let ((id (gensym "ask")))
192
       (dot:context-put-node context id :label "ASK")
193
       (dot:context-put-edge context id (context-graph-sse context expression))
194
       id))
195
   
196
   
197
   (def-graph-method spocq.a:|bgp| (&rest triples)
198
     (let ((id (gensym "bgp")))
199
       (encode-sparql-graph-node (id "bgp")
200
         (ecase *graph-bgp-mode*
201
           (:node
202
            (dot:context-put-node context id :label (format nil "bgp~{\\n~a~}"
203
                                                            (remove-if #'undistinguished-variable-p (expression-variables triples)))))
204
           (:graph-patterns
205
            (dot:context-put-node context id :label (format nil "bgp~{\\n~a~}"
206
                                                            (mapcar #'(lambda (triple) (apply #'graph-triple-string (rest triple)))
207
                                                                    triples))
208
                                  :shape "box"))
209
           (:triple-patterns
210
            (dot:context-put-node context id :label "bgp")
211
            (dolist (triple triples)
212
              (case (first triple)
213
                ((spocq.a:|triple| spocq.a:|quad|)
214
                 (dot:context-put-edge context id (context-graph-sse context triple)
215
                                       :dir "back")))))))
216
       id))
217
 
218
   (def-graph-method spocq.a:|bindings| (expressions variables)
219
     (let ((id (gensym "bindings")))
220
       (encode-sparql-graph-node (id "values")
221
         (dot:context-put-node context id :label (format nil "bind (~{?~a~^ ~}) :~:[ ()~;~:*\\n(~{(~{~/format-graph-term/~^ ~})~^\\n ~})~]"
222
                                                         variables
223
                                                         (typecase expressions
224
                                                           (list expressions)
225
                                                           (array (loop for i from 0 below (array-dimension expressions 0)
226
                                                                    collect (loop for j from 0 below (array-dimension expressions 1))))))))
227
       id))
228
   (def-graph-method spocq.e:bindings (expressions variables)
229
     (context-graph-sse context `(spocq.a:|bindings| ,(second expressions) ,(second variables))))
230
 
231
   ;; bindings
232
   ;; clear
233
   (def-graph-method spocq.a:|construct| (solution-field triples &optional continuation)
234
     (declare (ignore continuation))
235
     (let ((id (gensym "construct"))
236
           (*print-pretty* nil))
237
       (encode-sparql-graph-node (id "construct")
238
         (dot:context-put-node context id :label (format nil "construct~{\\n~a~}"
239
                                                         (mapcar #'(lambda (stmt)
240
                                                                     (case (first stmt)
241
                                                                       (spocq.a:|triple| (apply #'graph-triple-string (rest stmt)))
242
                                                                       (spocq.a:|quad| (apply #'graph-quad-string (rest stmt)))))
243
                                                                 triples))
244
                               :shape "box"))
245
       #+(or)
246
       (if (> (length triples) 1)
247
         (dot:context-put-node context id :label (format nil "construct (~{~%  ~a~})" triples))
248
         (dot:context-put-node context id :label (format nil "construct (~{\\n  ~a~})" triples)))
249
       (dot:context-put-edge context id (context-graph-sse context solution-field)
250
                             :dir "back")
251
       id))
252
 
253
   (def-graph-method spocq.e:construct (solution-field triples)
254
     (let ((id (gensym "CONSTRUCT"))
255
           (*print-pretty* nil))
256
       (when (eq (first triples) 'quote)
257
         (setf triples (second triples)))
258
       (encode-sparql-graph-node (id "CONSTRUCT")
259
         (dot:context-put-node context id :label (format nil "CONSTRUCT~{\\n~a~}"
260
                                                         (mapcar #'(lambda (stmt)
261
                                                                     (case (first stmt)
262
                                                                       (spocq.a:|triple| (apply #'graph-triple-string (rest stmt)))
263
                                                                       (spocq.a:|quad| (apply #'graph-quad-string (rest stmt)))))
264
                                                                 triples))
265
                               :shape "box"))
266
       #+(or)
267
       (if (> (length triples) 1)
268
         (dot:context-put-node context id :label (format nil "construct (~{~%  ~a~})" triples))
269
         (dot:context-put-node context id :label (format nil "construct (~{\\n  ~a~})" triples)))
270
       (dot:context-put-edge context id (context-graph-sse context solution-field)
271
                             :dir "back")
272
       id))
273
 
274
   ;; deleteData
275
   ;; deleteWhere
276
   
277
   (def-graph-method spocq.a:|describe| (solution-field subjects &optional continuation)
278
     (declare (ignore continuation))
279
     (let ((id (gensym "describe")))
280
       (encode-sparql-graph-node (id "describe")
281
         (dot:context-put-node context id :label (format nil "describe ~a" subjects)))
282
       (dot:context-put-edge context id (context-graph-sse context solution-field)
283
                             :dir "back")
284
       id))
285
   
286
   (def-graph-method spocq.a:|diff| (solution-field1 solution-field2 test-expression)
287
     (let ((id (gensym "diff")))
288
       (encode-sparql-graph-node (id "diff")
289
         (dot:context-put-node context id :label (format nil "diff ~a" (graph-expression-string test-expression))))
290
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
291
                             :dir "back")
292
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
293
                             :dir "back")
294
       id))
295
   
296
   (def-graph-method spocq.a:|distinct| (solution-field &key count end offset start)
297
     (declare (ignore count end offset count start))
298
     (let ((id (gensym "distinct")))
299
       (encode-sparql-graph-node (id "distinct")
300
         (dot:context-put-node context id :label "distinct"))
301
       (dot:context-put-edge context id (context-graph-sse context solution-field)
302
                             :dir "back")
303
       id))
304
 
305
   (def-graph-method spocq.e:distinct (solution-field &rest args)
306
     (context-graph-sse context `(spocq.a:|distinct| ,solution-field ,@args)))
307
 
308
   ;; drop
309
   (def-graph-method spocq.a:|extend| (solution-field variable expression)
310
     (let ((id (gensym "extend")))
311
       (encode-sparql-graph-node (id "extend")
312
         (dot:context-put-node context id :label (format nil "extend ?~a :\\n ~a"
313
                                                         variable
314
                                                         (graph-expression-string expression))))
315
       (dot:context-put-edge context id (context-graph-sse context solution-field)
316
                             :dir "back")
317
       id))
318
 
319
   (def-graph-method spocq.e:extend (solution-field bindings)
320
     (let ((id (gensym "extend")))
321
       (encode-sparql-graph-node (id "extend")
322
         (dot:context-put-node context id :label (format nil "extend (~{(~{?~a ~a~})~^\\n        ~})"
323
                                                         (loop for (variable expression) in (second bindings)
324
                                                           collect (list variable (graph-expression-string expression))))))
325
       (dot:context-put-edge context id (context-graph-sse context solution-field)
326
                             :dir "back")
327
       id))
328
   
329
   (def-graph-method spocq.a:|filter| (solution-field test-expression &key offset count)
330
     (declare (ignore offset count))
331
     (let ((id (gensym "filter")))
332
       (encode-sparql-graph-node (id "filter")
333
         (let ((constraint (test-expression-string test-expression)))
334
           (dot:context-put-node context id :label (format nil "filter (~a)" constraint))))
335
       (dot:context-put-edge context id (context-graph-sse context solution-field)
336
                             :dir "back")
337
       id))
338
   (def-graph-method spocq.e:filter (solution-field test-expression &rest args)
339
     (context-graph-sse context `(spocq.a:|filter| ,solution-field ,(second test-expression) ,@args)))
340
   
341
   (def-graph-method spocq.a:|graph| (name group-graph-pattern)
342
     (let ((id (gensym "graph")))
343
       (encode-sparql-graph-node (id "graph")
344
         (dot:context-put-node context id :label (format nil "graph ~a" (graph-term-string name))))
345
       (dot:context-put-edge context id (context-graph-sse context group-graph-pattern)
346
                             :dir "back")
347
       id))
348
 
349
   ;; group
350
   
351
   (def-graph-method spocq.a:|join| (solution-field1 solution-field2 &key offset count)
352
     (declare (ignore offset count))
353
     (let ((id (gensym "join")))
354
       (encode-sparql-graph-node (id "join")
355
         (dot:context-put-node context id :label "join"))
356
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
357
                             :dir "back")
358
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
359
                             :dir "back")
360
       id))
361
 
362
   (def-graph-method spocq.e:join (solution-field1 solution-field2 &key test offset count)
363
     (declare (ignore offset count))
364
     (let ((id (gensym "join"))
365
           (constraint (when test (test-expression-string test))))
366
       (encode-sparql-graph-node (id "join")
367
         (dot:context-put-node context id :label (if constraint (format nil "join (~a)" constraint) "join")))
368
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
369
                             :dir "back")
370
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
371
                             :dir "back")
372
       id))
373
 
374
   (def-graph-method spocq.a:|leftjoin| (solution-field1 solution-field2 &key test offset count)
375
     (declare (ignore offset count))
376
     (let ((id (gensym "leftjoin")))
377
       (encode-sparql-graph-node (id "leftjoin")
378
         (dot:context-put-node context id :label (format nil "leftjoin~@[ ~a~]" (graph-expression-string test))))
379
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
380
                             :dir "back")
381
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
382
                             :dir "back")
383
       id))
384
   (def-graph-method spocq.e:leftjoin (solution-field1 solution-field2 &rest args)
385
     (context-graph-sse context `(spocq.a:|leftjoin| ,solution-field1 ,solution-field2 ,@args)))
386
 
387
   ;; load
388
   (def-graph-method spocq.a:|minus| (solution-field1 solution-field2 &key offset count)
389
     (declare (ignore offset count))
390
     (let ((id (gensym "minus")))
391
       (encode-sparql-graph-node (id "minus")
392
         (dot:context-put-node context id :label "minus"))
393
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
394
                             :dir "back")
395
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
396
                             :dir "back")
397
       id))
398
 
399
   ;; modify
400
 
401
   (def-graph-method spocq.a:|null| (dimensions)
402
     (let ((id (gensym "null")))
403
       (encode-sparql-graph-node (id "null")
404
         (dot:context-put-node context id :label (format nil "null ~a" dimensions)))
405
       id))
406
   
407
   (def-graph-method spocq.a:|order| (solution-field order-expression-list)
408
     (let ((id (gensym "order")))
409
       (encode-sparql-graph-node (id "order")
410
         (dot:context-put-node context id :label (format nil "order ~a" order-expression-list)))
411
       (dot:context-put-edge context id (context-graph-sse context solution-field)
412
                             :dir "back")
413
       id))
414
   
415
   (def-graph-method spocq.a:|project| (solution-field variables &key offset count)
416
     (declare (ignore offset count))
417
     (let ((id (gensym "project")))
418
       (dot:context-put-node context id :label (format nil "project ~a" variables))
419
       (dot:context-put-edge context id (context-graph-sse context solution-field)
420
                             :dir "back")
421
       id))
422
 
423
   (def-graph-method spocq.e:project (solution-field variables &rest args)
424
     (context-graph-sse context `(spocq.a:|project| ,solution-field ,(second variables) ,@args)))
425
 
426
   (def-graph-method spocq.a:|quad| (s p o c &rest properties)
427
     (declare (ignore properties))
428
     (let ((id (gensym "triple")))
429
       (dot:context-put-node context id :label (format nil "(~a)" (graph-quad-string s p o c)))
430
       id))
431
   
432
   (def-graph-method spocq.a:|reduced| (solution-field &key offset count)
433
     (declare (ignore offset count))
434
     (let ((id (gensym "reduced")))
435
       (encode-sparql-graph-node (id "reduced")
436
         (dot:context-put-node context id :label "reduced"))
437
       (dot:context-put-edge context id (context-graph-sse context solution-field)
438
                             :dir "back")
439
       id))
440
   
441
   ;; replace
442
   (def-graph-method spocq.a:|select| (solution-field variables &optional continuation)
443
     (declare (ignore continuation))
444
     (let ((id (gensym "select")))
445
       (encode-sparql-graph-node (id "select")
446
         (dot:context-put-node context id :label (format nil "select ~a" (mapcar #'graph-term-string variables)) :shape "box"))
447
       (dot:context-put-edge context id (context-graph-sse context solution-field)
448
                             :dir "back")
449
       id))
450
   
451
   (def-graph-method spocq.a:|service| (name group-graph-pattern &rest args)
452
     (if (symbolp (first args)) ;; ignore text
453
         (let ((id (gensym "service"))
454
               (endpoint-id (gensym "endpoint")))
455
           (encode-sparql-graph-node (id "service")
456
             (dot:context-put-node context id :label (format nil "service ~a" (graph-term-string name))))
457
           (dot:context-put-node context endpoint-id :label (graph-term-string name) :color "red")
458
           (dot:context-put-edge context id (context-graph-sse context group-graph-pattern)
459
                                 :dir "back")
460
           (dot:context-put-edge context id endpoint-id :style "dashed" :dir "both")
461
           id)
462
         ;; allow both as service form
463
         (context-graph-sse context
464
                            `(spocq.a:|servicejoin| ,name ,group-graph-pattern ,@args))))
465
   (def-graph-method spocq.e:service (name group-graph-pattern &rest args)
466
     (context-graph-sse context `(spocq.a:|service| ,(second name) ,(second group-graph-pattern) ,@args)))
467
 
468
   (def-graph-method spocq.a:|servicejoin| (name group-graph-pattern source-graph-pattern &rest args)
469
     (declare (ignore args))
470
     (print (list name group-graph-pattern source-graph-pattern))
471
     (let ((id (gensym "service"))
472
           (endpoint-id (gensym "endpoint")))
473
       (encode-sparql-graph-node (id "service")
474
                                 (dot:context-put-node context id :label (format nil "servicejoin ~a" (graph-term-string name))))
475
       (dot:context-put-node context endpoint-id :label (graph-term-string name) :color "red")
476
       (dot:context-put-edge context id (context-graph-sse context group-graph-pattern)
477
                             :dir "back")
478
       (dot:context-put-edge context id (context-graph-sse context source-graph-pattern)
479
                             :dir "back")
480
       (dot:context-put-edge context id endpoint-id :style "dashed" :dir "both")
481
       id))
482
   (def-graph-method spocq.e:service-join (name group-graph-pattern source-graph-pattern &rest args)
483
     (context-graph-sse context `(spocq.a:|servicejoin| ,(second name) ,(second group-graph-pattern) ,source-graph-pattern ,@args)))
484
 
485
   (def-graph-method spocq.a::|serviceleftjoin| (name group-graph-pattern source-graph-pattern &rest args)
486
     (declare (ignore args))
487
     (print (list name group-graph-pattern source-graph-pattern))
488
     (let ((id (gensym "service"))
489
           (endpoint-id (gensym "endpoint")))
490
       (encode-sparql-graph-node (id "service")
491
                                 (dot:context-put-node context id :label (format nil "serviceleftjoin ~a" (graph-term-string name))))
492
       (dot:context-put-node context endpoint-id :label (graph-term-string name) :color "red")
493
       (dot:context-put-edge context id (context-graph-sse context group-graph-pattern)
494
                             :dir "back")
495
       (dot:context-put-edge context id (context-graph-sse context source-graph-pattern)
496
                             :dir "back")
497
       (dot:context-put-edge context id endpoint-id :style "dashed" :dir "both")
498
       
499
       id))
500
   (def-graph-method spocq.e::service-leftjoin (name group-graph-pattern source-graph-pattern &rest args)
501
     (context-graph-sse context `(spocq.a::|serviceleftjoin| ,(second name) ,(second group-graph-pattern) ,source-graph-pattern ,@args)))
502
 
503
   (def-graph-method spocq.a:|slice| (expression &key offset count)
504
     (let ((id (gensym "select")))
505
       (encode-sparql-graph-node (id "select")
506
         (dot:context-put-node context id :label (format nil "slice (~a x ~a)" offset count)))
507
       (dot:context-put-edge context id (context-graph-sse context expression)
508
                             :dir "back")
509
       id))
510
   
511
   (def-graph-method spocq.a:|table| (&optional dimensions)
512
     (let ((id (gensym "table")))
513
       (encode-sparql-graph-node (id "table")
514
         (dot:context-put-node context id :label (format nil "table~@[ ~a~]" dimensions)))
515
       id))
516
   
517
   (def-graph-method spocq.a:|to-list| (solution-field)
518
     (let ((id (gensym "to-list")))
519
       (encode-sparql-graph-node (id "to-list")
520
         (dot:context-put-node context id :label "to-list"))
521
       (dot:context-put-edge context id (context-graph-sse context solution-field))
522
       id))
523
   
524
   (def-graph-method spocq.a:|triple| (s p o &rest properties)
525
     (declare (ignore properties))
526
     (let ((id (gensym "triple")))
527
       (encode-sparql-graph-node (id "triple")
528
         (dot:context-put-node context id :label (format nil "(~a)" (graph-triple-string s p o))))
529
       id))
530
   
531
   (def-graph-method spocq.a:|union| (solution-field1 solution-field2)
532
     (let ((id (gensym "union")))
533
       (encode-sparql-graph-node (id "union")
534
         (dot:context-put-node context id :label "union"))
535
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
536
                             :dir "back")
537
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
538
                             :dir "back")
539
       id))
540
 
541
   (def-graph-method spocq.e:union (solution-field1 solution-field2)
542
     (let ((id (gensym "union")))
543
       (encode-sparql-graph-node (id "UNION")
544
         (dot:context-put-node context id :label "UNION"))
545
       (dot:context-put-edge context id (context-graph-sse context solution-field1)
546
                             :dir "back")
547
       (dot:context-put-edge context id (context-graph-sse context solution-field2)
548
                             :dir "back")
549
       id))
550
   ;; update
551
   (def-graph-method spocq.e::with-join-scope (scope expression)
552
     (declare (ignore scope))
553
     (context-graph-sse context expression))
554
   )