aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2019-09-04 12:52:12 +0200
committerChristopher Baines <mail@cbaines.net>2019-09-04 12:52:12 +0200
commit14419422008cc1ba42dea5ef90e6fb2762633064 (patch)
tree90ee30a94a7784b6d53a9c1a0c178fb8336687a7
parent902560d56bb111bb6b44989a0b3a8bdd36313090 (diff)
downloaddata-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.scm38
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))