feat(lisp): Implement persistent storage via cl-prevalence

Uses the cl-prevalence system to store tasks on disk. The storage
location is either relative to the working directory in which the
system is started or determined (with priority) by the environment
variable `GEMMA_DATA_DIR`.
This commit is contained in:
Vincent Ambo 2017-12-21 01:21:11 +01:00
parent 51ddb8fb53
commit a8d46a358e
2 changed files with 45 additions and 19 deletions

View file

@ -13,7 +13,10 @@
:version "0.1.0" :version "0.1.0"
:author "Vincent Ambo" :author "Vincent Ambo"
:license "GPLv3" :license "GPLv3"
:depends-on (alexandria local-time hunchentoot yason) :depends-on (local-time
hunchentoot
cl-json
cl-prevalence)
:components ((:module "src" :components ((:module "src"
:components :components
((:file "gemma")))) ((:file "gemma"))))

View file

@ -9,7 +9,6 @@
(defpackage gemma (defpackage gemma
(:use :cl (:use :cl
:alexandria
:hunchentoot :hunchentoot
:local-time :local-time
:cl-json)) :cl-json))
@ -23,7 +22,10 @@
;; Define task management system ;; Define task management system
;; ;;
(defclass task () (defclass task ()
(;; (Unique) name of the task ((id :reader id
:initarg :id)
;; (Unique) name of the task
(name :type symbol (name :type symbol
:initarg :name :initarg :name
:accessor name-of) :accessor name-of)
@ -40,24 +42,38 @@
;; Last completion time ;; Last completion time
(done-at :type local-time:timestamp (done-at :type local-time:timestamp
:initarg :done-at
:accessor last-done-at))) :accessor last-done-at)))
(defvar *tasks* (defvar *gemma-data-dir*
(make-hash-table) (pathname (or (sb-posix:getenv "GEMMA_DATA_DIR")
"List of all tasks registered in this Gemma instance.") (sb-posix:getcwd)))
"Directory in which to store Gemma data.")
(defvar *p-tasks*
(cl-prevalence:make-prevalence-system *gemma-data-dir*)
"All tasks registered in this Gemma instance.")
;; Initialise database ID counter
(or (> (length (cl-prevalence:find-all-objects *p-tasks* 'task)) 0)
(cl-prevalence:tx-create-id-counter *p-tasks*))
(defmacro deftask (task-name days &optional description) (defmacro deftask (task-name days &optional description)
`(setf (gethash (quote ,task-name) *tasks*) (unless (get-task task-name)
(make-instance (quote task) `(progn (cl-prevalence:tx-create-object
:name (quote ,task-name) *p-tasks*
:days ,days 'task
:description (or ,description "")))) (quote ((name ,task-name)
(days ,days)
(description ,(or description ""))
(done-at ,(local-time:now)))))
(cl-prevalence:snapshot *p-tasks*))))
(defun get-task (name) (defun get-task (name)
(gethash name *tasks*)) (cl-prevalence:find-object-with-slot *p-tasks* 'task 'name name))
(defun list-tasks () (defun list-tasks ()
(alexandria:hash-table-values *tasks*)) (cl-prevalence:find-all-objects *p-tasks* 'task))
(defun days-remaining (task) (defun days-remaining (task)
"Returns the number of days remaining before the supplied TASK reaches its "Returns the number of days remaining before the supplied TASK reaches its
@ -76,8 +92,9 @@ maximum interval."
(defun complete-task (name &optional at) (defun complete-task (name &optional at)
"Mark the task with NAME as completed, either now or AT specified time." "Mark the task with NAME as completed, either now or AT specified time."
(setf (last-done-at (get-task name)) (cl-prevalence:tx-change-object-slots *p-tasks* 'task
(or at (local-time:now)))) (id (get-task name))
`((done-at ,(or at (local-time:now))))))
;; ;;
;; Define web API ;; Define web API
@ -139,9 +156,15 @@ maximum interval."
(defun randomise-completion-times () (defun randomise-completion-times ()
"Set some random completion timestamps for all tasks" "Set some random completion timestamps for all tasks"
(mapcar (mapcar
(lambda (key) (complete-task key (local-time:timestamp- (local-time:now) (lambda (task)
(complete-task (name-of task)
(local-time:timestamp- (local-time:now)
(random 14) (random 14)
:day))) :day)))
(alexandria:hash-table-keys *tasks*))) (cl-prevalence:find-all-objects *p-tasks* 'task)))
(defun clear-all-tasks ()
(mapcar (lambda (task) (cl-prevalence:tx-delete-object *p-tasks* 'task (id task)))
(cl-prevalence:find-all-objects *p-tasks* 'task)))
;; (randomise-completion-times) ;; (randomise-completion-times)