query_react.cljs 4.8 KB

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