collect.lisp 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. ;;;; collect.lisp
  2. ;;;;
  3. ;;;; Copyright (c) 2015 Samuel W. Flint <swflint@flintfam.org>
  4. (in-package #:collect)
  5. ;;; "collect" goes here. Hacks and glory await!
  6. (defun to-sql-type (type)
  7. (cadr (assoc type '((:integer "INTEGER")
  8. (:text "TEXT")
  9. (:real "REAL")
  10. (:blob "BLOB")))))
  11. (defun relation (relationship)
  12. (if (not (null relationship))
  13. (destructuring-bind (table column) relationship
  14. (declare (string table column))
  15. (format nil " REFERENCES ~a (~a)"
  16. table
  17. column))
  18. ""))
  19. (defun col-to-clause (column)
  20. (destructuring-bind (name type &key (nullable t) (primary nil) relationship) column
  21. (declare (string name)
  22. (keyword type)
  23. (ignorable nullable relationship))
  24. (if (null primary)
  25. (if (null nullable)
  26. (format nil "~a ~a~a,"
  27. name
  28. (to-sql-type type)
  29. (relation relationship))
  30. (format nil "~a ~a~a NOT NULL,"
  31. name
  32. (to-sql-type type)
  33. (relation relationship)))
  34. (format nil "~a ~a PRIMARY KEY,"
  35. name
  36. (to-sql-type type)))))
  37. (defmacro define-table (name (&rest cols) &key &allow-other-keys)
  38. (let* ((clauses (map 'list #'col-to-clause cols))
  39. (sql-command (format nil "CREATE TABLE IF NOT EXISTS ~a~%(~%~{~a~%~});"
  40. name
  41. clauses)))
  42. `(list ,sql-command)))
  43. (defun make-form-entry (entry)
  44. (destructuring-bind (label column &key (type :text) other-column options) entry
  45. (declare (string label column)
  46. (ignorable other-column options))
  47. (let ((label-name (concatenate 'string "fld_" column))
  48. (the-options (if (null options)
  49. (if (not (null other-column))
  50. `(,(car other-column) ,(cadr other-column))))))
  51. (case type
  52. (:text
  53. `(:tr
  54. (:td ,label)
  55. (:td (:input :type :text
  56. :name ,label-name))))
  57. (:drop-down
  58. `(:tr
  59. (:td ,label)
  60. (:td
  61. (:select :name ,label-name
  62. (loop for option in ,the-options
  63. collect (make-option-drop-down option))))))
  64. (:radio-buttons
  65. `(:tr
  66. (:td ,label)
  67. (:td (loop for option in ,the-options
  68. collect (make-option-radio option ,label-name)))))))))
  69. (defun make-option-drop-down (option)
  70. (let ((name (first option))
  71. (value (second option)))
  72. `(:option :value ,value ,name)))
  73. (defun make-option-radio (option label)
  74. (let ((name (first option))
  75. (value (second option)))
  76. `(:div (:input :type "radio" :name ,label :value ,value)
  77. ,name (:br))))
  78. (defmacro define-form (name table (&rest fields) &key &allow-other-keys)
  79. (let* ((columns (map 'list #'second fields))
  80. (field-names (map 'list #'(lambda (column)
  81. (concatenate 'string "fld_" column))
  82. columns))
  83. (form-entries (map 'list #'make-form-entry fields)))
  84. `(list (list ,@columns)
  85. (list ,@field-names))))