query_react.cljs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. (ns frontend.db.query-react
  2. "Custom queries."
  3. (:require [cljs-time.core :as t]
  4. [clojure.string :as string]
  5. [clojure.walk :as walk]
  6. [frontend.config :as config]
  7. [frontend.db.model :as model]
  8. [frontend.db.react :as react]
  9. [frontend.db.utils :as db-utils :refer [date->int]]
  10. [frontend.debug :as debug]
  11. [frontend.extensions.sci :as sci]
  12. [frontend.state :as state]
  13. [logseq.graph-parser.text :as text]
  14. [frontend.util :as util]
  15. [lambdaisland.glogi :as log]))
  16. (defn resolve-input
  17. [input]
  18. (cond
  19. (= :right-now-ms input) (util/time-ms)
  20. (= :start-of-today-ms input) (util/today-at-local-ms 0 0 0 0)
  21. (= :end-of-today-ms input) (util/today-at-local-ms 24 0 0 0)
  22. (= :today input)
  23. (date->int (t/today))
  24. (= :yesterday input)
  25. (date->int (t/minus (t/today) (t/days 1)))
  26. (= :tomorrow input)
  27. (date->int (t/plus (t/today) (t/days 1)))
  28. (= :current-page input)
  29. ;; This sometimes runs when there isn't a current page e.g. :home route
  30. (some-> (state/get-current-page) string/lower-case)
  31. (and (keyword? input)
  32. (util/safe-re-find #"^\d+d(-before)?$" (name input)))
  33. (let [input (name input)
  34. days (util/parse-int (subs input 0 (dec (count input))))]
  35. (date->int (t/minus (t/today) (t/days days))))
  36. (and (keyword? input)
  37. (util/safe-re-find #"^\d+d(-after)?$" (name input)))
  38. (let [input (name input)
  39. days (util/parse-int (subs input 0 (dec (count input))))]
  40. (date->int (t/plus (t/today) (t/days days))))
  41. (and (string? input) (text/page-ref? input))
  42. (-> (text/page-ref-un-brackets! input)
  43. (string/lower-case))
  44. :else
  45. input))
  46. (defn- remove-nested-children-blocks
  47. [blocks]
  48. (let [ids (set (map :db/id blocks))]
  49. (->> blocks
  50. (remove
  51. (fn [block]
  52. (let [id (:db/id (:block/parent block))]
  53. (contains? ids id)))))))
  54. (defn custom-query-result-transform
  55. [query-result remove-blocks q]
  56. (try
  57. (let [result (db-utils/seq-flatten query-result)
  58. block? (:block/uuid (first result))
  59. result (if block?
  60. (let [result (if (seq remove-blocks)
  61. (let [remove-blocks (set remove-blocks)]
  62. (remove (fn [h]
  63. (contains? remove-blocks (:block/uuid h)))
  64. result))
  65. result)]
  66. (some->> result
  67. remove-nested-children-blocks
  68. (model/sort-by-left-recursive)
  69. (model/with-pages)))
  70. result)]
  71. (if-let [result-transform (:result-transform q)]
  72. (if-let [f (sci/eval-string (pr-str result-transform))]
  73. (try
  74. (sci/call-fn f result)
  75. (catch js/Error e
  76. (log/error :sci/call-error e)
  77. result))
  78. result)
  79. result))
  80. (catch js/Error e
  81. (log/error :query/failed e))))
  82. (defn- resolve-query
  83. [query]
  84. (let [page-ref? #(and (string? %) (text/page-ref? %))]
  85. (walk/postwalk
  86. (fn [f]
  87. (cond
  88. ;; backward compatible
  89. ;; 1. replace :page/ => :block/
  90. (and (keyword? f) (= "page" (namespace f)))
  91. (keyword "block" (name f))
  92. (and (keyword? f) (contains? #{:block/ref-pages :block/ref-blocks} f))
  93. :block/refs
  94. (and (list? f)
  95. (= (first f) '=)
  96. (= 3 (count f))
  97. (some page-ref? (rest f)))
  98. (let [[x y] (rest f)
  99. [page-ref sym] (if (page-ref? x) [x y] [y x])
  100. page-ref (string/lower-case page-ref)]
  101. (list 'contains? sym (text/page-ref-un-brackets! page-ref)))
  102. :else
  103. f)) query)))
  104. (defn react-query
  105. [repo {:keys [query inputs rules] :as query'} query-opts]
  106. (let [pprint (if config/dev? (fn [_] nil) debug/pprint)]
  107. (pprint "================")
  108. (pprint "Use the following to debug your datalog queries:")
  109. (pprint query')
  110. (let [query (resolve-query query)
  111. resolved-inputs (mapv resolve-input inputs)
  112. inputs (cond-> resolved-inputs
  113. rules
  114. (conj rules))
  115. repo (or repo (state/get-current-repo))
  116. k [:custom query']]
  117. (pprint "inputs (post-resolution):" resolved-inputs)
  118. (pprint "query-opts:" query-opts)
  119. (apply react/q repo k query-opts query inputs))))