mirror of
https://github.com/logseq/logseq.git
synced 2026-04-30 17:06:23 +00:00
feat: simple query builder (#8774)
Simple query builder --------- Co-authored-by: Gabriel Horner <gabriel@logseq.com> Co-authored-by: charlie <xyhp915@qq.com>
This commit is contained in:
@@ -14,15 +14,19 @@
|
||||
[frontend.template :as template]
|
||||
[logseq.graph-parser.text :as text]
|
||||
[logseq.graph-parser.util.page-ref :as page-ref]
|
||||
[logseq.graph-parser.util :as gp-util]
|
||||
[frontend.util.text :as text-util]
|
||||
[frontend.util :as util]))
|
||||
|
||||
|
||||
;; Query fields:
|
||||
|
||||
;; Operators:
|
||||
;; and
|
||||
;; or
|
||||
;; not
|
||||
|
||||
;; Filters:
|
||||
;; between
|
||||
;; Example: (between -7d +7d)
|
||||
;; (between created-at -1d today)
|
||||
@@ -32,16 +36,17 @@
|
||||
;; task (block)
|
||||
;; priority (block)
|
||||
;; page
|
||||
;; sample
|
||||
;; full-text-search ""
|
||||
|
||||
;; namespace
|
||||
;; page-property (page)
|
||||
;; page-tags (page)
|
||||
;; all-page-tags
|
||||
;; project (block, TBD)
|
||||
|
||||
;; Sort by (field, asc/desc):
|
||||
;; (sort-by created-at asc)
|
||||
|
||||
;; (between -7d +7d)
|
||||
|
||||
;; Time helpers
|
||||
;; ============
|
||||
(defn- ->journal-day-int [input]
|
||||
@@ -443,23 +448,32 @@ Some bindings in this fn:
|
||||
;; parse fns
|
||||
;; =========
|
||||
|
||||
(defn- pre-transform
|
||||
(defonce tag-placeholder "~~~tag-placeholder~~~")
|
||||
(defn pre-transform
|
||||
[s]
|
||||
(let [quoted-page-ref (str "\"" page-ref/left-brackets "$1" page-ref/right-brackets "\"")]
|
||||
(some-> s
|
||||
(string/replace page-ref/page-ref-re quoted-page-ref)
|
||||
(string/replace text-util/between-re
|
||||
(fn [[_ x]]
|
||||
(->> (string/split x #" ")
|
||||
(remove string/blank?)
|
||||
(map (fn [x]
|
||||
(if (or (contains? #{"+" "-"} (first x))
|
||||
(and (util/safe-re-find #"\d" (first x))
|
||||
(some #(string/ends-with? x %) ["y" "m" "d" "h" "min"])))
|
||||
(keyword (name x))
|
||||
x)))
|
||||
(string/join " ")
|
||||
(util/format "(between %s)")))))))
|
||||
(if (gp-util/wrapped-by-quotes? s)
|
||||
s
|
||||
(let [quoted-page-ref (fn [matches]
|
||||
(let [match' (string/replace (second matches) "#" tag-placeholder)]
|
||||
(str "\"" page-ref/left-brackets match' page-ref/right-brackets "\"")))]
|
||||
(some-> s
|
||||
(string/replace page-ref/page-ref-re quoted-page-ref)
|
||||
(string/replace text-util/between-re
|
||||
(fn [[_ x]]
|
||||
(->> (string/split x #" ")
|
||||
(remove string/blank?)
|
||||
(map (fn [x]
|
||||
(if (or (contains? #{"+" "-"} (first x))
|
||||
(and (util/safe-re-find #"\d" (first x))
|
||||
(some #(string/ends-with? x %) ["y" "m" "d" "h" "min"])))
|
||||
(keyword (name x))
|
||||
x)))
|
||||
(string/join " ")
|
||||
(util/format "(between %s)"))))
|
||||
(string/replace #"\"[^\"]+\"" (fn [s] (string/replace s "#" tag-placeholder)))
|
||||
(string/replace " #" " #tag ")
|
||||
(string/replace #"^#" "#tag ")
|
||||
(string/replace tag-placeholder "#")))))
|
||||
|
||||
(defn- add-bindings!
|
||||
[form q]
|
||||
@@ -499,17 +513,33 @@ Some bindings in this fn:
|
||||
:else
|
||||
q)))
|
||||
|
||||
(defn simplify-query
|
||||
[query]
|
||||
(if (string? query)
|
||||
query
|
||||
(walk/postwalk
|
||||
(fn [f]
|
||||
(if (and
|
||||
(coll? f)
|
||||
(contains? #{'and 'or} (first f))
|
||||
(= 2 (count f)))
|
||||
(second f)
|
||||
f))
|
||||
query)))
|
||||
|
||||
(def custom-readers {:readers {'tag (fn [x] (page-ref/->page-ref x))}})
|
||||
(defn parse
|
||||
[s]
|
||||
(when (and (string? s)
|
||||
(not (string/blank? s)))
|
||||
(let [s (if (= \# (first s)) (page-ref/->page-ref (subs s 1)) s)
|
||||
form (some-> s
|
||||
(pre-transform)
|
||||
(reader/read-string))
|
||||
form (some->> s
|
||||
(pre-transform)
|
||||
(reader/read-string custom-readers))
|
||||
sort-by (atom nil)
|
||||
blocks? (atom nil)
|
||||
sample (atom nil)
|
||||
form (simplify-query form)
|
||||
{result :query rules :rules}
|
||||
(when form (build-query form {:sort-by sort-by
|
||||
:blocks? blocks?
|
||||
@@ -545,12 +575,21 @@ Some bindings in this fn:
|
||||
(apply conj q where)
|
||||
(conj q where))))
|
||||
|
||||
(defn parse-query
|
||||
[q]
|
||||
(let [q' (template/resolve-dynamic-template! q)]
|
||||
(parse q')))
|
||||
|
||||
(defn pre-transform-query
|
||||
[q]
|
||||
(let [q' (template/resolve-dynamic-template! q)]
|
||||
(pre-transform q')))
|
||||
|
||||
(defn query
|
||||
"Runs a dsl query with query as a string. Primary use is from '{{query }}'"
|
||||
[repo query-string]
|
||||
(when (and (string? query-string) (not= "\"\"" query-string))
|
||||
(let [query-string' (template/resolve-dynamic-template! query-string)
|
||||
{:keys [query rules sort-by blocks? sample]} (parse query-string')]
|
||||
(let [{:keys [query rules sort-by blocks? sample]} (parse-query query-string)]
|
||||
(when-let [query' (some-> query (query-wrapper {:blocks? blocks?}))]
|
||||
(let [sort-by (or sort-by identity)
|
||||
random-samples (if @sample
|
||||
|
||||
Reference in New Issue
Block a user