Yu-Gi-Oh! Deck Building and Card Inventory Management web interface written in Common Lisp, utilizing HTMX.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

139 lignes
5.2KB

  1. #|
  2. src/web/search.lisp
  3. This is some ancient old dusty code that had preminitions of how
  4. things would work in the future.
  5. The idea was that there'd be a list of default parameters, maybe
  6. you've seen it in the code, *SEARCH-DEFAULTS*. And this machinery
  7. would query that default, then build an SQL query to hit the
  8. database based on what was read from Caveman2.
  9. This code needs a rewrite.
  10. |#
  11. (in-package #:cl-deck-builder2.web)
  12. ;; TODO defstruct search-params?
  13. (defparameter *search-defaults*
  14. '(("direction" . "asc")
  15. ("limit" . "10")
  16. ("name" . "")
  17. ("variant" . (1 . "on"))
  18. ("offset" . "0")
  19. ("sort-by" . "id")))
  20. (defun make-op-list (kind name value &key (fuzzy nil))
  21. (if fuzzy
  22. (setf kind "LIKE"
  23. value (format nil "%~a%" value)))
  24. (list
  25. (alexandria:make-keyword kind)
  26. (alexandria:make-keyword (string-upcase
  27. (substitute #\_ #\- name)))
  28. value))
  29. (defparameter +param-field-whitelist+
  30. '("amazon-asin" "barcode" "brand" "buy-price" "category" "code" "created-by"
  31. "deck-id" "desc" "description" "domestic-only" "edition" "email" "id" "kind"
  32. "linkmarkers" "linkval" "manufacturer-sku" "max-qty" "msrp" "parent" "price"
  33. "product-name" "rarity" "rarity-code" "sell-price" "tax-exempt" "total-qty"
  34. "url" "weight" "wishlists" "atk" "def" "level" "scale" "passcode" "type"
  35. "frame-type" "race" "attribute" "archetype" "name" "opt-qty" "qty" "condition")
  36. "A whitelist of keywords allowed by user input on the database side.")
  37. (defun filter-alist (alist &optional (whitelist +param-field-whitelist+))
  38. "Filter ALIST by CAR matching MEMBER in WHITELIST."
  39. (remove-if (lambda (pair)
  40. (destructuring-bind (key . value)
  41. pair
  42. (if (and (member key whitelist :test #'equal)
  43. value
  44. (> (length value) 0))
  45. nil
  46. t)))
  47. alist))
  48. ;; (defparameter *variant-id*
  49. ;; (mito:object-id (find-dao 'variant :name "Near Mint")))
  50. (defun make-where-clause (alist)
  51. "Helper function. Will rewrite ALIST into a series of SXQL queries. This is terrible, and needs a rewrite."
  52. (let* ((fuzzy-match (query-param "fuzzy-match" alist))
  53. (op (or (query-param "and-or" alist) "and"))
  54. (params (or
  55. (remove nil
  56. (mapcar
  57. (lambda (pair)
  58. (destructuring-bind (name . value)
  59. pair
  60. (when (string= name "product-name")
  61. (setf name "name"))
  62. (when (and value (> (length value) 0))
  63. (let ((kind (make-kind name alist))
  64. (fuzzy (and (string= name "name")
  65. (string= fuzzy-match "on"))))
  66. (make-op-list kind name value :fuzzy fuzzy)))))
  67. (filter-alist alist)))
  68. (list (sxql:make-op :not-null :name)))))
  69. (sxql:where
  70. (apply #'sxql:make-op (alexandria:make-keyword (string-upcase op))
  71. params))))
  72. ;; TODO This isn't terrible but I don't know how to improve
  73. (defun make-kind (kind alist)
  74. (if
  75. (or (string= kind "atk")
  76. (string= kind "def")
  77. (string= kind "level")
  78. (string= kind "scale"))
  79. (let ((param (query-param (format nil "~a-kind" kind) alist)))
  80. (cond ((string= "eq" param) "=")
  81. ((string= "ge" param) ">=")
  82. ((string= "le" param) "<=")
  83. ((string= "lt" param) "<")
  84. ((string= "gt" param) ">")
  85. (t "=")))
  86. "="))
  87. ;; TODO default arguments
  88. (defun make-search-query (class _parsed)
  89. (let ((direction (or (query-param "direction" _parsed) "desc"))
  90. (limit (or (query-param "limit" _parsed) "10"))
  91. (sort-by (or (query-param "sort-by" _parsed) "id"))
  92. (offset (or (query-param "offset" _parsed) "0")))
  93. (with-connection (db)
  94. (with-transaction
  95. (mito:select-dao class
  96. (sxql:limit limit)
  97. (sxql:offset offset)
  98. (make-order-by direction sort-by)
  99. (make-where-clause _parsed))))))
  100. ;; TODO this is bad and could be re-written using mito:count-dao maybe?
  101. (defun make-count-query (class _parsed)
  102. (let ((place (with-connection (db)
  103. (with-transaction
  104. (mito:retrieve-by-sql
  105. (sxql:select
  106. ((:as (:count :id) :count))
  107. (sxql:from
  108. (alexandria:make-keyword
  109. (string-upcase
  110. (mito.class:table-name (find-class class)))))
  111. (make-where-clause _parsed)))))))
  112. (getf (car place) :count)))
  113. (defun make-order-by (direction sort-by)
  114. "Construct SXQL:ORDER-BY list values"
  115. (let ((dir (if (string= direction "asc")
  116. :asc
  117. :desc))
  118. (sortby (if (member sort-by +param-field-whitelist+ :test #'string=)
  119. (alexandria:make-keyword
  120. (string-upcase sort-by))
  121. :id)))
  122. (sxql:order-by (list dir sortby))))