Files
emacs/lisp/emacsql/emacsql-pg.el
2025-02-26 20:16:44 +01:00

81 lines
3.0 KiB
EmacsLisp

;;; emacsql-pg.el --- EmacSQL back-end for PostgreSQL via pg -*- lexical-binding:t -*-
;; This is free and unencumbered software released into the public domain.
;; Author: Christopher Wellons <wellons@nullprogram.com>
;; Maintainer: Jonas Bernoulli <emacs.emacsql@jonas.bernoulli.dev>
;; SPDX-License-Identifier: Unlicense
;;; Commentary:
;; This library provides an EmacSQL back-end for PostgreSQL, which
;; uses the `pg' package to directly speak to the database. This
;; library requires at least Emacs 28.1.
;; (For an alternative back-end for PostgreSQL, see `emacsql-psql'.)
;;; Code:
(require 'emacsql)
(if (>= emacs-major-version 28)
(require 'pg nil t)
(message "emacsql-pg.el requires Emacs 28.1 or later"))
(declare-function pg-connect "pg"
( dbname user &optional
(password "") (host "localhost") (port 5432) (tls nil)))
(declare-function pg-disconnect "pg" (con))
(declare-function pg-exec "pg" (connection &rest args))
(declare-function pg-result "pg" (result what &rest arg))
(defclass emacsql-pg-connection (emacsql-connection)
((pgcon :reader emacsql-pg-pgcon :initarg :pgcon)
(dbname :reader emacsql-pg-dbname :initarg :dbname)
(result :accessor emacsql-pg-result)
(types :allocation :class
:reader emacsql-types
:initform '((integer "BIGINT")
(float "DOUBLE PRECISION")
(object "TEXT")
(nil "TEXT"))))
"A connection to a PostgreSQL database via pg.el.")
(cl-defun emacsql-pg (dbname user &key
(host "localhost") (password "") (port 5432) debug)
"Connect to a PostgreSQL server using pg.el."
(require 'pg)
(let* ((pgcon (pg-connect dbname user password host port))
(connection (make-instance 'emacsql-pg-connection
:handle (and (fboundp 'pgcon-process)
(pgcon-process pgcon))
:pgcon pgcon
:dbname dbname)))
(when debug (emacsql-enable-debugging connection))
(emacsql connection [:set (= default-transaction-isolation 'SERIALIZABLE)])
(emacsql-register connection)))
(cl-defmethod emacsql-close ((connection emacsql-pg-connection))
(ignore-errors (pg-disconnect (emacsql-pg-pgcon connection))))
(cl-defmethod emacsql-send-message ((connection emacsql-pg-connection) message)
(condition-case error
(setf (emacsql-pg-result connection)
(pg-exec (emacsql-pg-pgcon connection) message))
(error (signal 'emacsql-error error))))
(cl-defmethod emacsql-waiting-p ((_connection emacsql-pg-connection))
;; pg-exec will block
t)
(cl-defmethod emacsql-parse ((connection emacsql-pg-connection))
(let ((tuples (pg-result (emacsql-pg-result connection) :tuples)))
(cl-loop for tuple in tuples collect
(cl-loop for value in tuple
when (stringp value) collect (read value)
else collect value))))
(provide 'emacsql-pg)
;;; emacsql-pg.el ends here