|
- #|
-
- src/web/search.lisp
-
- This is some ancient old dusty code that had preminitions of how
- things would work in the future.
-
- The idea was that there'd be a list of default parameters, maybe
- you've seen it in the code, *SEARCH-DEFAULTS*. And this machinery
- would query that default, then build an SQL query to hit the
- database based on what was read from Caveman2.
-
- This code needs a rewrite.
-
- |#
-
- (in-package #:cl-deck-builder2.web)
-
- ;; TODO defstruct search-params?
- (defparameter *search-defaults*
- '(("direction" . "asc")
- ("limit" . "10")
- ("name" . "")
- ("variant" . (1 . "on"))
- ("offset" . "0")
- ("sort-by" . "id")))
-
- (defun make-op-list (kind name value &key (fuzzy nil))
- (if fuzzy
- (setf kind "LIKE"
- value (format nil "%~a%" value)))
- (list
- (alexandria:make-keyword kind)
- (alexandria:make-keyword (string-upcase
- (substitute #\_ #\- name)))
- value))
-
- (defparameter +param-field-whitelist+
- '("amazon-asin" "barcode" "brand" "buy-price" "category" "code" "created-by"
- "deck-id" "desc" "description" "domestic-only" "edition" "email" "id" "kind"
- "linkmarkers" "linkval" "manufacturer-sku" "max-qty" "msrp" "parent" "price"
- "product-name" "rarity" "rarity-code" "sell-price" "tax-exempt" "total-qty"
- "url" "weight" "wishlists" "atk" "def" "level" "scale" "passcode" "type"
- "frame-type" "race" "attribute" "archetype" "name" "opt-qty" "qty" "condition")
- "A whitelist of keywords allowed by user input on the database side.")
-
- (defun filter-alist (alist &optional (whitelist +param-field-whitelist+))
- "Filter ALIST by CAR matching MEMBER in WHITELIST."
- (remove-if (lambda (pair)
- (destructuring-bind (key . value)
- pair
- (if (and (member key whitelist :test #'equal)
- value
- (> (length value) 0))
- nil
- t)))
- alist))
-
- ;; (defparameter *variant-id*
- ;; (mito:object-id (find-dao 'variant :name "Near Mint")))
-
- (defun make-where-clause (alist)
- "Helper function. Will rewrite ALIST into a series of SXQL queries. This is terrible, and needs a rewrite."
- (let* ((fuzzy-match (query-param "fuzzy-match" alist))
- (op (or (query-param "and-or" alist) "and"))
- (params (or
- (remove nil
- (mapcar
- (lambda (pair)
- (destructuring-bind (name . value)
- pair
- (when (string= name "product-name")
- (setf name "name"))
- (when (and value (> (length value) 0))
- (let ((kind (make-kind name alist))
- (fuzzy (and (string= name "name")
- (string= fuzzy-match "on"))))
- (make-op-list kind name value :fuzzy fuzzy)))))
- (filter-alist alist)))
- (list (sxql:make-op :not-null :name)))))
- (sxql:where
- (apply #'sxql:make-op (alexandria:make-keyword (string-upcase op))
- params))))
-
- ;; TODO This isn't terrible but I don't know how to improve
- (defun make-kind (kind alist)
- (if
- (or (string= kind "atk")
- (string= kind "def")
- (string= kind "level")
- (string= kind "scale"))
- (let ((param (query-param (format nil "~a-kind" kind) alist)))
- (cond ((string= "eq" param) "=")
- ((string= "ge" param) ">=")
- ((string= "le" param) "<=")
- ((string= "lt" param) "<")
- ((string= "gt" param) ">")
- (t "=")))
- "="))
-
- ;; TODO default arguments
- (defun make-search-query (class _parsed)
- (let ((direction (or (query-param "direction" _parsed) "desc"))
- (limit (or (query-param "limit" _parsed) "10"))
- (sort-by (or (query-param "sort-by" _parsed) "id"))
- (offset (or (query-param "offset" _parsed) "0")))
- (with-connection (db)
- (with-transaction
- (mito:select-dao class
- (sxql:limit limit)
- (sxql:offset offset)
- (make-order-by direction sort-by)
- (make-where-clause _parsed))))))
-
- ;; TODO this is bad and could be re-written using mito:count-dao maybe?
- (defun make-count-query (class _parsed)
- (let ((place (with-connection (db)
- (with-transaction
- (mito:retrieve-by-sql
- (sxql:select
- ((:as (:count :id) :count))
- (sxql:from
- (alexandria:make-keyword
- (string-upcase
- (mito.class:table-name (find-class class)))))
- (make-where-clause _parsed)))))))
- (getf (car place) :count)))
-
- (defun make-order-by (direction sort-by)
- "Construct SXQL:ORDER-BY list values"
- (let ((dir (if (string= direction "asc")
- :asc
- :desc))
- (sortby (if (member sort-by +param-field-whitelist+ :test #'string=)
- (alexandria:make-keyword
- (string-upcase sort-by))
- :id)))
- (sxql:order-by (list dir sortby))))
|