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

KindCoveredAll%
expression50125 40.0
branch46 66.7
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
 ;;; ld+json serializer
6
 ;;; http://www.ietf.org/rfc/rfc4627.txt
7
 ;;;
8
 ;;; note that the json-ld serialization recommendation describes three profile indicators
9
 ;;; (http://www.w3.org/TR/json-ld/#iana-considerations), the namespace vocabulary
10
 ;;; (http://www.w3.org/ns/json-ld) includes single-term combinations
11
 
12
 ;;; no reading
13
 
14
 (defgeneric write-sparql-results+json-ld (results stream frame &rest args)
15
   (:documentation "Encode the result field to the stream as ld+json.
16
  The results are one of
17
  - a solution generator
18
  - a solution field instance, which comprises dimensions and a list of lists.
19
  - an s-expression, wihc is interpreted as a query.")
20
   
21
   (:method ((results symbol) (stream t) (frame t) &rest args)
22
     "Given a boolean, emit a simple json result"
23
     (declare (ignore args))
24
     (write-sparql-results+json results stream))
25
   
26
   (:method ((query cons) (stream t) (frame t) &rest args)
27
     "Given an s-expression, delegate to frame-sparql, !!!which interprets it as a query!!!"
28
     (declare (dynamic-extent args))
29
     (apply #'frame-sparql query frame :stream stream args))
30
   
31
   (:method ((results boolean-generator) (stream t) (frame t) &rest args)
32
     "Given a boolean, emit a simple json result"
33
     (declare (ignore args))
34
     (write-sparql-results+json results stream))
35
   
36
   (:method ((results solution-generator) (stream t) (frame json-ld:frame) &rest args)
37
     (declare (dynamic-extent args))
38
     (apply #'frame-sparql results frame :stream stream args))
39
 
40
   (:method ((results list-solution-field) (stream t) (frame json-ld:frame) &rest args)
41
     "Given a symbolic solution field, fabricate a query context, interpose
42
      a bindings clause and serialize it as the result.
43
      The query context is constructed to target system/null with a select
44
      operation in order to provide the read-only transaction for term interning."
45
     (declare (dynamic-extent args))
46
     (flet ((run-bindings-thread (result-channel solutions dimensions)
47
              (let ((*thread-operations* (cons (list 'spocq.a:|bindings| solutions dimensions)
48
                                               *thread-operations*)))
49
                (process-bindings result-channel solutions dimensions)
50
                'spocq.a:|bindings|)))
51
       (let* ((dimensions (solution-field-dimensions results))
52
              ;; need the task transaction context in order to intern any new terms
53
              (task (or *task*
54
                        (make-query :repository-id "system/null"
55
                                    :sse-expression `(spocq.a:|select| nil ,dimensions))))
56
              (result-channel (make-channel :name (list 'spocq.a:|bindings| (task-id task))
57
                                            :dimensions dimensions
58
                                            :size *channel-sliced-size-limit*))
59
              (generator-expression (list #'run-bindings-thread result-channel
60
                                          (solution-field-solutions results)
61
                                          dimensions))
62
              (generator (make-solution-generator :operator 'spocq.a:|bindings|
63
                                                  :dimensions dimensions
64
                                                  :expression generator-expression
65
                                                  :channel result-channel
66
                                                  :constituents ())))
67
         
68
         (query-run-in-thread task generator-expression)
69
         (apply #'frame-sparql generator frame :stream stream args))))
70
 
71
   (:method ((result-field t) (stream t) (frame t) &rest args)
72
     "For an unexpected field type, just warn and ignore it"
73
     (declare (ignore args))
74
     (log-warn "NYI: write-sparql-results+json-ld: ~s."
75
               (type-of result-field)))
76
   )
77
 
78
 #+(or) ;; test emitting json-ld from a symbolic field
79
 (let ((id (intern-uuid (dydra:make-task-id))))
80
   (write-sparql-results+json-ld
81
    (spocq.i::make-list-solution-field
82
     :dimensions spocq.i::*construct-dimensions*
83
     :solutions `((,id |as|:|id| ,id)
84
                  (,id |rdf|:|type| |as|:|Update|)))
85
    *trace-output*
86
     (json-ld:make-frame json-ld:*context*)))
87
 
88
 ;;;
89
 ;;;
90
 
91
 
92
 (defmethod send-error-message ((body t) (stream t) (content-type mime:application/ld+json))
93
   "Send an error response encoded as xml"
94
   (send-error-message body stream mime:application/sparql-query+sse))
95
 
96
 ;;; need to handle profile http://www.w3.org/ns/json-ld#context == |json-ld|:|context|
97
 
98
 (defmethod send-response-message ((operation t) (message t) (stream stream) (content-type mime:application/ld+json))
99
   "Given a MESSAGE, and a STREAM with the application/ld+json CONTENT-TYPE, encode the content as json-ld.
100
    Permit either solution field or graph content - as distinguished from the field dimensions.
101
 
102
    Extract configuration from the media type to override any global configuration
103
    See https://www.w3.org/TR/json-ld-syntax/#iana-considerations "
104
   (when *encoding-trace-output*
105
     (setf stream (make-broadcast-stream *encoding-trace-output* stream)))
106
   ;; extract parameters
107
   (let* ((frame (json-ld:make-frame json-ld:*context*))
108
          (compact (cond ((or (mime-type-profile-p content-type |json-ld|:|compacted|)
109
                              (mime-type-profile-p content-type |json-ld|:|compacted-flattened|))
110
                          t)
111
                         ((or (mime-type-profile-p content-type |json-ld|:|expanded|)
112
                              (mime-type-profile-p content-type |json-ld|:|expanded-flattened|))
113
                          nil)
114
                         (t json-ld:*compact*)))
115
          (embed (cond ((or (mime-type-profile-p content-type |json-ld|:|flattened|)
116
                            (mime-type-profile-p content-type |json-ld|:|compacted-flattened|)
117
                            (mime-type-profile-p content-type |json-ld|:|expanded-flattened|))
118
                        nil)
119
                       (t json-ld:*embed*))))
120
     (log-notice "send-response-message: (json-ld) ~s compact ~s embed ~s"
121
                 (mime-type-namestring content-type)
122
                 compact embed)
123
     (write-sparql-results+json-ld message stream frame
124
                                   :compact compact
125
                                   :embed embed)))