summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2024-10-10 15:03:06 +0600
committerunwox <me@unwox.com>2024-10-10 15:03:06 +0600
commit240aeb84855a153764830186d5f4e7f22873561c (patch)
tree0cda41c18d327edb9691249ac8d6e5a44fa9c91e /bin
parent9d1b193640c039f7300b44dd30def266cbc31a85 (diff)
implement filtering by tags
Diffstat (limited to 'bin')
-rw-r--r--bin/serve.fnl200
1 files changed, 129 insertions, 71 deletions
diff --git a/bin/serve.fnl b/bin/serve.fnl
index d4dbf4c..63e4a3b 100644
--- a/bin/serve.fnl
+++ b/bin/serve.fnl
@@ -1,4 +1,4 @@
-(import-macros {: map : reduce} :lib.macro)
+(import-macros {: map : reduce : filter} :lib.macro)
(tset package :path (.. package.path ";./vendor/lpeglj/?.lua"))
@@ -34,6 +34,91 @@
(string.gsub "&quot;" "\"")
(string.gsub "&amp;" "&"))))
+(fn random-products [limit]
+ (assert (< 0 limit) "limit must be > 0")
+ (luna.db.query*
+ db
+ "SELECT site,
+ title,
+ description,
+ image,
+ url,
+ price,
+ weight,
+ price_per AS \"price-per\",
+ year
+ FROM products
+ ORDER BY RANDOM()
+ LIMIT ?"
+ [limit]))
+
+(fn all-tags []
+ (map
+ (fn [_ v] (. v 1))
+ (luna.db.query
+ db
+ "SELECT title FROM tags ORDER BY creation_time"
+ [])))
+
+(fn query-products [page query tags]
+ (local tags (or tags []))
+
+ (var where-conds [])
+ (var where-vars [])
+ (when (< 0 (# tags))
+ (each [_ tag (pairs tags)]
+ (table.insert where-conds "product_tags.tag = ?")
+ (table.insert where-vars tag)))
+ (when (and query (< 0 (# query)))
+ (table.insert where-conds "search.title MATCH ?")
+ (table.insert where-vars
+ (array.join
+ (map (fn [_ q]
+ (if (. query-synonyms q)
+ (.. "(" q "* OR " (. query-synonyms q) "*)")
+ (.. q "*")))
+ (str.split query))
+ " ")))
+ (local where-sql (array.join where-conds "\nAND "))
+
+ (local total
+ (luna.db.query
+ db
+ (string.format
+ "SELECT count(*)
+ FROM search
+ LEFT JOIN product_tags ON product_tags.product = search.fid
+ WHERE search.`table` = 'products'
+ AND %s" where-sql)
+ where-vars))
+
+ {:results
+ (luna.db.query*
+ db
+ (string.format
+ "SELECT highlight(search, 0, '<i>', '</i>') AS \"title\",
+ products.site,
+ products.description,
+ products.image,
+ products.url,
+ products.price,
+ products.weight,
+ products.price_per AS \"price-per\",
+ products.year,
+ products.archived,
+ products.creation_time AS \"creation-time\"
+ FROM search
+ INNER JOIN products ON search.fid = products.url
+ LEFT JOIN product_tags ON product_tags.product = products.url
+ WHERE search.`table` = 'products'
+ AND %s
+ ORDER BY rank
+ LIMIT 48 OFFSET ?" where-sql)
+ (array.concat where-vars [(* (- page 1) 48)]))
+ :total (if (< 0 (# total))
+ (. total 1 1)
+ 0)})
+
(fn site-name-template [name]
(if
(= name "ipuer")
@@ -83,24 +168,33 @@
;; FIXME: security issue
[:small {} [:NO-ESCAPE (unescape (str.truncate product.description 200))]]])
-(fn paginator-template [query page limit total]
+(fn paginator-template [query tags page limit total]
(local last-page (math.ceil (/ total limit)))
+ (fn make-url [page query tags]
+ (.. "?page=" (tostring page)
+ "&query=" query
+ "&"
+ (array.join
+ (array.flatten
+ (map (fn [_ tag] (.. "tags=" tag))
+ tags))
+ "&")))
(if (< limit total)
[:div {:class "paginator"}
[:div {:class "paginator-numbers"}
(if (< 1 page)
- [:a {:href (.. "?page=" (- page 1) "&query=" query)} "<"]
+ [:a {:href (make-url (- page 1) query tags)} "←"]
"")
(faccumulate [res [:span {}] i 1 last-page]
(do
(table.insert
- res [:a {:href (.. "?page=" i "&query=" query)
+ res [:a {:href (make-url i query tags)
:class (if (= page i) "paginator-active" "")}
(tostring i)])
res))
(if (< page last-page)
- [:a {:href (.. "?page=" (+ page 1) "&query=" query)} ">"]
+ [:a {:href (make-url (+ page 1) query tags)} "→"]
"")]
[:div {} "Всего результатов: " [:strong {} (string.format "%d" total)]]]
""))
@@ -108,7 +202,7 @@
(fn aside-template [query tags paginator]
[:aside {:class "aside"}
[:div {:class "aside-content"}
- (if (~= query "")
+ (if (or (~= query "") (< 0 (# tags)))
[:a {:href "/" :style "display: block;"}
[:img {:class "logo" :src "static/logo.svg"
:alt "Логотип meicha.ru" :title "Логотип meicha.ru"}]]
@@ -117,11 +211,21 @@
[:form {:class "form"}
[:input {:type :search :name :query :value query
:autofocus true :placeholder "Поисковый запрос"}]
+ [:div {:class "form-tags"}
+ [:select {:class "form-tag" :name "tags"}
+ [:option {:value ""} "~ Категория ~"]
+ (table.unpack
+ (map
+ (fn [_ tag]
+ [:option {:value tag
+ :selected (if (array.contains tags tag) "selected" nil)}
+ tag])
+ (all-tags)))]]
[:button {:type :submit} "Искать"]]
paginator]])
(fn base-template [query tags page total ...]
- (local paginator (paginator-template query page 48 total))
+ (local paginator (paginator-template query tags page 48 total))
[:html {:lang "en"}
[:head {}
[:meta {:charset "UTF-8"}]
@@ -135,76 +239,30 @@
[:div {:class "list"} ...]
[:footer {} paginator]]]]]])
-(fn random-products [limit]
- (assert (< 0 limit) "limit must be > 0")
- (luna.db.query*
- db
- "SELECT site,
- title,
- description,
- image,
- url,
- price,
- weight,
- price_per AS \"price-per\",
- year
- FROM products
- ORDER BY RANDOM()
- LIMIT ?"
- [limit]))
-
-(fn query-products [page query sorters]
- (local query
- (table.concat
- (map (fn [_ q]
- (if (. query-synonyms q)
- (.. "(" q "* OR " (. query-synonyms q) "*)")
- (.. q "*")))
- (str.split query))
- " "))
- (local total
- (luna.db.query
- db
- "SELECT count(*)
- FROM search
- WHERE search.`table` = 'products'
- AND search.title MATCH ?"
- [query]))
+(fn get-query-string [query key]
+ (if (and query
+ (. query key)
+ (. query key 1)
+ (< 0 (# (. query key 1))))
+ (. query key 1)
+ nil))
- {:results
- (luna.db.query*
- db
- "SELECT highlight(search, 0, '<i>', '</i>') AS \"title\",
- products.site,
- products.description,
- products.image,
- products.url,
- products.price,
- products.weight,
- products.price_per AS \"price-per\",
- products.year,
- products.archived,
- products.creation_time AS \"creation-time\"
- FROM search
- INNER JOIN products ON search.fid = products.url
- WHERE search.`table` = 'products'
- AND search.title MATCH ?
- ORDER BY rank
- LIMIT 48 OFFSET ?"
- [query (* (- page 1) 48)])
- :total (if (< 0 (# total))
- (. total 1 1)
- 0)})
+(fn get-query-number [query key]
+ (if (and query
+ (. query key)
+ (. query key 1))
+ (tonumber (. query key 1))
+ nil))
(fn root-handler [{: path : query}]
(if (= path "/")
(let [headers {:content-type "text/html"}
- page (or (tonumber query.page) 1)
- search (str.trim (or query.query ""))
- tags (or query.tags [])
+ page (or (get-query-number query "page") 1)
+ search (str.trim (or (get-query-string query "query") ""))
+ tags (filter #(~= "" $2) (or query.tags []))
{: results : total}
- (if (~= "" search)
- (query-products page search)
+ (if (or (~= "" search) (< 0 (# tags)))
+ (query-products page search tags)
{:total 48 :results (random-products 48)})]
(values
200 headers