;;; 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 #:head #:time-stamp #:data #:container #:make-item #:insert #:create-indexes #:create-table)) (in-package :scopes/storage/tracking) (defclass track () ((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))) (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 value-list (track) (let ((vl (head track)) (data (data track)) (ts (time-stamp track))) (if ts (setf (getf vl :time-stamp) 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)))) (storage:do-sql st (sxql:insert-into table (sxql:set= :taskid "t01"))))) (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))))))