unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Danny Milosavljevic <dannym@scratchpost.org>
To: guix-devel@gnu.org, ludo@gnu.org
Subject: [PATCH] database: Simplify 'db-get-builds'.
Date: Mon, 19 Feb 2018 16:35:46 +0100	[thread overview]
Message-ID: <20180219153546.16173-1-dannym@scratchpost.org> (raw)
In-Reply-To: <20180219163506.2037e56e@scratchpost.org>

* src/cuirass/database.scm (db-get-builds): Modify.
(db-get-build): Modify.
---
 src/cuirass/database.scm | 165 ++++++++++++++++-------------------------------
 1 file changed, 55 insertions(+), 110 deletions(-)

diff --git a/src/cuirass/database.scm b/src/cuirass/database.scm
index dd3e5a2..5a4631f 100644
--- a/src/cuirass/database.scm
+++ b/src/cuirass/database.scm
@@ -26,6 +26,7 @@
   #:use-module (ice-9 rdelim)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-19)
+  #:use-module (srfi srfi-26)
   #:use-module (sqlite3)
   #:export (;; Procedures.
             db-init
@@ -347,15 +348,6 @@ log file for DRV."
              (cons `(,name . ((#:path . ,path)))
                    outputs))))))
 
-(define db-build-request "\
-SELECT Builds.id, Builds.timestamp, Builds.starttime, Builds.stoptime, Builds.log, Builds.status, Builds.derivation,\
-Derivations.job_name, Derivations.system, Derivations.nix_name,\
-Specifications.repo_name, Specifications.branch \
-FROM Builds \
-INNER JOIN Derivations ON Builds.derivation = Derivations.derivation and Builds.evaluation = Derivations.evaluation \
-INNER JOIN Evaluations ON Derivations.evaluation = Evaluations.id \
-INNER JOIN Specifications ON Evaluations.specification = Specifications.repo_name")
-
 (define (db-format-build db build)
   (match build
     (#(id timestamp starttime stoptime log status derivation job-name system
@@ -374,112 +366,65 @@ INNER JOIN Specifications ON Evaluations.specification = Specifications.repo_nam
        (#:outputs    . ,(db-get-outputs db id))
        (#:branch     . ,branch)))))
 
-(define (db-get-build db id)
-  "Retrieve a build in database DB which corresponds to ID."
-  (let ((res (sqlite-exec db (string-append db-build-request
-                                            " WHERE Builds.id=")
-                          id ";")))
-    (match res
-      ((build)
-       (db-format-build db build))
-      (() #f))))
-
 (define (db-get-builds db filters)
   "Retrieve all builds in database DB which are matched by given FILTERS.
 FILTERS is an assoc list which possible keys are 'project | 'jobset | 'job |
 'system | 'nr | 'order | 'status."
 
-  (define (clauses->query+arguments clauses)
-    ;; Given CLAUSES, return two values: a SQL query string, and a list of
-    ;; arguments to bind.  Each element of CLAUSES must be either a string, or
-    ;; a (SQL ARGUMENT) tuple, where SQL is a query fragment and ARGUMENT is
-    ;; the argument to be bound for that fragment.
-    (let loop ((clauses   clauses)
-               (query     '())
-               (arguments '()))
-      (match clauses
-        (()
-         (values (string-concatenate-reverse query)
-                 (reverse arguments)))
-        (((? string? clause) . rest)
-         (loop rest
-               (cons clause query)
-               arguments))
-        ((((? string? clause) argument) . rest)
-         (loop rest
-               (cons clause query)
-               (cons argument arguments))))))
-
-  (define (where-clauses filters)
-    (match (filter-map (match-lambda
-                         (('project project)
-                          (list "Specifications.repo_name=?" project))
-                         (('jobset jobset)
-                          (list "Specifications.branch=?" jobset))
-                         (('job job)
-                          (list "Derivations.job_name=?" job))
-                         (('system system)
-                          (list "Derivations.system=?" system))
-                         (('status 'done)
-                          "Builds.status >= 0")
-                         (('status 'pending)
-                          "Builds.status < 0")
-                         (_ #f))
-                       filters)
-      (()
-       '(""))
-      ((clause)
-       (list "WHERE " clause))
-      ((clause0 rest ...)
-       (cons* "WHERE " clause0
-              (fold-right (lambda (clause result)
-                            `(" AND " ,clause ,@result))
-                          '()
-                          rest)))))
-
-  (define (order-clause filters)
-    (or (any (match-lambda
-               (('order 'build-id)
-                "ORDER BY Builds.id ASC")
-               (('order 'decreasing-build-id)
-                "ORDER BY Builds.id DESC")
-               (('order 'finish-time)
-                "ORDER BY Builds.stoptime DESC")
-               (('order 'start-time)
-                "ORDER BY Builds.start DESC")
-               (('order 'submission-time)
-                "ORDER BY Builds.timestamp DESC")
-               (('order 'status+submission-time)
-                ;; With this order, builds in 'running' state (-1) appear
-                ;; before those in 'scheduled' state (-2).
-                "ORDER BY Builds.status DESC, Builds.timestamp DESC")
-               (_ #f))
-             filters)
-        "ORDER BY Builds.id DESC"))               ;default order
-
-  (define (limit-clause filters)
-    (or (any (match-lambda
-               (('nr number)
-                (list "LIMIT ?" number))
-               (_ #f))
-             filters)
-        ""))
-
-  (call-with-values
-      (lambda ()
-        (clauses->query+arguments (append (list db-build-request " ")
-                                          (where-clauses filters) '(" ")
-                                          (list (order-clause filters) " ")
-                                          (list (limit-clause filters) " "))))
-    (lambda (sql arguments)
-      (let loop ((rows    (apply %sqlite-exec db sql arguments))
-                 (outputs '()))
-        (match rows
-          (()
-           (reverse outputs))
-          ((row . rest)
-           (loop rest
-                 (cons (db-format-build db row) outputs))))))))
+  ;; XXX Change caller and remove
+  (define (assqx-ref filters key)
+    (if (null? filters)
+        #f
+        (match (car filters)
+         ((xkey xvalue) (if (eq? key xkey)
+                            xvalue
+                            (assqx-ref (cdr filters) key))))))
+  (let* ((order (if (eq? (assqx-ref filters 'order) 'build-id)
+                     "ASC"
+                     "DESC"))
+         (order-column-name
+          (match (assqx-ref filters 'order)
+                  (('order 'build-id) "Builds.id")
+                  (('order 'decreasing-build-id) "Builds.id")
+                  (('order 'finish-time) "Builds.stoptime")
+                  (('order 'start-time) "Builds.starttime")
+                  (('order 'submission-time) "Builds.timestamp")
+                  (_ "Builds.id")))
+         (stmt-text (format #f "\
+SELECT Builds.id, Builds.timestamp, Builds.starttime, Builds.stoptime, Builds.log, Builds.status, Builds.derivation,\
+Derivations.job_name, Derivations.system, Derivations.nix_name,\
+Specifications.repo_name, Specifications.branch \
+FROM Builds \
+INNER JOIN Derivations ON Builds.derivation = Derivations.derivation AND Builds.evaluation = Derivations.evaluation \
+INNER JOIN Evaluations ON Derivations.evaluation = Evaluations.id \
+INNER JOIN Specifications ON Evaluations.specification = Specifications.repo_name \
+WHERE (:id IS NULL OR (:id = Builds.id)) \
+OR (:project IS NULL OR (:project = Specifications.repo_name)) \
+OR (:jobset IS NULL OR (:jobset = Specifications.branch)) \
+OR (:job IS NULL OR (:job = Derivations.job_name)) \
+OR (:system IS NULL OR (:system = Derivations.system)) \
+OR (:status IS NULL OR (:status = 'done' AND Builds.status >= 0) OR (:status = 'pending' AND Builds.status < 0)) \
+ORDER BY ~a ~a LIMIT :nr;" order-column-name order))
+         (stmt (sqlite-prepare db stmt-text #:cache? #t)))
+    (sqlite-bind-arguments stmt #:id (assqx-ref filters 'id)
+                                #:project (assqx-ref filters 'project)
+                                #:jobset (assqx-ref filters 'jobset)
+                                #:job (assqx-ref filters 'job)
+                                #:system (assqx-ref filters 'system)
+                                #:status (and=> (assqx-ref filters 'status)
+                                                object->string)
+                                #:nr (match (assqx-ref filters 'nr)
+                                      (#f -1)
+                                      (x x)))
+    (map (cut db-format-build db <>)
+         (sqlite-fold-right cons '() stmt))))
+
+(define (db-get-build db id)
+  "Retrieve a build in database DB which corresponds to ID."
+  (match (db-get-builds db '(('id id)))
+    ((build)
+     build)
+    (() #f)))
 
 (define (db-get-stamp db spec)
   "Return a stamp corresponding to specification SPEC in database DB."

  reply	other threads:[~2018-02-19 15:36 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-24 22:12 Cuirass news Ludovic Courtès
2018-01-25 10:55 ` Mathieu Othacehe
2018-01-25 10:59   ` Mathieu Othacehe
2018-01-25 13:09     ` Ludovic Courtès
2018-01-26 14:30       ` Danny Milosavljevic
2018-01-27 16:01         ` Ludovic Courtès
2018-01-27 17:18           ` Danny Milosavljevic
2018-01-27 19:12             ` Danny Milosavljevic
2018-01-28 21:47             ` Ludovic Courtès
2018-01-28 22:23               ` Danny Milosavljevic
2018-01-29  9:57               ` Andy Wingo
2018-02-08 13:37             ` Ludovic Courtès
2018-02-08 16:29               ` Danny Milosavljevic
2018-02-08 22:21                 ` Ludovic Courtès
2018-02-08 23:05                   ` Danny Milosavljevic
2018-02-09  6:17                     ` Gábor Boskovits
2018-02-09  9:41                     ` Ludovic Courtès
2018-02-09 11:29                       ` Danny Milosavljevic
2018-02-09 16:53                         ` Ludovic Courtès
2018-02-09 17:06                           ` Danny Milosavljevic
2018-02-10 11:18                             ` Ludovic Courtès
2018-02-13  9:12                               ` Danny Milosavljevic
2018-02-14 13:43                                 ` Ludovic Courtès
2018-02-14 23:17                                   ` Ludovic Courtès
2018-02-19 15:35                                     ` Danny Milosavljevic
2018-02-19 15:35                                       ` Danny Milosavljevic [this message]
2018-02-19 17:52                                       ` [PATCH] database: db-get-builds: Inline output selection Danny Milosavljevic
2018-02-19 22:08                                       ` Cuirass news Danny Milosavljevic
2018-03-02 13:21                                         ` Ludovic Courtès
2018-03-02 22:06                                           ` Ludovic Courtès
2018-03-02 23:29                                           ` Danny Milosavljevic
2018-02-14 23:21                                   ` Ludovic Courtès
2018-01-25 21:06 ` Ricardo Wurmus
2018-01-26 11:12   ` Ludovic Courtès
2018-01-25 22:28 ` Danny Milosavljevic
2018-01-26 10:47   ` Ludovic Courtès
2018-01-28 12:33     ` Cuirass frontend Danny Milosavljevic
2018-01-29 17:42       ` Ludovic Courtès
2018-01-26  0:46 ` Cuirass news Danny Milosavljevic
2018-01-27 17:27   ` Danny Milosavljevic
2018-01-28 21:48     ` Ludovic Courtès
2018-01-26 17:55 ` Jan Nieuwenhuizen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180219153546.16173-1-dannym@scratchpost.org \
    --to=dannym@scratchpost.org \
    --cc=guix-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).