Coverage report: /development/source/library/org/datagraph/spocq-shard/src/store/term.lisp
| Kind | Covered | All | % |
| expression | 602 | 1217 | 49.5 |
| branch | 29 | 54 | 53.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; -*-
3
(in-package :org.datagraph.spocq.implementation)
5
(:documentation "terms"
6
"data manipulation for terms")
9
(defparameter *term-lock* nil)
11
(or *term-lock* (setf *term-lock* (bt:make-lock "fetch-term"))))
13
(defmacro rdfcache-fetch-term (transaction-pointer term-number term-pointer)
14
`(bt:with-lock-held ((term-lock)) (rdfcache:fetch-term* ,transaction-pointer ,term-number ,term-pointer)))
17
(defun getcache (id table)
20
(defun setcache (id table value)
21
(setf (gethash id table) value))
27
;;; term number<->object operators
29
(defun term-datatype-id (term-number)
30
(rlmdb:term-datatype-id term-number))
32
(defun term-number-lang (term-number)
33
(repository-term-number-lang (or *transaction* *repository*) term-number))
35
(defun term-number-object (term-number)
36
(repository-term-number-object (or *transaction* *repository*) term-number))
38
(defun term-number-type (term-number)
39
(repository-term-number-type (or *transaction* *repository*) term-number))
41
(defun context-term-number (term)
42
"return the term number for the current evaluation context with allowance
43
for special context terms"
44
(repository-context-term-number (or *transaction* *repository*) term))
46
(defun object-term-number (object)
47
"special-case true and false as results from intermediate operations"
49
((t) (repository-object-term-number (or *transaction* *repository*) spocq.a:|true|))
50
((nil) (repository-object-term-number (or *transaction* *repository*) spocq.a:|false|))
51
(t (repository-object-term-number (or *transaction* *repository*) object))))
53
(defun lookup-object-term-number (object)
54
"special-case trun and fals as results from intermediate operations"
56
((t) (repository-lookup-object-term-number *transaction* spocq.a:|true|))
57
((nil) (repository-lookup-object-term-number *transaction* spocq.a:|false|))
58
(t (repository-lookup-object-term-number *transaction* object))))
60
(defun graph-term-number (term &key (allow-all nil))
61
(repository-graph-term-number (or *transaction* *repository*) term :allow-all allow-all))
63
(defgeneric repository-graph-term-number (transaction term &key allow-all)
65
"if the term designates the default graph return that special term number.
66
Otherwise, if it designates either all or all named graphs, that is not a legitimate target.
67
Otherwise, retrieve the term number.")
68
(:method ((repository null) object &key (allow-all nil))
69
(rlmdb:graph-term-number object :allow-all allow-all))
70
(:method ((repository shard-repository) (object t) &key (allow-all nil))
71
(rlmdb:graph-term-number object :allow-all allow-all))
72
(:method ((transaction shard-transaction) (object t) &key (allow-all nil))
73
(rlmdb:graph-term-number object :allow-all allow-all)))
75
(defun intern-property-path (path)
76
(repository-intern-property-path (or *transaction* *repository*) path))
79
(defgeneric repository-object-term-number (repository object)
80
(:argument-precedence-order object repository)
81
(:method ((repository null) object)
82
(rlmdb:value-term-number object))
83
(:method ((repository shard-repository) (object t))
84
(rlmdb:value-term-number object))
85
(:method ((transaction shard-transaction) (object t))
86
(rlmdb:value-term-number object)))
88
(defgeneric repository-lookup-object-term-number (repository object)
89
(:argument-precedence-order object repository)
90
(:method ((repository null) object)
91
(rlmdb:value-term-number object :if-does-not-exist nil))
92
(:method ((repository shard-repository) (object t))
93
(rlmdb:value-term-number object :if-does-not-exist nil))
94
(:method ((transaction shard-transaction) (object t))
95
(rlmdb:value-term-number object :if-does-not-exist nil)))
97
(defgeneric repository-term-number-object (repository term-number)
98
(:method ((repository null) (id t))
99
(rlmdb:term-number-value id))
100
(:method ((repository shard-repository) (id t))
101
(rlmdb:term-number-value id))
102
(:method ((transaction shard-transaction) (id t))
103
(rlmdb:term-number-value id)))
105
(defgeneric repository-term-number-lang (repository term-number)
106
(:method ((repository null) (id t))
107
(rlmdb:term-language id))
108
(:method ((repository shard-repository) (id t))
109
(rlmdb:term-language id))
110
(:method ((transaction shard-transaction) (id t))
111
(rlmdb:term-language id)))
113
(defgeneric repository-term-number-object-list (repository term-number-list)
114
(:method ((repository null) (id-list t))
115
(loop for id in id-list
116
collect (rlmdb:term-number-value id)))
117
(:method ((repository shard-repository) (id-list list))
118
(loop for id in id-list
119
collect (rlmdb:term-number-value id)))
120
(:method ((transaction shard-transaction) (id-list list))
121
(loop for id in id-list
122
collect (rlmdb:term-number-value id))))
124
(defgeneric repository-term-number-type (repository term-number)
125
(:method ((repository null) (term-number t))
126
(rlmdb:term-type term-number))
127
(:method ((repository shard-repository) (term-number t))
128
(rlmdb:term-type term-number))
129
(:method ((transaction shard-transaction) (term-number t))
130
(rlmdb:term-type term-number)))
132
(defgeneric repository-term-is-iri (repository term-number)
133
(:method ((repository null) (id t))
134
(rlmdb:term-is-iri id))
135
(:method ((repository shard-repository) (id t))
136
(rlmdb:term-is-iri id))
137
(:method ((transaction shard-transaction) (id t))
138
(rlmdb:term-is-iri id)))
140
(defgeneric repository-term-is-blank-node (repository term-number)
141
(:method ((repository null) (id t))
142
(rlmdb:term-is-blank-node id))
143
(:method ((repository shard-repository) (id t))
144
(rlmdb:term-is-blank-node id))
145
(:method ((transaction shard-transaction) (id t))
146
(rlmdb:term-is-blank-node id)))
149
;;; rdfcache term management
150
;;; these do not cuse the complete shard term representation.
151
;;; the attributes are collected in just the type, literal, language and type fields
153
(defgeneric compute-term-initializer (term-variable value)
154
(:method (variable (object spocq:iri))
155
(let* ((string (spocq:iri-lexical-form object))
156
(string-var (gensym "STRING")))
157
(values `(cffi:with-foreign-string (,string-var ,string))
158
`((rdfcache:initialize-term ,variable :uri ,string-var :language nil :datatype nil)))))
160
(:method (variable (object spocq:date))
161
(let* ((string (term-lexical-form object))
162
(string-var (gensym "STRING")))
163
(values `(cffi:with-foreign-string (,string-var ,string))
164
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
165
:datatype (datatype-foreign-string '|xsd|:|date|))))))
167
(:method (variable (object spocq:date-time))
168
(let* ((string (term-lexical-form object))
169
(string-var (gensym "STRING")))
170
(values `(cffi:with-foreign-string (,string-var ,string))
171
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
172
:datatype (datatype-foreign-string '|xsd|:|dateTime|))))))
174
(:method (variable (object spocq:time))
175
(let* ((string (term-lexical-form object))
176
(string-var (gensym "STRING")))
177
(values `(cffi:with-foreign-string (,string-var ,string))
178
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
179
:datatype (datatype-foreign-string '|xsd|:|time|))))))
181
(:method (variable (object spocq:day-time-duration))
182
(let* ((string (term-lexical-form object))
183
(string-var (gensym "STRING")))
184
(values `(cffi:with-foreign-string (,string-var ,string))
185
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
186
:datatype (datatype-foreign-string '|xsd|:|dayTimeDuration|))))))
188
(:method (variable (object spocq:duration))
189
(let* ((string (term-lexical-form object))
190
(string-var (gensym "STRING")))
191
(values `(cffi:with-foreign-string (,string-var ,string))
192
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
193
:datatype (datatype-foreign-string '|xsd|:|duration|))))))
195
(:method (variable (object spocq:year-month-duration))
196
(let* ((string (term-lexical-form object))
197
(string-var (gensym "STRING")))
198
(values `(cffi:with-foreign-string (,string-var ,string))
199
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
200
:datatype (datatype-foreign-string '|xsd|:|yearMonthDuration|))))))
202
(:method (variable (object spocq:date-interval))
203
(let* ((string (term-lexical-form object))
204
(string-var (gensym "STRING")))
205
(values `(cffi:with-foreign-string (,string-var ,string))
206
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
207
:datatype (datatype-foreign-string '|time|:|DateInterval|))))))
209
(:method (variable (object spocq:date-time-interval))
210
(let* ((string (term-lexical-form object))
211
(string-var (gensym "STRING")))
212
(values `(cffi:with-foreign-string (,string-var ,string))
213
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
214
:datatype (datatype-foreign-string '|time|:|DateTimeInterval|))))))
216
(:method (variable (object spocq:time-interval))
217
(let* ((string (term-lexical-form object))
218
(string-var (gensym "STRING")))
219
(values `(cffi:with-foreign-string (,string-var ,string))
220
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
221
:datatype (datatype-foreign-string '|time|:|TimeInterval|))))))
224
(:method (variable (object spocq:blank-node))
225
(let* ((string (spocq:blank-node-label object))
226
(string-var (gensym "STRING")))
227
(values `(cffi:with-foreign-string (,string-var ,string))
228
`((rdfcache:initialize-term ,variable :node ,string-var :language nil :datatype nil)))))
230
(:method (variable (object symbol))
231
(let ((uri-namestring (symbol-uri-namestring object))
232
(string-var (gensym "STRING")))
233
(cond (uri-namestring
234
(values `(cffi:with-foreign-strings ((,string-var ,uri-namestring)))
235
`((rdfcache:initialize-term ,variable :uri ,string-var :language nil :datatype nil))))
237
(error "Attempt to initialize a term from an invalid symbol: ~s." object)))))
239
(:method (variable (object spocq:plain-literal))
240
(let ((language-tag (string-downcase (spocq:plain-literal-language-tag object)))
241
(language-var (gensym "LANGUAGE"))
242
(string (spocq:literal-lexical-form object))
243
(string-var (gensym "STRING")))
244
(values `(cffi:with-foreign-strings ((,string-var ,string) (,language-var ,language-tag)))
245
`((rdfcache:initialize-term ,variable :literal ,string-var :language ,language-var :datatype nil)))))
247
(:method (variable (object string))
248
(let ((string-var (gensym "STRING")))
249
(values `(cffi:with-foreign-string (,string-var ,object))
250
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
251
:datatype ,(datatype-foreign-string '|xsd|:|string|)
255
(:method (variable (object spocq:atomic-typed-literal))
256
(let ((string (term-lexical-form object))
257
(string-var (gensym "STRING"))
258
(datatype-string (iri-lexical-form (spocq:literal-datatype-uri object)))
259
(datatype-var (gensym "DATATYPE")))
260
(values `(cffi:with-foreign-strings ((,string-var ,string) (,datatype-var ,datatype-string)))
261
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil :datatype ,datatype-var)))))
263
(:method (variable (object spocq:unsupported-typed-literal))
264
(let ((string (spocq:literal-lexical-form object))
265
(string-var (gensym "STRING"))
266
(datatype-string (iri-lexical-form (spocq:unsupported-typed-literal-datatype-uri object)))
267
(datatype-var (gensym "DATATYPE")))
268
(values `(cffi:with-foreign-strings ((,string-var ,string) (,datatype-var ,datatype-string)))
269
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil :datatype ,datatype-var)))))
271
#-rdfcache-native-integers
272
(:method (variable (object integer))
273
(let ((string (format nil "~f" object))
274
(string-var (gensym "STRING")))
275
(values `(cffi:with-foreign-string (,string-var ,string))
276
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
277
:datatype ,(datatype-foreign-string '|xsd|:|decimal|))))))
279
#+rdfcache-native-integers
280
(:method (variable (object integer))
281
(let ((string (princ-to-string object))
282
(string-var (gensym "STRING")))
283
(values `(cffi:with-foreign-string (,string-var ,string))
284
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
285
:datatype ,(datatype-foreign-string '|xsd|:|integer|))))))
287
(:method (variable (object double-float))
288
(if (or (eq object dsu.codecs:double-float-nan)
289
(eq object dsu.codecs:double-float-positive-infinity)
290
(eq object dsu.codecs:double-float-negative-infinity))
291
(error "Invalid float value: ~a" object)
292
(let* ((*read-default-float-format* 'double-float)
293
(string (xsd-lexical-representation object))
294
(string-var (gensym "STRING")))
295
(values `(cffi:with-foreign-string (,string-var ,string))
296
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
297
:datatype ,(datatype-foreign-string '|xsd|:|double|)))))))
299
(:method (variable (object single-float))
300
(if (or (eq object nan) (eq object +inf) (eq object -inf))
301
(error "Invalid float value: ~a" object)
302
(let* ((*read-default-float-format* 'single-float)
303
(string (xsd-lexical-representation object))
304
(string-var (gensym "STRING")))
305
(values `(cffi:with-foreign-string (,string-var ,string))
306
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
307
:datatype ,(datatype-foreign-string '|xsd|:|float|)))))))
309
(:method (variable (object rational))
310
(let* ((*read-default-float-format* 'single-float)
311
;;(string (format nil "~d/~d" (numerator object) (denominator object)))
312
(string (format nil "~f" (float object 1.0s0)))
313
(string-var (gensym "STRING")))
314
(values `(cffi:with-foreign-string (,string-var ,string))
315
`((rdfcache:initialize-term ,variable :literal ,string-var :language nil
316
:datatype ,(datatype-foreign-string '|xsd|:|decimal|)))))))
319
(undefun rdfcache-constrain-string-length (string)
320
"constrain the string to be of a length less than any configured limit."
321
(cond ((and *rdf-string-length-maximum*
322
(> (length string) *rdf-string-length-maximum*))
323
(log-error "string ~s exceeds length limit of ~s"
324
(type-of string) *rdf-string-length-maximum*)
325
(error "string ~s exceeds length limit of ~s"
326
(type-of string) *rdf-string-length-maximum*))
330
(defun rdfcache-intern-object (%transaction-record object)
331
(if (spocq::unbound-variable-p object)
332
;; guard against cases where compiled operations do not preclude this
334
(with-term-record (%term)
335
;; proactively clear - otherwise the unwind may fail on initial content
336
(rdfcache::%clear-term %term)
337
;; apply any constraints
339
(string (constrain-string-length object)))
341
(progn (set-optional-term %term object)
342
;; (print-term-strings %term)
343
(if (integerp object)
344
(flet ((when-plusp (number)
345
(when (and (integerp number) (plusp number)) number)))
346
;; implicitly promote int/integer to rational
347
(or (when-plusp (rdfcache:lookup-term %transaction-record
348
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
349
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
350
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
351
(datatype-foreign-string '|xsd|:|integer|)))
352
#+(or) ;; do not promote integers to decimal
353
(when-plusp (rdfcache:lookup-term %transaction-record
354
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
355
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
356
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
357
(datatype-foreign-string '|xsd|:|decimal|)))
358
(when-plusp (rdfcache:lookup-term %transaction-record
359
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
360
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
361
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
362
(datatype-foreign-string '|xsd|:|int|)))
363
(rdfcache:intern-term %transaction-record
364
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
365
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
366
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
367
(datatype-foreign-string '|xsd|:|integer|))))
368
(rdfcache:intern-term %transaction-record
369
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
370
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
371
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
372
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype))))
373
(clear-optional-term %term)))))
376
(defgeneric rdfcache-object-term-number (context object)
377
(:documentation "given a context and a term, return the current term number respective the context.
378
If the context is a transaction and the term is not yet in the store, this entails generating a
379
transaction-relative ephemeral term number. If the context is null, then either return the number for an
380
existing term or signal an error. see also rdfcache-lookup-object-term-number, which returns nil in that case.")
381
(:argument-precedence-order object context)
383
(:method ((repository rdfcache-repository) (object t))
384
(rdfcache-object-term-number *transaction* object))
386
(:method ((context null) (object t))
387
;; w/o transaction do a context-free lookup
388
(or (rdfcache-find-object-term-number object)
389
(error "unknown term: ~s." object)))
391
(:method ((context rdfcache-transaction) (object t))
392
(or (gethash object *spocq->store-term-registry*)
393
(setf (gethash object *spocq->store-term-registry*)
394
(rdfcache-intern-object (transaction-record context) object))))
396
(:method ((context t) (object t))
397
(or (gethash object *spocq->store-term-registry*)
398
(let ((term-number (rdfcache-intern-object context object)))
399
;; do not cache the mapping for ephemeral terms
400
(when (> term-number 0)
401
(setcache object *spocq->store-term-registry* term-number)
402
(setcache term-number *store->spocq-term-registry* object))
405
(:method ((context t) (object symbol))
406
(or (symbol-term-id object)
409
(:method (context (object spocq:term))
410
(or (spocq:term-id object)
411
(let ((term-number (rdfcache-intern-object (transaction-record context) object)))
412
(if (> term-number 0) ; cache persistent identifiers only
413
(setf (spocq:term-id object) term-number)
415
(:method (context (object spocq:unbound-variable))
418
(defun rdfcache-find-object-term-number (object)
419
(rdfcache-lookup-object-term-number object))
422
(defgeneric rdfcache-lookup-object-term-number (object)
423
(:documentation "given a term, return the global term number in the store.
424
if the term is not found in the global dictionary, return nil for constants
425
and 0 for wildcards.")
427
(:method ((object t))
428
;; do a context-free lookup
429
(or (gethash object *spocq->store-term-registry*)
430
(let ((term-number (with-term-record (%term)
432
(progn (set-optional-term %term object)
433
;; (print-term-strings %term)
434
(rdfcache:lookup-term-number %term)
435
#+(or) ; until null context is implemented
436
(rdfcache:lookup-term nil
437
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
438
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
439
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
440
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype)))
441
(clear-optional-term %term)))))
443
(setf (gethash object *spocq->store-term-registry*) term-number))
446
(:method ((object spocq:term))
447
(or (spocq:term-id object)
448
(let ((term-number (call-next-method)))
449
(when term-number ; cache persistent identifiers only
450
(setf (spocq:term-id object) term-number)
453
(:method ((object null))
455
(:method ((object spocq:unbound-variable))
458
(defun rdfcache-lookup-object-term-number! (object)
459
(with-term-record (%term)
461
(progn (set-optional-term %term object)
462
;; (print-term-strings %term)
463
(rdfcache:lookup-term-number %term))
464
(clear-optional-term %term))))
467
(defmethod store-context ((transaction rdfcache-transaction))
468
(transaction-record transaction))
474
(undefun rdfcache-call-with-numbered-term (operator context term-number)
475
(declare (dynamic-extent operator))
476
#|(declare (type (function (t) t) operator)
477
(type fixnum term-number))
478
(assert (typep operator 'function) () "Invalid operator: ~s." operator)
479
(assert (typep term-number 'fixnum) () "Invalid term number: ~s." term-number)|#
480
(cond ((or (= term-number 0) (= term-number -1))
481
(with-term-record (%term)
482
(rdfcache::%clear-term %term)
483
(funcall operator %term)))
486
(rdfcache-transaction (setf context (transaction-record context)))
487
(cffi:foreign-pointer ))
488
(with-term-record (%term)
489
(rdfcache:fetch-term* context term-number %term)
490
(funcall operator %term)))
492
(with-term-record (%term)
493
(rdfcache:fetch-term term-number %term)
494
(funcall operator %term)))))
496
(undefun rdfcache-call-with-numbered-term-aspects (operator context term-number)
497
(declare (dynamic-extent operator))
498
#|(declare (type (function (t t t t) t) operator)
499
(type fixnum term-number))
500
(assert (typep operator 'function) () "Invalid operator: ~s." operator)
501
(assert (typep term-number 'fixnum) () "Invalid term number: ~s." term-number)|#
502
(if (or (rdfcache:ephemeral-term-number-p term-number)
503
(rdfcache:persistent-term-number-p term-number))
504
(if (setf context (transaction-record context))
505
(with-term-record (%term)
506
(rdfcache:fetch-term* context term-number %term)
508
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
509
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
510
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
511
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype)))
512
(with-term-record (%term)
513
(rdfcache:fetch-term term-number %term)
515
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
516
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
517
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
518
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype))))
519
;; treat an internal term number as the 'null' term
520
(with-term-record (%term)
521
(rdfcache::%clear-term %term)
523
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
524
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
525
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
526
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype)))))
528
(undefmethod repository-call-with-numbered-term-aspects (operator (transaction rdfcache-transaction) term-number)
529
(rdfcache-call-with-numbered-term-aspects operator transaction term-number))
531
(undefmethod repository-term-deconstructor ((context rdfcache-transaction))
532
#'rdfcache-call-with-numbered-term-aspects)
534
(undefun rdfcache-term-number-object-p (expression)
535
(and (consp expression)
536
(eq (first expression) 'rdfcache-term-number-object)))
538
;; (rdfcache-call-with-numbered-term #'print-term-strings nil 829)
540
(undefgeneric repository-typed-term-number-object (context number datatype-id)
542
"Retrieve the data model value for the given (term-number x datatype-term-id) combination.
543
This will include methods specialized for the immediate typed, which avoid parsing
545
(:argument-precedence-order datatype-id context number)
546
(:method ((context t) (number t) (datatype-id t))
547
"The default method, to be used when nothing is defined for the given datatype id,
548
uses the generic logic to intern the term and manage a cache of the interned values."
549
(or (get-registry number *store->spocq-term-registry*)
550
(repository-cache-term-number-object context number))))
552
(undefun repository-cache-term-number-object (context number)
553
(let ((object (repository-term-number-object context number)))
554
(cond ((and (spocq:term-p object) (> number 0))
555
(setf (spocq:term-id object) number)
556
(setf (get-registry number *store->spocq-term-registry*) object))
558
(setf (get-registry number *store->spocq-term-registry*) object))
562
(defparameter *intern-datatype-operators*
563
'((|http://www.w3.org/2001/XMLSchema|:|boolean| :term-value-as-boolean)
564
(|http://www.w3.org/2001/XMLSchema|:|byte| :term-value-as-int32)
565
(|http://www.w3.org/2001/XMLSchema|:|decimal| :term-value-as-decimal)
566
(|http://www.w3.org/2001/XMLSchema|:|double| :term-value-as-double)
567
(|http://www.w3.org/2001/XMLSchema|:|float| :term-value-as-float)
568
(|http://www.w3.org/2001/XMLSchema|:|int| :term-value-as-int32)
569
(|http://www.w3.org/2001/XMLSchema|:|integer| :term-value-as-integer)
570
(|http://www.w3.org/2001/XMLSchema|:|long| :term-value-as-int64)
571
(|http://www.w3.org/2001/XMLSchema|:|nonNegativeInteger| :term-value-as-integer)
572
(|http://www.w3.org/2001/XMLSchema|:|nonPositiveInteger| :term-value-as-integer)
573
(|http://www.w3.org/2001/XMLSchema|:|negativeInteger| :term-value-as-integer)
574
(|http://www.w3.org/2001/XMLSchema|:|positiveInteger| :term-value-as-integer)
575
(|http://www.w3.org/2001/XMLSchema|:|short| :term-value-as-int16)
576
(|http://www.w3.org/2001/XMLSchema|:|unsignedByte| :term-value-as-int8)
577
(|http://www.w3.org/2001/XMLSchema|:|unsignedInt| :term-value-as-uint32)
578
(|http://www.w3.org/2001/XMLSchema|:|unsignedLong| :term-value-as-uint64)
579
(|http://www.w3.org/2001/XMLSchema|:|unsignedShort| :term-value-as-uint16)
582
;; not yet (|http://www.w3.org/2001/XMLSchema|:|date| term-value-as-date-from-int64)
583
(|http://www.w3.org/2001/XMLSchema|:|dateTime| term-value-as-date-time-from-int64)
584
(|http://www.w3.org/2001/XMLSchema|:|time| term-value-as-time-from-int64)
588
(defun term-value-as-date-from-int64 (number)
589
(let ((value (rlmdb:term-number-value number)))
590
(assert (spocq:date-p value) ()
591
"invalid date term: ~s: ~s" number value)
594
(defun term-value-as-date-time-from-int64 (number)
595
(let ((value (rlmdb:term-number-value number)))
596
(assert (spocq:date-time-p value) ()
597
"invalid date-time term: ~s: ~s" number value)
600
(defun term-value-as-time-from-int64 (number)
601
(let ((value (rlmdb:term-number-value number)))
602
(assert (spocq:time-p value) ()
603
"invalid time term: ~s: ~s" number value)
607
(undefun define-rdfcache-typed-term-number-object-methods ()
608
;; runs at store initialization
610
(loop for method in (copy-list (c2mop:generic-function-methods #'rdfcache-typed-term-number-object))
611
do (when (typep (third (c2mop:method-specializers method)) 'c2mop:eql-specializer)
612
(remove-method #'rdfcache-typed-term-number-object method)))
614
(loop for (datatype-uri operator-name) in *intern-datatype-operators*
615
for datatype-id = (symbol-term-id datatype-uri)
616
for interned-operator-name = (or (find-symbol (string operator-name) :spocq.i)
617
(find-symbol (string operator-name) :dydra-ndk))
618
if interned-operator-name
619
do (eval `(defmethod rdfcache-typed-term-number-object ((context t) (number t) (datatype-id (eql ,datatype-id)))
620
(or ;; (,interned-operator-name number :junk-allowed t)
621
(,interned-operator-name number)
622
(call-next-method))))
623
else do (warn "unimplemented native datatype: ~s ~s" datatype-uri operator-name)))
625
(undefun compute-rdfcache-typed-term-number-object-methods ()
626
(loop for (datatype-uri operator-name) in *intern-datatype-operators*
627
for datatype-id = (symbol-term-id datatype-uri)
628
for interned-operator-name = (or (find-symbol (string operator-name) :spocq.i)
629
(find-symbol (string operator-name) :dydra-ndk))
630
if interned-operator-name
631
collect `(defmethod rdfcache-typed-term-number-object ((context t) (number t) (datatype-id (eql ,datatype-id)))
632
(or ;; (,interned-operator-name number :junk-allowed t)
633
(,interned-operator-name number)
635
else do (warn "unimplemented native datatype: ~s ~s" datatype-uri operator-name)))
638
(defun clear-optional-term (%term)
639
"When the term was initialized, the fields may have heap values which should have dynamic extent. If so
640
free and clear these fields. If the value is a registered foreign string - as for datatyes, then
641
just clear the field"
643
(unless (eq :none (rdfcache:term-type %term))
644
(contingently-foreign-free (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value))
645
(contingently-foreign-free (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language))
646
(contingently-foreign-free (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype))
647
(setf (rdfcache:term-type %term) :none)
648
(rdfcache::%clear-term %term))
651
(defun make-rdfcache-term (object)
652
(let ((%term (cffi:foreign-alloc 'rdfcache::term)))
653
(set-optional-term %term object)
656
(defgeneric set-optional-term (term value)
657
(:method (term (object spocq:unbound-variable))
658
(rdfcache::%clear-term term))
660
(:method (term (object spocq:blank-node))
661
(let* ((string (spocq:blank-node-label object)))
662
(rdfcache:initialize-term term :node (cffi:foreign-string-alloc string) :language nil :datatype nil))
665
(:method (term (object spocq:boolean))
666
(let* ((string (term-lexical-form object)))
667
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
669
:datatype (datatype-foreign-string '|xsd|:|boolean|)))
672
(:method (term (object spocq:date))
673
(let* ((string (if (offset-zone-p (date-zone object))
674
(with-output-to-string (stream) (spocq:format-date stream object))
675
(term-lexical-form object))))
676
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
678
:datatype (datatype-foreign-string '|xsd|:|date|)))
681
(:method (term (object spocq:date-time))
682
(let* ((string (if (offset-zone-p (date-time-zone object))
683
(with-output-to-string (stream) (spocq:format-date-time stream object))
684
(term-lexical-form object))))
685
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
687
:datatype (datatype-foreign-string '|xsd|:|dateTime|)))
690
(:method (term (object spocq:day-time-duration))
691
(let* ((string (term-lexical-form object))) ; no zone offset
692
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
694
:datatype (datatype-foreign-string '|xsd|:|dayTimeDuration|)))
697
(:method (term (object spocq:date-interval))
698
(let* ((string (term-lexical-form object)))
699
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
701
:datatype (datatype-foreign-string '|time|:|DateInterval|)))
704
(:method (term (object spocq:date-time-interval))
705
(let* ((string (term-lexical-form object)))
706
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
708
:datatype (datatype-foreign-string '|time|:|DateTimeInterval|)))
711
(:method (term (object spocq:duration))
712
(let* ((string (term-lexical-form object))) ; no zone offset
713
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
715
:datatype (datatype-foreign-string '|xsd|:|duration|)))
718
(:method (term (object spocq:g-day))
719
(let* ((string (if (offset-zone-p (g-day-zone object))
720
(with-output-to-string (stream) (spocq:format-g-day stream object nil t spocq:+reference-zone+))
721
(term-lexical-form object))))
722
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
724
:datatype (datatype-foreign-string '|xsd|:|gDay|)))
727
(:method (term (object spocq:g-month))
728
(let* ((string (if (offset-zone-p (g-month-zone object))
729
(with-output-to-string (stream) (spocq:format-g-month stream object nil t spocq:+reference-zone+))
730
(term-lexical-form object))))
731
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
733
:datatype (datatype-foreign-string '|xsd|:|gMonth|)))
736
(:method (term (object spocq:g-month-day))
737
(let* ((string (if (offset-zone-p (g-month-day-zone object))
738
(with-output-to-string (stream) (spocq:format-g-month-day stream object nil t spocq:+reference-zone+))
739
(term-lexical-form object))))
740
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
742
:datatype (datatype-foreign-string '|xsd|:|gMonthDay|)))
745
(:method (term (object spocq:g-year))
746
(let* ((string (if (offset-zone-p (g-year-zone object))
747
(with-output-to-string (stream) (spocq:format-g-year stream object nil t spocq:+reference-zone+))
748
(term-lexical-form object))))
749
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
751
:datatype (datatype-foreign-string '|xsd|:|gYear|)))
754
(:method (term (object spocq:g-year-month))
755
(let* ((string (if (offset-zone-p (g-year-month-zone object))
756
(with-output-to-string (stream) (spocq:format-g-year-month stream object nil t spocq:+reference-zone+))
757
(term-lexical-form object))))
758
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
760
:datatype (datatype-foreign-string '|xsd|:|gYearMonth|)))
763
(:method (term (object spocq:time))
764
(let* ((string (if (offset-zone-p (time-zone object))
765
(with-output-to-string (stream) (spocq:format-time stream object nil t spocq:+reference-zone+))
766
(term-lexical-form object))))
767
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
769
:datatype (datatype-foreign-string '|xsd|:|time|)))
772
(:method (term (object spocq:time-interval))
773
(let* ((string (term-lexical-form object)))
774
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
776
:datatype (datatype-foreign-string '|time|:|TimeInterval|)))
779
(:method (term (object spocq:year-month-duration))
780
(let* ((string (term-lexical-form object))) ; no zone offset
781
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
783
:datatype (datatype-foreign-string '|xsd|:|yearMonthDuration|)))
786
(:method (term (object spocq:iri))
787
(let* ((string (spocq:iri-lexical-form object)))
788
(rdfcache:initialize-term term :uri (cffi:foreign-string-alloc string) :language nil :datatype nil))
791
(:method (term (object symbol))
793
((nil) (set-optional-term term spocq.a:|false|))
794
((t) (set-optional-term term spocq.a:|true|))
796
(let ((uri-namestring (symbol-uri-namestring object)))
797
(cond (uri-namestring
798
(rdfcache:initialize-term term :uri (cffi:foreign-string-alloc uri-namestring) :language nil :datatype nil))
800
(rdfcache::%clear-term term)
801
(error "Attempt to initialize a term from an invalid symbol: ~s." object))))
804
(:method (term (object spocq:plain-literal))
805
(let ((language-tag (string-downcase (spocq:plain-literal-language-tag object)))
806
(string (spocq:literal-lexical-form object)))
807
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
808
:language (cffi:foreign-string-alloc language-tag)
809
:datatype nil ;; (datatype-foreign-string '|rdf|:|langString|)
813
(:method (term (object string))
814
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc object)
816
:datatype (datatype-foreign-string '|xsd|:|string|)
817
;; :datatype (cffi:foreign-string-alloc (symbol-uri-namestring |xsd|:|string|))
821
(:method (term (object spocq:atomic-typed-literal))
822
(let ((string (term-lexical-form object))
823
(datatype-string (iri-lexical-form (spocq:literal-datatype-uri object))))
824
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
826
:datatype (cffi:foreign-string-alloc datatype-string)))
829
(:method (term (object spocq:unsupported-typed-literal))
830
(let ((string (spocq:literal-lexical-form object))
831
(datatype-string (iri-lexical-form (spocq:unsupported-typed-literal-datatype-uri object))))
832
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string)
834
:datatype (cffi:foreign-string-alloc datatype-string)))
837
#-rdfcache-native-integers
838
(:method (term (object integer))
839
(let ((string (spocq.e:string object))) ; do not format directly to avoid problem with 0.0
840
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string) :language nil
841
:datatype (datatype-foreign-string |xsd|:|decimal|)))
844
#+rdfcache-native-integers
845
(:method (term (object integer))
846
(let ((string (princ-to-string object)))
847
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string) :language nil
848
:datatype (datatype-foreign-string |xsd|:|integer|)))
851
(:method (term (object double-float))
852
(cond ((or *permit-float-special-values*
853
(not (or (eql object dsu.codecs:double-float-nan)
854
(eql object dsu.codecs:double-float-positive-infinity)
855
(eql object dsu.codecs:double-float-negative-infinity))))
856
(let* ((*read-default-float-format* 'double-float)
857
(string (xsd-lexical-representation object)))
858
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string) :language nil
859
:datatype (datatype-foreign-string '|xsd|:|double|))))
861
(rdfcache::%clear-term term)
862
(error "Invalid float value: ~a" object)))
865
(:method (term (object single-float))
866
(cond ((or *permit-float-special-values*
867
(not (or (eql object nan) (eql object +inf) (eq object -inf))))
868
(let* ((*read-default-float-format* 'single-float)
869
(string (xsd-lexical-representation object)))
870
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string) :language nil
871
:datatype (datatype-foreign-string '|xsd|:|float|))))
873
(rdfcache::%clear-term term)
874
(error "Invalid float value: ~a" object)))
877
(:method (term (object rational))
878
(let* ((*read-default-float-format* 'single-float)
879
;; (string (format nil "~d/~d" (numerator object) (denominator object)))
880
;; special case test for unit denominator which woudl cause the float operator
882
(string (format nil "~f" (float object 1.0s0))))
883
(rdfcache:initialize-term term :literal (cffi:foreign-string-alloc string) :language nil
884
:datatype (datatype-foreign-string '|xsd|:|decimal|)))
888
(defun call-with-term-string (op %term-string)
889
"use rdfcache decoder to handle utf8 decoding."
890
(declare (type rdfcache::foreign-pointer %term-string))
891
(let* ((intended-count (rdfcache::%%utf8-get-length %term-string))
892
(result-string (make-string intended-count)))
893
(sb-sys:with-pinned-objects (result-string)
894
(cffi:with-pointer-to-vector-data (%buffer result-string)
895
(let ((count (rdfcache::%%utf8-to-utf32 %term-string -1 %buffer (* intended-count 4))))
896
(assert (= count intended-count) ()
897
"Decoded length != counted length: ~d != ~d: ~s." count intended-count result-string))
898
(funcall op result-string)))))
899
(defun call-with-term-string (op %term-string)
900
(declare (type rdfcache::foreign-pointer %term-string))
901
(let ((string (cffi:foreign-string-to-lisp %term-string)))
902
(funcall op string)))
904
(defun intern-term (%term)
905
;; (print-term %term)
906
(assert (rdfcache::pointerp %term) ()
907
"Invalid term pointer: ~a." %term)
908
(with-term-attributes (type literal language-tag datatype) %term
909
; (print (list type literal language-tag datatype))
910
(when (integerp type)
911
(setf type (ecase type (0 :none) (1 :uri) (2 :node) (5 :literal) (255 :id))))
912
(intern-term-aspects type literal datatype language-tag)))
915
(defun call-with-term-number-type (op term-number)
916
(declare (dynamic-extent op))
917
(funcall op (term-number-type term-number)))
920
(defun print-term (%term &optional (stream *standard-output*))
921
(print-unreadable-object (%term stream :identity nil :type nil)
922
(format stream "%term ~8,'0x: type ~s value ~s language ~s datatype ~s"
923
(cffi:pointer-address %term)
924
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
925
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
926
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
927
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype))))
929
(defun print-term-strings (%term &optional (stream *standard-output*))
931
(print-unreadable-object (%term stream :identity nil :type nil)
932
(flet ((string-or-nll (ptr)
933
(unless (cffi:null-pointer-p ptr)
934
(cffi:foreign-string-to-lisp ptr))))
935
(flet ((print-it (%term)
936
(format stream "~8,'0x: type ~s value ~s language ~s datatype ~s"
937
(cffi:pointer-address %term)
938
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
939
(string-or-nll (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value))
940
(string-or-nll (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language))
941
(string-or-nll (cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype)))))
944
(integer (format stream "~8,'0x: ~s" %term (rlmdb:term-elements %term)))
945
(cffi:foreign-pointer (print-it %term)))))))
947
(defgeneric print-term-number-strings (repository-designator term-number)
948
(:method ((repository shard-transaction) (term-number integer))
949
(format *standard-output* "~8,'0x: ~s" term-number (rlmdb:term-elements term-number)))
950
(:method ((repository shard-repository) (term-number integer))
951
(format *standard-output* "~8,'0x: ~s" term-number (rlmdb:term-elements term-number))))
955
(let ((literal-tagged "w/lang")
956
(literal-typed "w/type"))
957
(setf (literal-language-tag literal-tagged) "EN")
958
(setf (literal-datatype literal-typed) |xsd|:|anyURI|)
960
(let ((*print-case* :downcase))
963
`(with-terms ((symbol-datatype-term |xsd|:|anyURI|)
964
(uri-term <http://example/q>)
965
(string-term "a string")
966
(tagged-string-term ,literal-tagged)
967
(typed-string-term ,literal-typed)
971
(print (list symbol-datatype uri string integer float decimal)))))))
973
(defun zero-duration ()
975
(with-term-record (%term)
976
(cffi:with-foreign-string (%lexical-form "PT0S")
977
(cffi:with-foreign-string (%datatype "http://www.w3.org/2001/XMLSchema#dayTimeDuration")
978
(rdfcache:initialize-term %term :literal %lexical-form :language nil :datatype %datatype)
979
;;(print-term-strings %term)
980
(let ((id (rdfcache:lookup-term-number %term)))
982
(log-warn "Interning missing term <~a>." "PT0S")
983
(rdfcache::intern-term nil
984
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::type)
985
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::value)
986
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::language)
987
(cffi:foreign-slot-value %term '(:struct rdfcache::term) 'rdfcache::datatype)))
988
(setf *zero-duration* (intern-term-aspects :literal "PT0S" |xsd|::|dayTimeDuration| nil))
989
(setf (spocq:term-id *zero-duration*) id)
990
(unless (plusp (rdfcache-object-term-number nil *zero-duration*))
991
(error "Cannot locate PT0S in the store."))
992
*zero-duration*))))))
994
(defun graph-management-argument (term)
995
(cond ((member term '(nil :default |urn:dydra|:|default|))
996
rdfcache:*default-context-number*)
997
((member term '(t |urn:dydra|:|named| |urn:dydra|:|all|))
998
(error "invalid graph management argument: ~s" term))
1000
(iri-lexical-form term))
1002
(spocq.e::invalid-graph-error :identifier term))))