async.cljs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. (ns frontend.db.async
  2. "Async queries"
  3. (:require [promesa.core :as p]
  4. [frontend.state :as state]
  5. [frontend.config :as config]
  6. [frontend.db.utils :as db-utils]
  7. [frontend.db.async.util :as db-async-util]
  8. [frontend.db.file-based.async :as file-async]
  9. [frontend.db :as db]
  10. [frontend.db.model :as db-model]
  11. [frontend.persist-db.browser :as db-browser]
  12. [datascript.core :as d]
  13. [frontend.db.react :as react]
  14. [frontend.date :as date]
  15. [cljs-time.core :as t]
  16. [cljs-time.format :as tf]
  17. [logseq.db :as ldb]
  18. [frontend.util :as util]
  19. [frontend.handler.file-based.property.util :as property-util]
  20. [logseq.db.frontend.property :as db-property]))
  21. (def <q db-async-util/<q)
  22. (def <pull db-async-util/<pull)
  23. (comment
  24. (def <pull-many db-async-util/<pull-many))
  25. (defn <get-files
  26. [graph]
  27. (p/let [result (<q graph
  28. {:transact-db? false}
  29. '[:find [(pull ?file [:file/path :file/last-modified-at]) ...]
  30. :where
  31. [?file :file/path ?path]])]
  32. (->> result seq reverse (map #(vector (:file/path %) (or (:file/last-modified-at %) 0))))))
  33. (defn <get-all-templates
  34. [graph]
  35. (p/let [result (<q graph
  36. {:transact-db? true}
  37. '[:find ?t (pull ?b [*])
  38. :where
  39. [?b :block/properties ?p]
  40. [(get ?p :template) ?t]])]
  41. (into {} result)))
  42. (defn <get-template-by-name
  43. [name]
  44. (let [repo (state/get-current-repo)]
  45. (p/let [templates (<get-all-templates repo)]
  46. (get templates name))))
  47. (defn <db-based-get-all-properties
  48. "Return seq of all property names except for private built-in properties."
  49. [graph & {:keys [remove-built-in-property?]
  50. :or {remove-built-in-property? true}}]
  51. (p/let [result (<q graph
  52. {:transact-db? false}
  53. '[:find [(pull ?e [:block/uuid :db/ident :block/title :block/schema]) ...]
  54. :where
  55. [?e :block/type "property"]
  56. [?e :block/title]])]
  57. (cond->> result
  58. remove-built-in-property?
  59. ;; remove private built-in properties
  60. (remove #(and (:db/ident %)
  61. (db-property/logseq-property? (:db/ident %))
  62. (not (ldb/public-built-in-property? %))
  63. (not= (:db/ident %) :logseq.property/icon))))))
  64. (defn <get-all-properties
  65. "Returns all public properties as property maps including their
  66. :block/title and :db/ident. For file graphs the map only contains
  67. :block/title"
  68. [& {:keys [remove-built-in-property?]}]
  69. (when-let [graph (state/get-current-repo)]
  70. (if (config/db-based-graph? graph)
  71. (<db-based-get-all-properties graph {:remove-built-in-property? remove-built-in-property?})
  72. (p/let [properties (file-async/<file-based-get-all-properties graph)
  73. hidden-properties (set (map name (property-util/hidden-properties)))]
  74. (remove #(hidden-properties (:block/title %)) properties)))))
  75. (defn <file-get-property-values
  76. "For file graphs, returns property value names for given property name"
  77. [graph property]
  78. (when-not (config/db-based-graph? graph)
  79. (file-async/<get-file-based-property-values graph property)))
  80. (defn <get-block-property-values
  81. "For db graphs, returns property value ids for given property db-ident.
  82. Separate from file version because values are lazy loaded"
  83. [graph property-id]
  84. (let [empty-id (:db/id (db/entity :logseq.property/empty-placeholder))]
  85. (<q graph {:transact-db? false}
  86. '[:find [?v ...]
  87. :in $ ?property-id ?empty-id
  88. :where
  89. [?b ?property-id ?v]
  90. [(not= ?v ?empty-id)]]
  91. property-id
  92. empty-id)))
  93. (comment
  94. (defn <get-block-property-value-entity
  95. [graph property-id value]
  96. (p/let [result (<q graph {}
  97. '[:find [(pull ?vid [*]) ...]
  98. :in $ ?property-id ?value
  99. :where
  100. [?b ?property-id ?vid]
  101. [(not= ?vid :logseq.property/empty-placeholder)]
  102. (or
  103. [?vid :property.value/content ?value]
  104. [?vid :block/title ?value])]
  105. property-id
  106. value)]
  107. (db/entity (:db/id (first result))))))
  108. ;; TODO: batch queries for better performance and UX
  109. (defn <get-block
  110. [graph name-or-uuid & {:keys [children? nested-children?]
  111. :or {children? true
  112. nested-children? false}}]
  113. (let [name' (str name-or-uuid)
  114. *async-queries (:db/async-queries @state/state)
  115. async-requested? (get @*async-queries name')
  116. e (cond
  117. (number? name-or-uuid)
  118. (db/entity name-or-uuid)
  119. (util/uuid-string? name')
  120. (db/entity [:block/uuid (uuid name')])
  121. :else
  122. (db/get-page name'))
  123. id (or (and (:block/uuid e) (str (:block/uuid e)))
  124. (and (util/uuid-string? name') name')
  125. name-or-uuid)]
  126. (if (or (:block.temp/fully-loaded? e) async-requested?)
  127. e
  128. (when-let [^Object sqlite @db-browser/*worker]
  129. (swap! *async-queries assoc name' true)
  130. (state/update-state! :db/async-query-loading (fn [s] (conj s name')))
  131. (p/let [result (.get-block-and-children sqlite graph id (ldb/write-transit-str
  132. {:children? children?
  133. :nested-children? nested-children?}))
  134. {:keys [properties block children] :as result'} (ldb/read-transit-str result)
  135. conn (db/get-db graph false)
  136. block-and-children (concat properties [block] children)
  137. _ (d/transact! conn block-and-children)
  138. affected-keys (->> (keep :db/id block-and-children)
  139. (map #(vector :frontend.worker.react/block %)))]
  140. (react/refresh-affected-queries! graph affected-keys)
  141. (state/update-state! :db/async-query-loading (fn [s] (disj s name')))
  142. (if children?
  143. block
  144. result'))))))
  145. (defn <get-block-parents
  146. [graph id depth]
  147. (assert (integer? id))
  148. (when-let [^Object worker @db-browser/*worker]
  149. (when-let [block-id (:block/uuid (db/entity graph id))]
  150. (state/update-state! :db/async-query-loading (fn [s] (conj s (str block-id "-parents"))))
  151. (p/let [result-str (.get-block-parents worker graph id depth)
  152. result (ldb/read-transit-str result-str)
  153. conn (db/get-db graph false)
  154. _ (d/transact! conn result)]
  155. (state/update-state! :db/async-query-loading (fn [s] (disj s (str block-id "-parents"))))
  156. result))))
  157. (defn <get-page-all-blocks
  158. [page-name]
  159. (when-let [page (some-> page-name (db-model/get-page))]
  160. (when-let [^Object worker @db-browser/*worker]
  161. (p/let [result (.get-block-and-children worker
  162. (state/get-current-repo)
  163. (str (:block/uuid page))
  164. (ldb/write-transit-str
  165. {:children? true
  166. :nested-children? false}))]
  167. (some-> result (ldb/read-transit-str) (:children))))))
  168. (defn <get-block-refs
  169. [graph eid]
  170. (assert (integer? eid))
  171. (when-let [^Object worker @db-browser/*worker]
  172. (state/update-state! :db/async-query-loading (fn [s] (conj s (str eid "-refs"))))
  173. (p/let [result-str (.get-block-refs worker graph eid)
  174. result (ldb/read-transit-str result-str)
  175. conn (db/get-db graph false)
  176. _ (d/transact! conn result)]
  177. (state/update-state! :db/async-query-loading (fn [s] (disj s (str eid "-refs"))))
  178. result)))
  179. (defn <get-block-refs-count
  180. [graph eid]
  181. (assert (integer? eid))
  182. (when-let [^Object worker @db-browser/*worker]
  183. (.get-block-refs-count worker graph eid)))
  184. (defn <get-all-referenced-blocks-uuid
  185. "Get all uuids of blocks with any back link exists."
  186. [graph]
  187. (<q graph {:transact-db? false}
  188. '[:find [?refed-uuid ...]
  189. :where
  190. ;; ?referee-b is block with ref towards ?refed-b
  191. [?refed-b :block/uuid ?refed-uuid]
  192. [?referee-b :block/refs ?refed-b]]))
  193. (defn <get-file
  194. [graph path]
  195. (when (and graph path)
  196. (p/let [result (<pull graph [:file/path path])]
  197. (:file/content result))))
  198. (defn <get-date-scheduled-or-deadlines
  199. [journal-title]
  200. (when-let [date (date/journal-title->int journal-title)]
  201. (let [future-days (state/get-scheduled-future-days)
  202. date-format (tf/formatter "yyyyMMdd")
  203. current-day (tf/parse date-format (str date))
  204. future-day (some->> (t/plus current-day (t/days future-days))
  205. (tf/unparse date-format)
  206. (parse-long))]
  207. (when future-day
  208. (when-let [repo (state/get-current-repo)]
  209. (p/let [result (<q repo {}
  210. '[:find [(pull ?block ?block-attrs) ...]
  211. :in $ ?day ?future ?block-attrs
  212. :where
  213. (or
  214. [?block :block/scheduled ?d]
  215. [?block :block/deadline ?d])
  216. [(get-else $ ?block :block/repeated? false) ?repeated]
  217. [(get-else $ ?block :block/marker "NIL") ?marker]
  218. [(not= ?marker "DONE")]
  219. [(not= ?marker "CANCELED")]
  220. [(not= ?marker "CANCELLED")]
  221. [(<= ?d ?future)]
  222. (or-join [?repeated ?d ?day]
  223. [(true? ?repeated)]
  224. [(>= ?d ?day)])]
  225. date
  226. future-day
  227. db-model/file-graph-block-attrs)]
  228. (->> result
  229. db-model/sort-by-order-recursive
  230. db-utils/group-by-page)))))))
  231. (defn <get-tag-pages
  232. [graph tag-id]
  233. (<q graph {:transact-db? true}
  234. '[:find [(pull ?page [:db/id :block/uuid :block/name :block/title :block/created-at :block/updated-at])]
  235. :in $ ?tag-id
  236. :where
  237. [?page :block/tags ?tag-id]
  238. [?page :block/name]]
  239. tag-id))
  240. (defn <get-property-objects
  241. [graph property-ident]
  242. (<q graph {:transact-db? true}
  243. '[:find [(pull ?b [*]) ...]
  244. :in $ ?property-ident
  245. :where
  246. [?b ?property-ident]]
  247. property-ident))
  248. (defn <get-tag-objects
  249. [graph class-id]
  250. (let [class-children (db-model/get-structured-children graph class-id)
  251. class-ids (distinct (conj class-children class-id))]
  252. (<q graph {:transact-db? true}
  253. '[:find [(pull ?b [*]) ...]
  254. :in $ [?class-id ...]
  255. :where
  256. [?b :block/tags ?class-id]]
  257. class-ids)))
  258. (defn <get-views
  259. [graph class-id]
  260. (<q graph {:transact-db? true}
  261. '[:find [(pull ?b [*]) ...]
  262. :in $ ?class-id
  263. :where
  264. [?b :logseq.property/view-for ?class-id]]
  265. class-id))
  266. (defn <get-tags
  267. [graph]
  268. (<q graph {:transact-db? false}
  269. '[:find [(pull ?tag [:db/id :block/title]) ...]
  270. :where
  271. [?tag :block/type "class"]]))
  272. (defn <get-asset-with-checksum
  273. [graph checksum]
  274. (p/let [result (<q graph {:transact-db? true}
  275. '[:find [(pull ?b [*]) ...]
  276. :in $ ?checksum
  277. :where
  278. [?b :logseq.property.asset/checksum ?checksum]]
  279. checksum)]
  280. (some-> (first result)
  281. :db/id
  282. db/entity)))
  283. (defn <get-pdf-annotations
  284. [graph pdf-id]
  285. (p/let [result (<q graph {:transact-db? true}
  286. '[:find [(pull ?b [*]) ...]
  287. :in $ ?pdf-id
  288. :where
  289. [?b :logseq.property/asset ?pdf-id]]
  290. pdf-id)]
  291. result))
  292. (comment
  293. (defn <fetch-all-pages
  294. [graph]
  295. (when-let [^Object worker @db-browser/*worker]
  296. (let [db (db/get-db graph)
  297. exclude-ids (->> (d/datoms db :avet :block/name)
  298. (map :db/id)
  299. (ldb/write-transit-str))]
  300. (.fetch-all-pages worker graph exclude-ids)))))