Introduce rules to query-dsl

Fixes #4217 as each use of page-property have unique bindings that don't
clobber each other
This commit is contained in:
Gabriel Horner
2022-03-01 16:41:10 -05:00
parent ce618443bf
commit 12395c61fb
4 changed files with 111 additions and 81 deletions

View File

@@ -10,6 +10,7 @@
[frontend.db.model :as model]
[frontend.db.query-react :as react]
[frontend.db.utils :as db-utils]
[frontend.db.rules :as rules]
[frontend.template :as template]
[frontend.text :as text]
[frontend.util :as util]
@@ -50,8 +51,10 @@
(when where
(let [q (if blocks? ; FIXME: it doesn't need to be either blocks or pages
`[:find (~'pull ~'?b ~model/block-attrs)
:in ~'$ ~'%
:where]
'[:find (pull ?p [*])
:in $ %
:where])
result (if (coll? (first where))
(apply conj q where)
@@ -156,16 +159,6 @@
;; For integer pages that aren't strings
[(list 'contains? sym (str v))])]))
(defn ->page-property-query
[k v]
[['?p :block/name]
['?p :block/properties '?prop]
[(list 'get '?prop (keyword k)) '?v]
(list
'or
[(list '= '?v v)]
[(list 'contains? '?v v)])])
(defn- build-query-property-two-arg
[e current-filter counter]
(let [k (string/replace (name (nth e 1)) "_" "-")
@@ -183,15 +176,17 @@
[fe clauses current-filter nested-and?]
(cond
(= fe 'not)
(let [clauses (if (coll? (first clauses))
(apply concat clauses)
clauses)
clauses (if (and (= 1 (count clauses))
(= 'and (ffirst clauses)))
;; unflatten
(rest (first clauses))
clauses)]
(cons fe (seq clauses)))
(if (every? list? clauses)
(cons fe (seq clauses))
(let [clauses (if (coll? (first clauses))
(apply concat clauses)
clauses)
clauses (if (and (= 1 (count clauses))
(= 'and (ffirst clauses)))
;; unflatten
(rest (first clauses))
clauses)]
(cons fe (seq clauses))))
(coll? (first clauses))
(cond
@@ -205,10 +200,12 @@
:else
(->> (map (fn [result]
(let [result (if (vector? (ffirst result))
(apply concat result)
result)]
(cons 'and (seq result)))) clauses)
(if (list? result)
result
(let [result (if (vector? (ffirst result))
(apply concat result)
result)]
(cons 'and (seq result))))) clauses)
(apply list fe)))
:else
@@ -218,35 +215,41 @@
(defn- build-query-and-or-not
[repo e {:keys [current-filter vars] :as env} level fe]
(let [clauses (->> (map (fn [form]
(build-query repo form (assoc env :current-filter fe) (inc level)))
(rest e))
(let [raw-clauses (map (fn [form]
(build-query repo form (assoc env :current-filter fe) (inc level)))
(rest e))
clauses (->> raw-clauses
(map :query)
remove-nil?
(distinct))
nested-and? (and (= fe 'and) (= current-filter 'and))]
(when (seq clauses)
(let [result (build-query-and-or-not-result
fe clauses current-filter nested-and?)
vars' (set/union (set @vars) (collect-vars result))]
vars' (set/union (set @vars) (collect-vars result))
query (cond
;; TODO: more thoughts
(and (= current-filter 'and)
(= 'or fe)
(= #{'?b} vars'))
[(concat result [['?b]])]
nested-and?
result
(and (zero? level) (= 'and fe))
(if (list? (first clauses))
result
(distinct (apply concat clauses)))
(and (zero? level) (= 'or fe))
result
:else
[result])]
(reset! vars vars')
(cond
;; TODO: more thoughts
(and (= current-filter 'and)
(= 'or fe)
(= #{'?b} vars'))
[(concat result [['?b]])]
nested-and?
result
(and (zero? level) (= 'and fe))
(distinct (apply concat clauses))
(and (zero? level) (= 'or fe))
result
:else
[result])))))
{:query query
:rules (distinct (mapcat :rules raw-clauses))}))))
(defn- build-query-between-two-arg
[e]
@@ -291,14 +294,13 @@
[e]
(let [[k v] (rest e)
k (string/replace (name k) "_" "-")]
(if-not (nil? v)
(let [v (text/parse-property k v)
v (if (coll? v) (first v) v)]
(->page-property-query k v))
[['?p :block/name]
['?p :block/properties '?prop]
[(list 'get '?prop (keyword k)) '?prop-v]
[true]])))
(if (some? v)
(let [v' (text/parse-property k v)
val (if (coll? v') (first v') v')]
{:query (list 'page-property '?p (keyword k) val)
:rules [:page-property]})
{:query (list 'has-page-property '?p (keyword k))
:rules [:has-page-property]})))
(defn- build-query-page-tags
[e counter]
@@ -333,20 +335,21 @@
page-ref?
(let [page-name (-> (text/page-ref-un-brackets! e)
(util/page-name-sanity-lc))]
[['?b :block/path-refs [:block/name page-name]]])
{:query [['?b :block/path-refs [:block/name page-name]]]})
(string? e) ; block content full-text search, could be slow
(do
(reset! blocks? true)
[['?b :block/content '?content]
[(list 'clojure.string/includes? '?content e)]])
{:query
[['?b :block/content '?content]
[(list 'clojure.string/includes? '?content e)]]})
(contains? #{'and 'or 'not} fe)
(build-query-and-or-not repo e env level fe)
(and (= 'between fe)
(= 3 (count e)))
(build-query-between-two-arg e)
{:query (build-query-between-two-arg e)}
;; (between created_at -1d today)
(and (= 'between fe)
@@ -361,24 +364,24 @@
(when (and start end)
(let [[start end] (sort [start end])
sym '?v]
[['?b :block/properties '?prop]
[(list 'get '?prop k) sym]
[(list '>= sym start)]
[(list '< sym end)]])))))
{:query [['?b :block/properties '?prop]
[(list 'get '?prop k) sym]
[(list '>= sym start)]
[(list '< sym end)]]})))))
(and (= 'property fe)
(= 3 (count e)))
(build-query-property-two-arg e current-filter counter)
{:query (build-query-property-two-arg e current-filter counter)}
(and (= 'property fe)
(= 2 (count e)))
(build-query-property-one-arg e)
{:query (build-query-property-one-arg e)}
(or (= 'todo fe) (= 'task fe))
(build-query-todo e)
{:query (build-query-todo e)}
(= 'priority fe)
(build-query-priority e)
{:query (build-query-priority e)}
(= 'sort-by fe)
(let [[k order] (rest e)
@@ -408,24 +411,24 @@
(= 'page fe)
(let [page-name (text/page-ref-un-brackets! (str (first (rest e))))
page-name (util/page-name-sanity-lc page-name)]
[['?b :block/page [:block/name page-name]]])
{:query [['?b :block/page [:block/name page-name]]]})
(and (= 'namespace fe)
(= 2 (count e)))
(let [page-name (text/page-ref-un-brackets! (str (first (rest e))))
page (util/page-name-sanity-lc page-name)]
(when-not (string/blank? page)
[['?p :block/namespace '?parent]
['?parent :block/name page]]))
{:query [['?p :block/namespace '?parent]
['?parent :block/name page]]}))
(= 'page-property fe)
(build-page-property e)
(= 'page-tags fe)
(build-query-page-tags e counter)
{:query (build-query-page-tags e counter)}
(= 'all-page-tags fe)
[['?e :block/tags '?p]]
{:query [['?e :block/tags '?p]]}
(= 'sample fe)
(when-let [num (second e)]
@@ -505,10 +508,11 @@
(let [sort-by (atom nil)
blocks? (atom nil)
sample (atom nil)
result (when form (build-query repo form {:sort-by sort-by
:blocks? blocks?
:counter counter
:sample sample}))]
{result :query rules :rules}
(when form (build-query repo form {:sort-by sort-by
:blocks? blocks?
:counter counter
:sample sample}))]
(cond
(and (nil? result) (string? form))
form
@@ -528,6 +532,7 @@
result)]
(add-bindings! form result)))]
{:query result
:rules (mapv rules/query-dsl-rules rules)
:sort-by @sort-by
:blocks? (boolean @blocks?)
:sample sample})))))
@@ -541,7 +546,7 @@
(when (string? query-string)
(let [query-string (template/resolve-dynamic-template! query-string)]
(when-not (string/blank? query-string)
(let [{:keys [query sort-by blocks? sample] :as result} (parse repo query-string)
(let [{:keys [query rules sort-by blocks? sample] :as result} (parse repo query-string)
query (if (string? query) (string/trim query) query)
full-text-query? (and (string? result)
(not (string/includes? result " ")))]
@@ -558,6 +563,7 @@
transform-fn (comp sort-by random-samples)]
(react/react-query repo
{:query query
:rules rules
:query-string query-string}
{:use-cache? false
:transform-fn transform-fn}))))))))))