refactor(db): move some fn into react

This commit is contained in:
defclass
2020-12-17 14:23:52 +08:00
committed by Tienson Qin
parent 31a8498e3c
commit 6ad34f5b3f
8 changed files with 351 additions and 290 deletions

View File

@@ -5,20 +5,159 @@
solution.
"
(:require [frontend.db.conn :as conn]
[frontend.db.utils :as db-utils]
[frontend.db.model :as model]
[frontend.db.base :as base]
[frontend.state :as state]
[frontend.date :as date]
[frontend.util :as util :refer-macros [profile] :refer [react]]
[clojure.string :as string]
[frontend.config :as config]
[frontend.format :as format]
[cljs-time.core :as t]
[cljs-time.coerce :as tc]
[frontend.utf8 :as utf8]
[datascript.core :as d]
[lambdaisland.glogi :as log]))
;; Query atom of map of Key ([repo q inputs]) -> atom
;; TODO: replace with LRUCache, only keep the latest 20 or 50 items?
(defonce query-state (atom {}))
(def ^:dynamic *query-component*)
;; key -> components
(defonce query-components (atom {}))
(defn set-new-result!
[k new-result]
(when-let [result-atom (get-in @query-state [k :result])]
(reset! result-atom new-result)))
;; KV
(defn kv
[key value]
{:db/id -1
:db/ident key
key value})
(defn remove-key!
[repo-url key]
(base/transact! repo-url [[:db.fn/retractEntity [:db/ident key]]])
(set-new-result! [repo-url :kv key] nil))
(defn clear-query-state!
[]
(reset! query-state {}))
(defn clear-query-state-without-refs-and-embeds!
[]
(let [state @query-state
state (->> (filter (fn [[[_repo k] v]]
(contains? #{:blocks :block/block :custom} k)) state)
(into {}))]
(reset! query-state state)))
;; TODO: Add components which subscribed to a specific query
(defn add-q!
[k query inputs result-atom transform-fn query-fn inputs-fn]
(swap! query-state assoc k {:query query
:inputs inputs
:result result-atom
:transform-fn transform-fn
:query-fn query-fn
:inputs-fn inputs-fn})
result-atom)
(defn remove-q!
[k]
(swap! query-state dissoc k))
(defn add-query-component!
[key component]
(swap! query-components update key
(fn [components]
(distinct (conj components component)))))
(defn remove-query-component!
[component]
(reset!
query-components
(->> (for [[k components] @query-components
:let [new-components (remove #(= component %) components)]]
(if (empty? new-components) ; no subscribed components
(do (remove-q! k)
nil)
[k new-components]))
(keep identity)
(into {}))))
(defn get-page-blocks-cache-atom
[repo page-id]
(:result (get @query-state [repo :page/blocks page-id])))
(defn get-block-blocks-cache-atom
[repo block-id]
(:result (get @query-state [repo :block/block block-id])))
;; TODO: rename :custom to :query/custom
(defn remove-custom-query!
[repo query]
(remove-q! [repo :custom query]))
;; Reactive query
(defn query-entity-in-component
([id-or-lookup-ref]
(base/entity (state/get-current-repo) id-or-lookup-ref))
([repo id-or-lookup-ref]
(let [k [:entity id-or-lookup-ref]
result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(when-let [db (conn/get-conn repo)]
(let [result (d/entity db id-or-lookup-ref)
result-atom (or result-atom (atom nil))]
(set! (.-state result-atom) result)
(add-q! k nil nil result-atom identity identity identity))))))
(defn q
[repo k {:keys [use-cache? files-db? transform-fn query-fn inputs-fn]
:or {use-cache? true
files-db? false
transform-fn identity}} query & inputs]
(let [kv? (and (vector? k) (= :kv (first k)))
k (vec (cons repo k))]
(when-let [conn (if files-db?
(when-let [files-conn (conn/get-files-conn repo)]
(deref files-conn))
(conn/get-conn repo))]
(let [result-atom (:result (get @query-state k))]
(when-let [component *query-component*]
(add-query-component! k component))
(if (and use-cache? result-atom)
result-atom
(let [result (cond
query-fn
(query-fn conn)
inputs-fn
(let [inputs (inputs-fn)]
(apply d/q query conn inputs))
kv?
(d/entity conn (last k))
(seq inputs)
(apply d/q query conn inputs)
:else
(d/q query conn))
result (transform-fn result)
result-atom (or result-atom (atom nil))]
;; Don't notify watches now
(set! (.-state result-atom) result)
(add-q! k query inputs result-atom transform-fn query-fn inputs-fn)))))))
;; TODO: Extract several parts to handlers
(defn get-current-page
@@ -39,7 +178,7 @@
(date/journal-name))]
(when page
(let [page-name (util/url-decode (string/lower-case page))]
(model/entity (if tag?
(base/entity (if tag?
[:tag/name page-name]
[:page/name page-name]))))))
@@ -106,7 +245,7 @@
(apply concat
(for [{:block/keys [ref-pages]} blocks]
(map (fn [page]
(when-let [page (model/entity [:page/name (:page/name page)])]
(when-let [page (base/entity [:page/name (:page/name page)])]
[:page/refed-blocks (:db/id page)]))
ref-pages)))
@@ -126,14 +265,14 @@
(filter (fn [v]
(and (= (first v) (state/get-current-repo))
(= (second v) :custom)))
(keys @model/query-state))
(keys @query-state))
(map (fn [v]
(vec (drop 1 v)))))
block-blocks (some->>
(filter (fn [v]
(and (= (first v) (state/get-current-repo))
(= (second v) :block/block)))
(keys @model/query-state))
(keys @query-state))
(map (fn [v]
(vec (drop 1 v)))))]
(->>
@@ -162,7 +301,7 @@
handler-keys (get-handler-keys handler-opts)]
(doseq [handler-key handler-keys]
(let [handler-key (vec (cons repo-url handler-key))]
(when-let [cache (get @model/query-state handler-key)]
(when-let [cache (get @query-state handler-key)]
(let [{:keys [query inputs transform-fn query-fn inputs-fn]} cache]
(when (or query query-fn)
(let [new-result (->
@@ -177,7 +316,7 @@
(apply d/q query db inputs))
(keyword? query)
(model/get-key-value repo-url query)
(base/get-key-value repo-url query)
(seq inputs)
(apply d/q query db inputs)
@@ -185,7 +324,7 @@
:else
(d/q query db))
transform-fn)]
(model/set-new-result! handler-key new-result))))))))))
(set-new-result! handler-key new-result))))))))))
(catch js/Error e
;; FIXME: check error type and notice user
(log/error :db/transact! e)))))
@@ -193,9 +332,9 @@
(defn set-key-value
[repo-url key value]
(if value
(transact-react! repo-url [(model/kv key value)]
(transact-react! repo-url [(kv key value)]
{:key [:kv key]})
(model/remove-key! repo-url key)))
(remove-key! repo-url key)))
(defn set-file-content!
[repo path content]