diff options
author | Christopher Baines <mail@cbaines.net> | 2019-09-04 12:52:12 +0200 |
---|---|---|
committer | Christopher Baines <mail@cbaines.net> | 2019-09-04 12:52:12 +0200 |
commit | 14419422008cc1ba42dea5ef90e6fb2762633064 (patch) | |
tree | 90ee30a94a7784b6d53a9c1a0c178fb8336687a7 | |
parent | 902560d56bb111bb6b44989a0b3a8bdd36313090 (diff) | |
download | data-service-14419422008cc1ba42dea5ef90e6fb2762633064.tar data-service-14419422008cc1ba42dea5ef90e6fb2762633064.tar.gz |
Hack better NULL support on to (squee)
PQgetvalue used by squee returns null values as empty strings, which are
ambiguous for string fields. Therefore, use PQgetisnull to implement a
serialiser for squee which checks empty strings to see if they're actually a
NULL value, then returns '() in this case.
exec-query-with-null-handling can be used to access this behaviour.
-rw-r--r-- | guix-data-service/database.scm | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/guix-data-service/database.scm b/guix-data-service/database.scm index 140ea44..0d6d61b 100644 --- a/guix-data-service/database.scm +++ b/guix-data-service/database.scm @@ -16,12 +16,15 @@ ;;; <http://www.gnu.org/licenses/>. (define-module (guix-data-service database) + #:use-module (system foreign) #:use-module (squee) #:export (with-postgresql-connection with-postgresql-transaction with-advisory-session-lock - obtain-advisory-transaction-lock)) + obtain-advisory-transaction-lock + + exec-query-with-null-handling)) ;; TODO This isn't exported for some reason (define pg-conn-finish @@ -80,3 +83,36 @@ (exec-query conn "SELECT pg_advisory_xact_lock($1)" (list lock-number)))) + +(define squee/libpq + (@@ (squee) libpq)) + +(define squee/unwrap-result-ptr + (@@ (squee) unwrap-result-ptr)) + +(define %PQgetisnull + (pointer->procedure int + (dynamic-func "PQgetisnull" squee/libpq) + (list '* int int))) + +(define (result-serializer-simple-list-with-null-handling result-ptr) + "Get a simple list of lists representing the result of the query" + (let ((rows-range (iota (result-num-rows result-ptr))) + (cols-range (iota (result-num-cols result-ptr)))) + (map + (lambda (row-i) + (map + (lambda (col-i) + (let ((val (result-get-value result-ptr row-i col-i))) + (if (string-null? val) + (if (eq? 1 (%PQgetisnull + (squee/unwrap-result-ptr result-ptr) row-i col-i)) + '() + val) + val))) + cols-range)) + rows-range))) + +(define* (exec-query-with-null-handling pg-conn command #:optional (params '())) + (exec-query pg-conn command params + #:serializer result-serializer-simple-list-with-null-handling)) |