Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/ssl/ssl-api.lisp
| Kind | Covered | All | % |
| expression | 0 | 169 | 0.0 |
| branch | 0 | 10 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- package: org.dataagraph.spocq.implementation -*-
3
;;; spocq runtime query processor implementation as an interpreter for
4
;;; concrete and abstract model combinations
6
;;; (load (compile-file "/opt/spocq/patches/ssl-api.lisp"))
8
;;; see file:///Development/Downloads/VOWL/WebVOWL_Single_Ont/webvowl.html
9
;;; for the ontology diagram generator
11
;;; http : http://www.w3.org/TR/HTTP-in-RDF10
12
;;; http-headers : http://www.w3.org/2011/http-headers
17
the current query implementation includes a simple control structure and a very limited
19
the control structure is a data-flow network which is constructed by a reduction combination
21
if the algebra operations are abstracted into two classes:
23
- combine (arity 0 -- 2 operators)
27
- match : (quad-field x quad-pattern) -> solution-field
28
- combine : (operator x solution-field* ) -> solution-field
29
- modify : (operator x quad-field x solution-field*) -> quad-field
30
includes an implicit data commission step
31
- encode [emit a field to a destination] : (solution-field x media-type) -> (media-stream) -> t
32
- decode [receive a query from a source] : (media-stream x media-type) -> query
33
- project : (query) -> (quad-field) -> solution-field
35
the standard operation, as implemented, is
37
request (media-stream x media-stream x media-type x media-type x quad-field)
39
which the current version expresses as the operator
41
pipe-query (input-source output-destination
43
repository-id revision-id
44
response-content-type request-content-type)
46
of which the repository-id and revision-id designate the quad-field
48
and implements the control flow as the fixed form combination
50
(respond-to-request (make-query (receive-message input-source request-content-type)
51
:repository repository-id
52
:revision-id revision-id
53
:response-content-type response-content-type)
56
that combination parses the query from the input stream, instantiates a task which binds the dataset and response
57
content type, distributes the query processing across per-node threads, and emits the collected result to
58
the destination stream.
59
this suffices for simple sparql processing, but not to accomplish anything other than a direct data flow
60
from one the source and back.
62
in active development and production environments, however essential a black box
63
which emits data streams encoded as
64
application/rdf+xml and application/sparql-results may be, it fails to provide numerous
65
essential capabilities:
67
- provide notification of repository modification
68
- provide those changes selectively with respect to content and/or destination
69
- provide introspective statistics as to processing resources
70
- enforce constraints on repository modifications
71
- augment repository modifications
72
- enforce contraints on query patterns
73
- augment query patterns
74
- perform one query or update step contingent on the result of some initial step
75
- share a result stream between multiple successive stept
76
- consolidate result streams in a single step.
78
in general, permit more general data flow combinations among more capable operations than just a
80
match - project - encode
84
the closed process restricts operations on the intermediate results and allows no alternative,
85
whether for introspective analysis or to provide data to additional detinations and it has no allowance
86
for additional steps, such as augmenting the entailment process
87
or constraining the state of the store subsequent to an update.
88
sparql processing environments have taken to either supporting additional processing
89
instructions in-line as annotations to the query document,
90
introducing support elsewhere in the processing stack for processors which are embedded
91
in a language such as java (for Sesame or Jena), c# (for dotnetrdf) or ruby (for rdf.rb),
92
or by integrating query processing into a larger application framework, as in rdf pipes[1] or dapaas[2].
95
in oder to reduce application complexity, this implementation proposes to retain
96
the simple request-response interface of an http-based web service, but to permit
97
the application to compose request processors from a broader range of constituent steps
98
in combinations other than just piped sequences.
100
as the base, a set of atomic operators implements the individual steps essential to process a query
101
and adds several to provide capabilities absent from a standard sparql process:
103
- decode : (stream x media type) -> query + quad-field + solution-field
104
parse a an encoded document from a media-stream.
105
as standard, the standard operator supports application/sparql-query and application/sparql-update
106
and produces a query form
107
in addition, it supports alternative query expressions, such as sse and cascalog,
108
with the same result, as well as graph representations, such a application/rdf+xml and application/n-triples,
109
in order to permit graph sources, and application/sparql-results, in order to composes
112
- matcher : (method x quad-field) -> matcher
113
marshall rules from a dataset to be used to bind a query
115
- bind : (query x quad-field x method) -> query
116
combine matching inference rules (as the theory quad field) with a dataset
117
(as the assertion quad field) to bind a query to the dataset
118
either by modifying its patterns statically or preparing the rules to be applied
119
when the query executes
121
- notify : (query x quad-field) -> (media-stream) -> query
122
generate and emit results to an arbitrary destination in the course of query processing
124
- project : (query x quad-field) -> solution-field
125
combine the bound query patterns and algebra reduction graph with a quad field to
126
either yield a solution field/graph or project the solutions back into the original quad field.
128
- commit : (quad-field) -> quad-field
129
commit quad field changes to persistent storage
131
- encode-result : ((solution-field + quad-field) x stream x media type) -> (solution-field + quad-field)
132
combine a solution/graph field with a media type to emit the encoded results a media stream
134
- constrain (query x quad-field) -> quad-field
135
use a query to determine whether to continue processing or abort it
137
control-flow operators allow processing patterns in addition to pipelines
139
- if : (solution-field x code x code)
140
execute the consequent or alternative operations dependent on the solution field state:
141
a null field is false and otherwise true
143
- when : (solution-field x code)
144
execute the consequent operations when the solution field is true
146
- not : (solution-field)
147
invert the solution field state. a null field yields a unit field, otherwise a null field.
149
- continue : (query + source)
150
continue processing with the given query applied with the current agent and repository
152
higher-level operations encapsulate elementry sequences and manage completion
158
- import : (quad-field x quad-field)
159
a simplified equivalent to a sparql load which obeys the graph store protocol
160
with respect to HTTP method and resource designators.
163
a simplified equivalent to a sparql wild-card select which obeys the graph store protocol
164
with respect to HTTP method and resource designators.
167
the operations accept data of the folowing types
177
logical-source (request stream, response stream)
181
the abstract queries are represented as RDF graphs and compiled into
182
operation scripts for execution.
183
In order to facilitate composition, the execution model combines a global environment
184
for configuration settings with an execution stack
185
operators extract thei arguments from the stack and deposit reults upon completion.
187
see the doc;rquest-schema; directory for examples.
189
a simple query specifies just the text and relies on the request environment to specify
190
the dataset, decoding and encoding media types, and the result destination
192
(<ssl:name> "Simple Query"
194
(<ssl:location> "select * where {?s ?p ?o}"
201
in order to introduce entailment, the process specifies an alternative matching
202
method, in the form of a dataset and entailment mechanism. these are integrated into
203
the query statically as modification to its graph patterns.
204
this is the approach of implementation such as jena.
206
(<ssl:name> "Simple Query"
208
(<ssl:location> "select * where {?s ?p ?o}"
210
<ssl:dataset> <ssl:location> _:requestRepository <ssl:Dataset>
211
<ssl:method> <ssl:method> <urn:dydra:RIFCore> <ssl:dataset> _:ontologyRepository <ssl:Matcher>
217
alternatively, the request could specify to delay the effect of the entailment regime as as to apply it
218
dynamically during execution:
220
(<ssl:name> "Simple Query"
222
(<ssl:location> "select * where {?s ?p ?o}"
225
<ssl:dataset> <ssl:location> _:requestRepository <ssl:Dataset>
226
<ssl:method> <ssl:method> <urn:dydra:RIFCore> <ssl:dataset> _:ontologyRepository <ssl:Matcher>
230
;;; both approaches share the advantage, that modifications to the concrete dataset do not
231
;;; invalidate the ontological dataset state, but the static approach is unable to
232
;;; implement unbounded inference, as its modifications are finite.
240
;;; abstract operator classes
242
(defclass |ssl|:|Operation| (ssl:word)
244
(:metaclass c2mop:funcallable-standard-class))
246
(defclass |ssl|:|Composition| (|ssl|:|Operation|)
248
(:metaclass c2mop:funcallable-standard-class))
251
;;; operator api definitions
253
(ssl:defword |ssl|:|Abort| (&key transaction dataset)
254
(:documentation "Abort the given transaction.
255
If either no transaction exists, or the current transactionis no longer active, the operation
257
The default transaction is the thread's current transaction.
258
Returns the transaction.")
259
(:values (or transaction null))
260
(:generic-function-class |ssl|:|Operation|)
262
(:method (&key (transaction *transaction* t-s) dataset)
263
;; if a dataset or a list is specified, operate on the respective transactions
264
;; otherwise on the given transaction or the current one
265
;; if none is present or both arguments are supplied, signal an error.
267
(if (and t-s transaction)
268
(invalid-argument-type |ssl|:|Abort| dataset null)
269
(ssl::abort-transaction dataset))
271
(ssl::abort-transaction transaction)
272
(invalid-argument-type |ssl|:|Abort| transaction transaction)))))
275
(ssl:defword |ssl|:|Begin| (&key task dataset)
276
(:documentation "Begin a new transaction for the given dataset in the active thread.
277
If a transaction is already active, shadow it with the new transaction.
278
The default dataset is the thread's current dataset.
280
(:values transaction)
281
(:generic-function-class |ssl|:|Operation|)
283
(:method (&key (task *task*) (dataset *repository*))
284
(ssl::begin-transaction task dataset)))
287
(ssl:defword |ssl|:|Bind| (projection &key dataset method)
288
(:documentation "Given a task, bind it with an execution plan to the given data set.
289
For a query, this includes using a particular matching approach and secondary assertions
290
to compile the query such that the graph patterns effect a particular entailment regime.
291
(see http://www.w3.org/TR/sparql11-entailment/)
292
Iff no transaction is active for the given dataset, begin a new one.
293
The default data set is the thread's current dataset.
294
The default matching method is the d-entailment logic (<http://www.w3.org/ns/entailment/D>)
295
implicit in simple quad pattern matching.
296
The alternative the binding mechanims permits also
298
- <http://www.w3.org/ns/entailment/D> : Datatype entailment, which recognizes the numeric class hierarchy
299
- <urn:dydra:RIFCore> : simple inference based on SPIN definitions in an additional repository ;
300
(see http://spinrdf.org/spin.html)
302
Returns the bound query.")
304
(:generic-function-class |ssl|:|Operation|)
306
(:method ((task task) &key (dataset (task-revision task) d-s) (method nil))
307
(when (and d-s (task-revision task))
308
(assert (eql (task-revision task) dataset) ()
309
"Task repository incompatible: ~s != ~s" (task-revision task) dataset))
310
(ssl::bind-task task dataset method)))
313
(ssl:defword |ssl|:|Commit| (&key transaction dataset)
314
(:documentation "Commit the given transaction (by default, the thread's current transaction).
315
If either no transaction exists, or the current transactionis no longer active, the operation
317
Alternatively supply a dataset or a list to arrange that all are committed inone operation.
318
The default transaction is the thread's current transaction.
319
Returns the transaction.")
320
(:values transaction)
321
(:generic-function-class |ssl|:|Operation|)
323
(:method (&key (transaction *transaction* t-s) dataset)
324
;; if a dataset or a list is specified, operate on the respective transactions
325
;; otherwise on the given transaction or the current one
326
;; if none is present or both arguments are supplied, signal an error.
328
(if (and t-s transaction)
329
(invalid-argument-type |ssl|:|Commit| dataset null)
330
(ssl::commit-transaction dataset))
332
(ssl::commit-transaction transaction)
333
(invalid-argument-type |ssl|:|Commit| transaction transaction)))))
336
(ssl:defword |ssl|:|Compose| (&code steps)
337
(:documentation "A generic composition just executes the given steps.
338
The state values are those of the current thread context.
339
Returns the result of the last step.")
340
(:generic-function-class |ssl|:|Composition|)
343
(ssl::compose steps)))
346
(ssl:defword |ssl|:|Conditional| (value &code consequent alternative)
347
(:documentation "Given a predicate value and consequent and alternative plans,
348
continue execution in the current dynamic context with one or the other depending on the give value.
349
Iff the value is a logical true (non-zero, non-empty solution field, boolean true, non-empty string, etc),
350
execute the consequent plan. Otherwise perform the alternative. If the respective clause is <rdf:nil>,
352
Delegates to ssl:if, which yields the value of the respective plan.")
355
(:method ((value t) consequent alternative)
356
(ssl::conditional value
357
(unless (eq consequent |rdf|:|nil|) consequent)
358
(unless (eq alternative |rdf|:|nil|) alternative))))
361
(ssl:defword |ssl|:|Constrain| (&code steps &key dataset source name)
362
(:documentation "A contrain plan is a query which is not intended to encode results as a response,
363
but rather leave them active for subsequent conditional execution")
364
(:values solution-field)
365
(:generic-function-class |ssl|:|Composition|)
367
(:method ((steps list) &rest args)
368
(declare (dynamic-extent args))
369
(apply #'ssl::constrain steps args)))
372
(ssl:defword |ssl|:|Dataset| (&key location)
373
(:documentation "Resolve the given location to instantiate a dataset respective the access form
374
which is implicit in the location.
375
The default location is the request repository.
376
Returns the resolved dataset.")
377
(:values (or iri stream repository))
378
(:generic-function-class |ssl|:|Operation|)
380
(:method (&key (location (ssl::request-repository)))
381
(ssl::dataset location)))
384
(ssl:defword |ssl|:|Decode| (&key location request-type response-type)
385
(:documentation "A decode step parses the given location (a string, the resource designated by an IRI,
386
or the request content) accoding to the given media type to yield a query instance.
387
The default location is the request content stream.
388
The default media type is the request content type.
389
Returns the parsed (but unbound) task/query.")
391
(:generic-function-class |ssl|:|Operation|)
393
(:method (&key (location *request-location*)
394
(request-type *request-content-type*)
395
(response-type *response-content-type*))
396
(setq *task* (decode-task location
397
(mime:mime-type request-type)
398
(mime:mime-type response-type)))
399
(setq *query* *task*))
401
(:method :after (&key &allow-other-keys)
402
(generate-accounting-note :parse)))
405
(ssl:defword |ssl|:|Encode| (projection &key location media-type)
406
(:documentation "An encode step expects the projection result from a project step,
407
encodes it according to the given media type and delivers it to the given destination location.
408
The default location is the request response stream.
409
The default media type is the request accept type.
410
Returns the projection instance, which would have comsumed and emited its content,
411
but would still have access to its structure and metadata.
413
Handle authorization by delegating the location to a dataset, to control access.")
414
(:values solution-field)
415
(:generic-function-class |ssl|:|Operation|)
417
(:method (projection &key
418
(location (processor-response-content-location (request-processor)))
419
(media-type (task-response-content-type *task*)))
420
"delegate to the internal implementation providing the location, wrapped as a dataset
421
to enforce authroization constraints, and media type in addition to the projected content.
422
the default destination location is taken from the request settings as cached in the processor,
423
while the content type is taken from the immediate task, as each task may be specific."
424
(ssl::encode projection (ssl::dataset location :operation |acl|:|Write|) (mime:mime-type media-type))
428
(ssl:defword |ssl|:|End| (&key transaction)
429
(:documentation "Closes a transaction without either aborting or commiting.
430
The default transaction is the thread's current transaction.
432
(:values transaction)
433
(:generic-function-class |ssl|:|Operation|)
435
(:method (&key (transaction *transaction*))
436
(ssl::end-transaction transaction)))
438
(ssl:defword |ssl|:|For| (projection &code steps)
439
(:documentation "Given a projected field, iterate over the solutions, bind the respective variable
440
and execute the cose sequence for each solution")
443
(:method (projection steps)
444
(ssl::for projection steps)))
447
(ssl:defword |ssl|:|Loop| (&code steps &key name)
448
(:documentation "Repeat the given code until something returns")
451
(:method (steps &rest args)
452
(declare (dynamic-extent args))
453
(apply #'ssl::loop steps args)))
456
(ssl:defword |ssl|:|Matcher| (&key method dataset)
457
(:documentation "Instantiate a graph matcher to integrate into either a bind or a projection step.
458
The method determine the matching/entailment regime.
459
As per regime, the dataset can serve as the source for entailment rules.
460
Yields a matcher instance.")
461
(:values ssl::matcher)
462
(:generic-function-class |ssl|:|Operation|)
464
(:method (&key (method nil) (dataset nil))
465
(ssl::graph-matcher method dataset)))
469
(ssl:defword |ssl|:|Notify| (&code steps &key dataset source destination mode)
470
(:documentation "An notify step is a specialized query form which encodes the result to a
471
location other than the response content stream. It also allows options to specify whether
472
the notification is synchronous and whether errors are siliently suppressed or cause the
473
primary request to fail
474
No direct effect on an active transaction upon the step's successful completion.
475
The default mode is asynchronous
476
If wait, then execution suspends until the notification completes. If test, it must complete error-free.
477
Yields the value of the last operation in the plan.")
479
(:generic-function-class |ssl|:|Composition|)
481
(:method ((steps list) &rest args)
482
(declare (dynamic-extent args))
483
(apply #'ssl::notify steps args)))
486
(ssl:defword |ssl|:|Project| (projection &key dataset method media-type)
487
(:documentation "A Project step applies the bound query to the given dataset to generate solutions
488
which are then cpmbined as per the query algebra and then projected through a select, construct,
489
describe or ask clause to yield the final result.
490
The default data set is the thread's current dataset.
491
The default matching method is the d-entailment logic (<http://www.w3.org/ns/entailment/D>)
492
Returns a solution/graph field")
493
(:values solution-field)
494
(:generic-function-class |ssl|:|Operation|)
496
(:method ((projection query) &key
497
(dataset (task-repository projection))
499
(media-type (task-response-content-type projection)))
500
(ssl::project projection dataset method media-type)))
503
(ssl:defword |ssl|:|Query| (&code steps &key dataset name transaction source destination)
504
(:documentation "A query is a specialized plan form which intends to project the dataset content,
505
but not modify it. Acts as a plan to establish a dynamic context.
506
Ends an active transaction - which must be unmodified, upon successful completion.
507
Returns the value of the last opration in the plan.")
509
(:generic-function-class |ssl|:|Composition|)
511
(:method ((steps list) &rest args)
512
(declare (dynamic-extent args))
513
(apply #'ssl::query steps args)))
516
(ssl:defword |ssl|:|Request| (projection &key location request-media-type response-media-type)
517
(:documentation "An request step expects the projection result from a project step,
518
encodes it according to the given media type and delivers it to the given destination location.
519
The usual location is a remote http resource.
520
Returns the decoded response (if any) or the original solution field,
521
The combined media types and method are subject to constraints.
523
Handle authorization by delegating the location to a dataset, to control access.")
524
(:values solution-field)
525
(:generic-function-class |ssl|:|Operation|)
527
(:method (projection &key
528
(location (error "Request: locationis required"))
529
(request-media-type (task-request-content-type *task*))
530
(response-media-type (task-response-content-type *task*))
531
(method *request-http-method*))
532
"delegate to the internal implementation providing the location, wrapped as a dataset
533
to enforce authroization constraints, and media type in addition to the projected content.
534
the default destination location is taken from the request settings as cached in the processor,
535
while the content type is taken from the immediate task, as each task may be specific."
536
(let* ((method-key (http-method-key method))
537
(access-mode (ecase method-key
538
((:head :get) |acl|:|Read|)
539
((:put :post :patch) |acl|:|Write|))))
540
(ssl::request projection (ssl::dataset location :operation access-mode)
543
:method method-key))))
546
(ssl:defword |ssl|:|Return| (&key name value)
547
(:documentation "Return from the dynamic context identified by the tag.
548
If no tag is provided, return from the immediately enclosing block")
549
(:generic-function-class |ssl|:|Operation|)
550
(:method (&key (name nil) (value nil))
551
(invoke-restart name value)))
553
(ssl:defword |ssl|:|Task| (&code steps &key name)
554
(:documentation "A task serves as request container for other compositions")
556
(:generic-function-class |ssl|:|Composition|)
558
(:method ((steps list) &rest args)
559
(declare (dynamic-extent args))
560
(apply #'ssl::query steps args)))
563
(ssl:defword |ssl|:|Update| (&code steps &key dataset destination mode name source transaction)
564
(:documentation "An update is a specialized plan form which intends to project the dataset content to
566
unless :mode is :continue, it commits an active transaction - even if unmodified,
567
upon successful completion.
568
Returns the value of the last opration in the plan.")
570
(:generic-function-class |ssl|:|Composition|)
572
(:method ((steps list) &rest args)
573
(declare (dynamic-extent args))
574
(apply #'ssl::update steps args)))