about summary refs log tree commit diff
path: root/dump/special-forms.scm
diff options
context:
space:
mode:
Diffstat (limited to 'dump/special-forms.scm')
-rw-r--r--dump/special-forms.scm599
1 files changed, 0 insertions, 599 deletions
diff --git a/dump/special-forms.scm b/dump/special-forms.scm
deleted file mode 100644
index 2650580..0000000
--- a/dump/special-forms.scm
+++ /dev/null
@@ -1,599 +0,0 @@
-(define-module (dump special-forms)
-  #:use-module (srfi srfi-1)
-  #:use-module (ice-9 match)
-  #:use-module (srfi srfi-26)
-  #:use-module (dump sql)
-  #:use-module (dump table)
-  #:use-module (dump triples)
-  #:export (translate-forms
-            collect-forms
-            collect-keys
-            field->key
-            field->assoc-ref
-            collect-fields
-            find-clause
-            remove-namespace
-            column-id
-            id
-            syntax-let
-            blank-node
-            map-alist
-	    with-documentation
-            define-transformer))
-
-(define (key->assoc-ref alist x)
-  "Recursively translate (key k) forms in source X to (assoc-ref ALIST
-k) forms."
-  (translate-forms 'key
-                   ;; (syntax-rules (key)
-                   ;;   ((key k) (assoc-ref alist k)))
-                   (lambda (x)
-                     (syntax-case x (key)
-                       ((key k) #`(assoc-ref #,alist 'k))))
-                   x))
-
-(define (alist-delete* alist keys)
-  "Delete entries from ALIST whose key is equal (in the sense of
-equal?) to any in KEYS, a list."
-  (remove (match-lambda
-            ((key . value)
-             (member key keys))
-            (x (error "malformed alist element" x)))
-          alist))
-
-(define (translate-forms from translator x)
-  "Recursively pass (FROM ...) forms in source X to TRANSLATOR, and
-replace them with the return value."
-  (syntax-case x ()
-    ;; Handle translation base case.
-    ((head tail ...) (eq? (syntax->datum #'head)
-                          from)
-     (translator x))
-    ;; Recurse.
-    ((head tail ...)
-     (cons (translate-forms from translator #'head)
-           (map (cut translate-forms from translator <>)
-                #'(tail ...))))
-    ;; Handle leaf base case.
-    (leaf #'leaf)))
-
-(define (collect-forms target x)
-  "Recursively collect (TARGET ...) forms in source X and return them
-as a list."
-  (syntax-case x ()
-    ;; Handle collection base case.
-    ((head tail ...) (eq? (syntax->datum #'head)
-                          target)
-     (list x))
-    ;; Recurse.
-    ((head tail ...)
-     (append (collect-forms target #'head)
-             (append-map (cut collect-forms target <>) #'(tail ...))))
-    ;; Handle leaf base case.
-    (leaf (list))))
-
-(define (collect-keys x)
-  "Recursively collect (key k) forms from source X and return as a
-list of all K."
-  (map (syntax-rules (key)
-         ((key k) 'k))
-       (collect-forms 'key x)))
-
-(define-syntax map-alist
-  (lambda (x)
-    "Transform (aka map) ALIST, an association list, into another
-association list. The returned association list may contain multiple
-associations for the same key. equal? is used in all association list
-key comparisons.
-
-Syntax:
-
-(map-alist alist
-  (verb key expression) ...
-  (else=> proc))
-
-VERB must be one of set, filter-set, multiset and remove.
-
-For the set VERB, KEY is set to the result of evaluating
-EXPRESSION. Multiple set verbs on the same key will result in multiple
-associations for that key.
-
-For the filter-set VERB, KEY is set to the result of evaluating
-EXPRESSION only if that result is not #f.
-
-For the multiset VERB, EXPRESSION must return a list and KEY is
-associated multiple times once with each element of the returned list.
-
-For the remove VERB, KEY is discarded.
-
-EXPRESSIONs must reference elements of ALIST using (key k) forms where
-K is the key to be referenced from ALIST. K must not be quoted. That
-is, if K is the symbol 'bar, it must be referenced as (key bar), not
-as (key 'bar).
-
-The else=> clause is optional.
-
-If the else=> clause is present, PROC is passed all pairs of ALIST
-that are not set by an earlier (verb key expression) action. PROC must
-return #f or a pair to replace its input pair. If PROC returns #f,
-that pair is discarded.
-
-If the else=> clause is absent, all unset pairs are discarded.
-
-Example:
-
-(map-alist '((\"foo\" . 1)
-             (bar . 2)
-             (foobar . 5)
-             (fubar . 3))
-  (set spam (1+ (key \"foo\")))
-  (set ham (* 2 (key bar)))
-  (set eggs (* 3 (key bar)))
-  (set aal (+ (key \"foo\")
-              (key bar)))
-  (multiset vel (iota (* 2 (key bar))))
-  (remove foobar)
-  (else=> (match-lambda
-            ((key . value)
-             (cons key (expt 2 value))))))
-=> ((spam . 2) (ham . 4) (eggs . 6) (aal . 3)
-    (vel . 0) (vel . 1) (vel . 2) (vel . 3) (fubar . 8))"
-    (syntax-case x ()
-      ((_ alist actions ...)
-       ;; TODO: Check that all actions are valid.
-       #`(let ((evaluated-alist alist))
-           (append (remove (match-lambda
-                             ;; Filter out results of filter-set actions.
-                             ((key . #f)
-                              (member key '#,(filter-map (lambda (action)
-                                                           (syntax-case action (filter-set)
-                                                             ((filter-set key expression) #'key)
-                                                             (_ #f)))
-                                                         #'(actions ...))))
-                             (_ #f))
-                           ;; Do set and filter-set.
-                           `#,(filter-map (lambda (action)
-                                            (syntax-case action (set filter-set)
-                                              ((set key expression)
-                                               #`(key . ,#,(key->assoc-ref #'evaluated-alist #'expression)))
-                                              ((filter-set key expression)
-                                               #`(key . ,#,(key->assoc-ref #'evaluated-alist #'expression)))
-                                              (_ #f)))
-                                          #'(actions ...)))
-                   ;; Do multiset.
-                   #,@(filter-map (lambda (action)
-                                    (syntax-case action (multiset)
-                                      ((multiset key expression)
-                                       #`(map (cut cons 'key <>)
-                                              #,(key->assoc-ref #'evaluated-alist #'expression)))
-                                      (_ #f)))
-                                  #'(actions ...))
-                   ;; Apply else=> procedure on unspecified keys. If
-                   ;; no else=> procedure is specified, delete
-                   ;; unspecified keys.
-                   (filter-map #,(or (any (lambda (action)
-                                            (syntax-case action (else=>)
-                                              ((else=> proc) #'proc)
-                                              (_ #f)))
-                                          #'(actions ...))
-                                     #'(const #f))
-                               ;; The unspecified part of the input
-                               ;; alist
-                               (alist-delete* evaluated-alist
-                                              (list
-                                               ;; Keys that were referenced
-                                               #,@(append-map (lambda (action)
-                                                                (syntax-case action ()
-                                                                  ((_ key expression)
-                                                                   (collect-keys #'expression))
-                                                                  (_ '())))
-                                                              #'(actions ...))
-                                               ;; Keys that were deleted
-                                               #,@(filter-map (lambda (action)
-                                                                (syntax-case action (remove)
-                                                                  ((remove key) #''key)
-                                                                  (_ #f)))
-                                                              #'(actions ...))
-                                               ;; Keys that were set
-                                               #,@(filter-map (lambda (action)
-                                                                (syntax-case action ()
-                                                                  ((_ key expression) #''key)
-                                                                  (_ #f)))
-                                                              #'(actions ...)))))))))))
-
-
-
-(eval-when (expand load )
-  (define (field->datum x)
-    (translate-forms
-     'field
-     (lambda (x)
-       (syntax-case x (field)
-         ((field (query alias))
-          #`(format #f "~a" (syntax->datum #'alias)))
-         ((field table column)
-          #`(format #f "~a(~a)"
-                    (syntax->datum #'table)
-                    (syntax->datum #'column)))
-         ((field table column alias)
-          #`(format #f "~a(~a)"
-                    (syntax->datum #'table)
-                    (syntax->datum #'alias)))))
-     x))
-
-  (define (field->key x)
-    (translate-forms 'field
-                     (lambda (x)
-                       #`(key #,(symbol->string
-                                 (syntax->datum
-                                  ((syntax-rules (field)
-                                     ((field (query alias)) alias)
-                                     ((field table column) column)
-                                     ((field table column alias) alias))
-                                   x)))))
-                     x))
-
-  (define (field->assoc-ref alist x)
-    "Recursively translate field references in source X to (assoc-ref
-ALIST field-name) forms."
-    (translate-forms 'field
-                     (lambda (x)
-                       #`(assoc-ref #,alist
-                                    #,(symbol->string
-                                       (syntax->datum
-                                        ((syntax-rules (field)
-                                           ((field (query alias)) alias)
-                                           ((field table column) column)
-                                           ((field table column alias) alias))
-                                         x)))))
-                     x))
-
-  (define (collect-fields x)
-    (map (syntax-rules (field)
-           ((field reference ...)
-            (reference ...)))
-         (collect-forms 'field x)))
-
-  (define (find-clause clauses key)
-    "Find (KEY ...) clause among CLAUSES, a list of syntax forms."
-    (find (lambda (x)
-            (syntax-case x ()
-              ((clause-key _ ...)
-               (eq? (syntax->datum #'clause-key)
-                    key))))
-          clauses))
-
-  (define (remove-namespace str)
-    "Remove RDF namespace prefix from STR."
-    (substring str (1+ (string-index str #\:))))
-
-  (define (column-id table-name column-name)
-    (string->identifier
-     "field" (string-append
-              ;; We downcase table names in identifiers. So, we
-              ;; distinguish between the user and User tables.
-              (if (string=? table-name "User")
-                  "user2" table-name)
-              "__" column-name)))
-
-  (define (id table predicate)
-    (symbol->string
-     (string->identifier
-      "dump"
-      (string-append
-       table "_" (remove-namespace (symbol->string predicate)))))))
-
-(define-syntax blank-node
-  (syntax-rules ()
-    "Allow having set and multiset within the context of a blank-node"
-    [(_ (op predicate object) ...)
-     (let [(node (string-join
-                  (filter-map (match-lambda
-                                ((pred . obj)
-                                 (match obj
-                                   ((and (?  string? obj)
-                                         (?  string-null? obj))
-                                    #f)
-                                   ((?  symbol? obj)
-                                    (format #f "~a ~a" pred (symbol->string obj)))
-                                   (_
-                                    (format #f "~a ~s" pred obj)))))
-                              (map-alist '()
-                                (op predicate object) ...))
-                  " ; "))]
-       (if (string-null? node)
-           ""
-           (format #f "[ ~a ]" node)))]))
-
-(define-syntax syntax-let
-  (syntax-rules ()
-    "Like match-let, but for syntax.
-
-(syntax-let ((pattern literals expression))
-  body ...)
-≡
-(syntax-case expression ()
-  (pattern literals
-   body ...))
-
-literals is optional. So,
-
-(syntax-let ((pattern expression))
-  body ...)
-≡
-(syntax-case expression ()
-  (pattern
-   body ...))
-"
-    ((_ () body ...)
-     (begin body ...))
-    ((_ ((pattern expression)
-         bindings ...)
-        body ...)
-     (syntax-case expression ()
-       (pattern
-        (syntax-let (bindings ...)
-          body ...))))
-    ((_ ((pattern literals expression)
-         bindings ...)
-        body ...)
-     (syntax-case expression literals
-       (pattern
-        (syntax-let (bindings ...)
-          body ...))))))
-
-(define-syntax define-transformer
-  (lambda (x)
-    "Define FUNCTION-NAME, a function that dumps a view of the database.
-
-define-transformer consists of three order-agnostic clauses---tables,
-schema-triples and triples---in the form shown below.
-
-(define-transformer function-name
-  (tables (table ...) raw-forms ...)
-  (schema-triples
-   (subject predicate object) ...)
-  (triples subject
-    (verb predicate object) ...))
-
-The tables clause specifies the database tables to be joined to
-construct the view to be dumped. TABLE must be either of the form
-TABLE-NAME or of the form (JOIN-OPERATOR TABLE-NAME
-RAW-CONDITION). TABLE-NAME must, obviously, be the name of the
-table. JOIN-OPERATOR must be one of join, left-join and
-inner-join. RAW-CONDITION should be the join condition as a raw
-string. This is usually something like
-\"USING (SpeciesId)\". RAW-FORMS are expressions that must evaluate to
-strings to be appended to the SQL query.
-
-The schema-triples clause specifies the list of triples to be written
-once when the dump starts.
-
-The triples clause specifies the triples to be dumped once for each
-row in the view. All triples have a common SUBJECT. The (verb
-predicate object) clauses are described below.
-
-VERB must either be set or multiset. For the set VERB, a single triple
-(SUBJECT PREDICATE OBJECT-VALUE) is written where OBJECT-VALUE is the
-result of evaluating OBJECT. For the multiset VERB, OBJECT must
-evaluate to a list, and a triple (SUBJECT PREDICATE
-OBJECT-VALUE-ELEMENT) is created for each element OBJECT-VALUE-ELEMENT
-of that list.
-
-The SUBJECT and OBJECT expressions in the triples clause must
-reference database fields using a (field TABLE COLUMN) clause where
-TABLE and COLUMN refer to the table and column of the field being
-referenced. Database fields can also be referenced using (field TABLE
-COLUMN ALIAS) where ALIAS is an alias for that column in the SQL
-query. Specification of ALIAS is indeed a leak in the abstraction, and
-must be remedied."
-    (syntax-case x (tables schema-triples triples)
-      ((_ name clauses ...)
-       (syntax-let (((tables (primary-table other-tables ...) tables-raw ...) (tables)
-                     (find-clause #'(clauses ...) 'tables))
-                    (schema-triples-clause (or (find-clause #'(clauses ...) 'schema-triples)
-                                               #'(schema-triples)))
-                    ((triples subject predicate-clauses ...) (triples)
-                     (find-clause #'(clauses ...) 'triples)))
-         #`(define* (name db #:key
-                          (metadata? #f)
-                          (data? #t)
-                          (documentation? #f))
-             (when metadata?
-               #,@(let ((table (symbol->string (syntax->datum #'primary-table)))
-                        (subject-type (any (lambda (predicate)
-                                             (syntax-case predicate (rdf:type)
-                                               ((_ rdf:type type) #'type)
-                                               (_ #f)))
-                                           #'(predicate-clauses ...))))
-                    (map (lambda (predicate-clause)
-                           (syntax-case predicate-clause ()
-                             ((_ predicate _)
-                              ;; Dump metadata about the dump itself.
-                              #`(begin
-                                  (scm->triples
-                                   (map-alist '()
-	        		     (set rdf:type 'gn-id:dump)
-	        		     (set gn-term:createsPredicate 'predicate)
-	        		     (filter-set gn-term:forSubjectType #,subject-type)
-	        		     (multiset gn-term:dependsOn
-	        			       '#,(map (lambda (field)
-	        					 (match (syntax->datum field)
-	        					   ((table-name column-name _ ...)
-	        					    (datum->syntax
-	        					     x (column-id (symbol->string table-name)
-	        							  (symbol->string column-name))))
-	        					   (((query alias))
-	        					    (datum->syntax
-	        					     x (column-id query (symbol->string alias))))))
-	        				       (collect-fields predicate-clause))))
-                                   #,(id table (syntax->datum #'predicate)))
-                                  ;; Automatically create domain triples
-                                  ;; for predicates.
-                                  (when #,subject-type
-                                    (triple 'predicate 'rdfs:domain #,subject-type))))
-                             (_ (error "Invalid predicate clause:" predicate-clause))))
-                         #'(predicate-clauses ...))))
-             (when documentation?
-               (format #t "~%## '~a'~%~%" (syntax->datum #'name))
-               #,(syntax-case #'schema-triples-clause (schema-triples)
-                   ((schema-triples (triple-subject triple-predicate triple-object) ...)
-                    #`(begin
-                        (when (not (list 'triple-subject ...))
-                          (format #t "## Schema Triples:~%~%```text~%")
-                          (for-each (lambda (s p o)
-                                      (format #t "~a -> ~a -> ~a~%" s p o))
-                                    (list 'triple-subject ...)
-                                    (list 'triple-predicate ...)
-                                    (list 'triple-object ...))
-                          (format #t "```"))))
-                   (_ (error "Invalid schema triples clause:" #'schema-triples-clause)))
-               (format #t "## Generated Triples:
-
-The following SQL query was executed:
-
-```sql
-~a
-```
-
-The above query results to triples that have the form:
-
-```text
-"
-                       (select-query #,(collect-fields #'(subject predicate-clauses ...))
-                                     (primary-table other-tables ...)
-                                     tables-raw ...))
-               (for-each (match-lambda
-                           ((predicate . object)
-                            (format #t "~a -> ~a -> ~a ~%"
-                                    (if (symbol? #,(field->datum #'subject))
-                                        (symbol->string #,(field->datum #'subject))
-                                        #,(field->datum #'subject))
-                                    predicate
-                                    (if (symbol? object)
-                                        (symbol->string object)
-                                        object))))
-                         (map-alist
-                             '()
-                           #,@(field->datum #'(predicate-clauses ...))))
-               (format #t "```~%Here's an example query:~%~%```sparql~%")
-               (documentation?)
-               (newline)
-               (let* ((result
-                       (map-alist (sql-find
-                                   db
-                                   (format #f "~a LIMIT 1"
-                                           (select-query #,(collect-fields #'(subject predicate-clauses ...))
-                                                         (primary-table other-tables ...)
-                                                         tables-raw ...)))
-        		 #,@(field->key #'(predicate-clauses ...))))
-                      (first-n (list-head result
-                                          (let ((n
-                                                 (min 4 (truncate
-                                                         (+ (exact-integer-sqrt (length result)) 1)))))
-                                            (if (< n 3)
-                                                (length result)
-                                                n)))))
-                 (format #t "SELECT * WHERE { ~%")
-                 (for-each (match-lambda
-                             ((predicate . object)
-                              (match object
-                                        ((or (?  symbol? object)
-                                             (?  (lambda (el) (string-match "^\\[ .* \\]$" el)) object))
-                                         (format #t "    ?s ~a ~a .~%" predicate object))
-                                        ((and (? string? object)
-                                              (? (lambda (el) (not (string-null? el))) object))
-                                         (format #t "    ?s ~a \"~a\" .~%" predicate object))
-                                        (_ ""))))
-                           first-n)
-                 (format #t "    ?s ?p ?o .~%}~%```~%"))
-               (format #t "~%Expected Result:~%~%```rdf~%")
-               (sql-for-each (lambda (row)
-                               (scm->triples
-                                (map-alist row #,@(field->key #'(predicate-clauses ...)))
-                                #,(field->assoc-ref #'row #'subject)
-                                (lambda (s p o)
-                                  (triple s p o))))
-                             db
-                             (format #f "~a LIMIT 1"
-                                     (select-query #,(collect-fields #'(subject predicate-clauses ...))
-                                                   (primary-table other-tables ...)
-                                                   tables-raw ...)))
-               (format #t "```~%~%"))
-             (when data?
-               #,(syntax-case #'schema-triples-clause (schema-triples)
-                   ((schema-triples (triple-subject triple-predicate triple-object) ...)
-                    #`(for-each triple
-                                (list 'triple-subject ...)
-                                (list 'triple-predicate ...)
-                                (list 'triple-object ...)))
-                   (_ (error "Invalid schema triples clause:" #'schema-triples-clause)))
-	       (sql-for-each (lambda (row)
-                               (scm->triples
-                                (map-alist row #,@(field->key #'(predicate-clauses ...)))
-                                #,(field->assoc-ref #'row #'subject)))
-                             db
-                             (select-query #,(collect-fields #'(subject predicate-clauses ...))
-                                           (primary-table other-tables ...)
-                                           tables-raw ...)))
-             )))
-      (_ (error "Invalid define-transformer syntax:" (syntax->datum x))))))
-
-(define (get-keyword-value args keyword default)
-  (let ((kv (memq keyword args)))
-    (if (and kv (>= (length kv) 2))
-        (cadr kv)
-        default)))
-
-(define-syntax with-documentation
-  (syntax-rules ()
-    ((_ (key value) ...)
-     (let* ((alist `((key . ,value) ...))
-            (name (assoc-ref alist 'name))
-            (connection (assoc-ref alist 'connection))
-            (table-metadata? (assoc-ref alist 'table-metadata?))
-            (prefixes (assoc-ref alist 'prefixes))
-            (inputs (assoc-ref alist 'inputs))
-            (outputs (assoc-ref alist 'outputs))
-            (rdf-path (get-keyword-value outputs #:rdf ""))
-            (doc-path (get-keyword-value outputs #:documentation "")))
-       (call-with-target-database
-        connection
-        (lambda (db)
-          (with-output-to-file        ;
-              doc-path
-            (lambda ()
-              (format #t "# ~a" name)
-              (for-each
-               (lambda (proc)
-                 (proc db
-                       #:metadata? #f
-                       #:data? #f
-                       #:documentation?
-                       (lambda () (for-each
-                                   (match-lambda
-                                     ((k v)
-                                      (begin
-                                        (prefix k v #f))))
-                                   prefixes))))
-               inputs))
-            #:encoding "UTF-8")
-
-          ;; Dumping the actual data
-          (with-output-to-file
-              rdf-path
-            (lambda ()
-              ;; Add the prefixes
-              (for-each
-               (match-lambda
-                 ((k v)
-                  (begin
-                    (prefix k v))))
-               prefixes)
-              (newline)
-              (for-each
-               (lambda (proc)
-                 (proc db #:metadata? table-metadata?))
-               inputs))
-            #:encoding "UTF-8")))))))
-