96 lines
3.4 KiB
Common Lisp
96 lines
3.4 KiB
Common Lisp
;;; cl-scopes/storage/tracking.lisp
|
|
|
|
;;;; A simple generic (SQL-based) storage for tracks, messages, and other stuff.
|
|
|
|
(defpackage :scopes/storage/tracking
|
|
(:use :common-lisp)
|
|
(:local-nicknames (:storage :scopes/storage))
|
|
(:export #:track #:trackid #:head #:head-proplist #:time-stamp #:data
|
|
#:container
|
|
#:make-item
|
|
#:insert
|
|
#:create-indexes #:create-table))
|
|
|
|
(in-package :scopes/storage/tracking)
|
|
|
|
(defclass track ()
|
|
((trackid :accessor trackid :initform nil)
|
|
(head :accessor head :initarg :head)
|
|
(time-stamp :accessor time-stamp :initform nil)
|
|
(data :accessor data :initform nil)
|
|
(container :reader container :initarg :container)))
|
|
|
|
(defun engine (tr)
|
|
(storage:engine (storage (container tr))))
|
|
|
|
(defclass container ()
|
|
((item-factory :initform #'(lambda (cont head)
|
|
(make-instance 'track :container cont :head head)))
|
|
(head-fields :reader head-fields :initform '(:taskid :username))
|
|
(table-name :reader table-name :initform :tracks)
|
|
(indexes :reader indexes :initform '((taskid username) (username)))
|
|
(storage :reader storage :initarg :storage)))
|
|
|
|
(defun make-item (cont &rest head)
|
|
(funcall (slot-value cont 'item-factory) cont head))
|
|
|
|
(defun head-proplist (track)
|
|
(let (pl (hv (head track)))
|
|
(dolist (hf (head-fields (container track)))
|
|
(setf (getf pl hf) (if (car hv) (car hv) ""))
|
|
(setf hv (cdr hv)))
|
|
pl))
|
|
|
|
(defun proplist (track)
|
|
(let ((vl (head-proplist track)))
|
|
(with-slots ((trid trackid) (ts time-stamp) data) track
|
|
(if trid (setf (getf vl :trackid) trid))
|
|
(if ts (setf (getf vl :timestamp)
|
|
(storage:timestamp-to-sql (engine track) ts)))
|
|
(if data (setf (getf vl :data) data)))
|
|
vl))
|
|
|
|
(defun insert (track)
|
|
(let* ((cont (container track))
|
|
(st (storage cont))
|
|
(table (storage:qualified-table-name st (table-name cont)))
|
|
(res (car (storage:query st
|
|
(sxql:insert-into table
|
|
(apply #'sxql:make-clause ':set= (proplist track))
|
|
(sxql:returning :trackid :timestamp))))))
|
|
(setf (trackid track) (cadr res))
|
|
(setf (time-stamp track) (cadddr res))
|
|
track))
|
|
|
|
(defun create-table (cont)
|
|
(let*
|
|
((st (storage cont))
|
|
(tn (table-name cont))
|
|
(table (storage:qualified-table-name st tn))
|
|
(head-fields (head-fields cont))
|
|
(params (storage:db-params st))
|
|
(id-type (getf params :id-type))
|
|
(json-type (getf params :json-type))
|
|
(hf-def (mapcar #'(lambda (x)
|
|
(list x :type 'text :not-null t :default '|''|))
|
|
head-fields)))
|
|
(storage:do-sql st
|
|
(sxql:make-statement :create-table table
|
|
(nconc
|
|
`((trackid :type ,id-type :primary-key t :not-null t))
|
|
hf-def
|
|
`((timestamp :type timestamptz :not-null t :default current_timestamp)
|
|
(data :type ,json-type :not-null t :default |'{}'|)))))
|
|
(create-indexes st table tn (indexes cont))))
|
|
|
|
(defun create-indexes (st table tname ixs)
|
|
(let ((i 1)
|
|
(tn (symbol-name tname)))
|
|
(dolist (ix ixs)
|
|
(let ((ixname (intern (format nil "IDX_~a_~d" tn i))))
|
|
(incf i)
|
|
(storage:do-sql st
|
|
(sxql:create-index ixname :on (cons table ix)))))
|
|
(storage:do-sql st
|
|
(sxql:create-index (intern (format nil "IDX_~a_TS" tn))
|
|
:on (cons table '(timestamp))))))
|