db.lisp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. (in-package #:chatikbot)
  2. (defvar *db-name* "db.sqlite" "SQLite database name")
  3. (defun db-path ()
  4. (merge-pathnames *db-name*
  5. (asdf:component-pathname
  6. (asdf:find-system '#:chatikbot))))
  7. (defvar *current-db* nil "Currently opened database")
  8. (defmacro with-db ((db) &body body)
  9. `(if *current-db*
  10. (let ((,db *current-db*))
  11. (declare (ignorable ,db))
  12. ,@body)
  13. (sqlite:with-open-database (,db (db-path) :busy-timeout 30)
  14. (sqlite:execute-non-query ,db "PRAGMA foreign_keys = ON")
  15. (let ((*current-db* ,db))
  16. ,@body))))
  17. (defmacro db-transaction (&body body)
  18. (let ((db (gensym "DB-")))
  19. `(with-db (,db)
  20. (sqlite:with-transaction ,db ,@body))))
  21. (defun db-execute (sql &rest parameters)
  22. (with-db (db)
  23. (apply #'sqlite:execute-non-query db sql parameters)
  24. (sqlite:last-insert-rowid db)))
  25. (defun db-select (sql &rest parameters)
  26. (with-db (db)
  27. (apply #'sqlite:execute-to-list db sql parameters)))
  28. (defun db-single (sql &rest parameters)
  29. (with-db (db)
  30. (apply #'sqlite:execute-single db sql parameters)))
  31. (defmacro def-db-init (&body body)
  32. `(add-hook :db-init #'(lambda ()
  33. (handler-case (progn ,@body)
  34. (error (e) (log:error e)))
  35. (values))))
  36. (defun db-init ()
  37. (with-db (db)
  38. (db-execute "create table if not exists settings (var, val)")
  39. (db-execute "create unique index if not exists settings_var_unique on settings (var)")
  40. (db-execute "create table if not exists lists (list, entry)")
  41. (db-execute "create unique index if not exists lists_unique on lists (list, entry)")))
  42. (defun load-settings ()
  43. (let ((*package* (find-package :chatikbot)))
  44. (loop for (var val) in (db-select "select var, val from settings")
  45. do (setf (symbol-value (intern var))
  46. (handler-case (read-from-string val)
  47. (error (e) (log:error e)))))))
  48. (defun set-setting (symbol value)
  49. (handler-case
  50. (let ((*package* (find-package :chatikbot)))
  51. (db-execute "replace into settings (var, val) values (?, ?)"
  52. (symbol-name symbol)
  53. (write-to-string value))
  54. (setf (symbol-value symbol) value))
  55. (error (e) (log:error e))))
  56. (defun lists-set-entry (list entry &optional (add t))
  57. (with-db (db)
  58. (handler-case
  59. (if add
  60. (db-execute "insert into lists (list, entry) values (?, ?)"
  61. (dekeyify list) entry)
  62. (db-execute "delete from lists where list = ? and entry = ?"
  63. (dekeyify list) entry))
  64. (sqlite:sqlite-constraint-error ()
  65. nil))))
  66. (defun lists-get (list)
  67. (with-db (db)
  68. (mapcar #'car (db-select "select entry from lists where list = ?" (dekeyify list)))))