query_custom.cljs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. (ns frontend.db.query-custom
  2. "Handles executing custom queries a.k.a. advanced queries"
  3. (:require [frontend.state :as state]
  4. [frontend.db.query-react :as query-react]
  5. [frontend.db.query-dsl :as query-dsl]
  6. [frontend.db.model :as model]
  7. [logseq.db.rules :as rules]
  8. [frontend.util.datalog :as datalog-util]
  9. [clojure.walk :as walk]))
  10. ;; FIXME: what if users want to query other attributes than block-attrs?
  11. (defn- replace-star-with-block-attrs!
  12. [l]
  13. (let [block-attrs (butlast model/block-attrs)]
  14. (walk/postwalk
  15. (fn [f]
  16. (if (and (list? f)
  17. (= 'pull (first f))
  18. (= '?b (second f))
  19. (= '[*] (nth f 2)))
  20. `(~'pull ~'?b ~block-attrs)
  21. f))
  22. l)))
  23. (defn- add-rules-to-query
  24. "Searches query's :where for rules and adds them to query if used"
  25. [{:keys [query] :as query-m}]
  26. (let [{:keys [where in]} (datalog-util/query-vec->map query)
  27. rules-found (datalog-util/find-rules-in-where where (-> rules/query-dsl-rules keys set))]
  28. (if (seq rules-found)
  29. (if (and (= '% (last in)) (vector? (last (:inputs query-m))))
  30. ;; Add to existing :inputs rules
  31. (update query-m
  32. :inputs
  33. (fn [inputs]
  34. (assoc (vec inputs)
  35. ;; last position is rules
  36. (dec (count inputs))
  37. (->> (mapv rules/query-dsl-rules rules-found)
  38. (into (last inputs))
  39. ;; user could give rules that we already have
  40. distinct
  41. vec))))
  42. ;; Add new rules
  43. (-> query-m
  44. (update :query
  45. (fn [q]
  46. (if (contains? (set q) :in)
  47. ;; only add '% if not already present
  48. (if (not (contains? (set q) '%))
  49. (datalog-util/add-to-end-of-query-section q :in ['%])
  50. q)
  51. (into q [:in '$ '%]))))
  52. (update :rules
  53. (fn [rules]
  54. (into (or rules [])
  55. (mapv rules/query-dsl-rules rules-found))))))
  56. query-m)))
  57. (defn custom-query
  58. "Executes a datalog query through query-react, given either a regular datalog
  59. query or a simple query"
  60. ([query]
  61. (custom-query query {}))
  62. ([query query-opts]
  63. (custom-query (state/get-current-repo) query query-opts))
  64. ([repo query query-opts]
  65. (let [query' (replace-star-with-block-attrs! query)
  66. query-opts (if (:query-string query-opts) query-opts
  67. (assoc query-opts :query-string (str query)))]
  68. (if (or (list? (:query query'))
  69. (not= :find (first (:query query')))) ; dsl query
  70. (query-dsl/custom-query repo query' query-opts)
  71. (query-react/react-query repo (add-rules-to-query query') query-opts)))))