Querying SPARQL endpoints using GNU Guile

Roel Janssen — July 23, 2017

Recently I attempted to load all GNU Guix packages into a triplet store. For this we need to find or create an ontology that describes software in a compatible way with GNU Guix.

The easy part was transforming the package information into SPARQL queries, which can be done using the following snippet:

(use-modules (gnu packages)
             (guix packages)
             (ice-9 vlist))

(define (packages->sparql)
  "Display available packages."
  (format #t "INSERT DATA~%{~%  GRAPH <http://sparql.guixsd.org/packages>~%  {~%")
  (let ((packages (fold-packages
                   (lambda (p r) (vhash-cons (package-full-name p) p r))
                   vlist-null)))
    (vlist-for-each
     (lambda (pair)
       (let* ((package (cdr pair))
              (full-name (package-full-name package))
              (version (package-version package))
              (name (package-name package))
              (home-page (package-home-page package)))
         (format #t "    <#~a> <#name> ~s .~%" full-name name)
         (format #t "    <#~a> <#version> ~s .~%" full-name version)
         (when home-page
           (format #t "    <#~a> <#home-page> ~s .~%" full-name home-page))))
     packages))
  (format #t "  }~%}~%"))

(define guix-packages (with-output-to-string packages->sparql))

At this point, we have the SPARQL query, but we don't have the GNU Guile interface to submit it to a SPARQL endpoint. Ideally, we want the following function:

(sparql-query guix-packages)

This turns out to be rather easy to implement with GNU Guile's (web client) module. The initial implementation looks like so:

(define* (sparql-query query
                       #:key
                       (host "localhost")
                       (port 8890)
                       (type "text/csv"))
  (http-post (format #f "http://~a:~a/sparql" host port)
   #:body query
   #:streaming? #t
   #:headers `((user-agent . "GNU Guile")
               (content-type . (application/sparql-update))
               (accept . ((,(string->symbol type)))))))

After using SPARQL and triple-stores more, I created a Guile module called guile-sparql, which can be viewed on Github, or installed with GNU Guix:

$ guix package -i guile-sparql