mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
debug: db validate
This commit is contained in:
@@ -511,24 +511,6 @@ independent of format as format specific heading characters are stripped"
|
||||
(not= parent-id (:db/id node)))
|
||||
node)) lefts))))
|
||||
|
||||
(defn- get-next-outdented-block
|
||||
"Get the next outdented block of the block that has the `id`.
|
||||
e.g.
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- d
|
||||
|
||||
The next outdented block of `c` is `d`."
|
||||
[db id]
|
||||
(when-let [block (db-utils/entity db id)]
|
||||
(let [parent (:block/parent block)]
|
||||
(if-let [parent-sibling (get-by-parent-&-left db
|
||||
(:db/id (:block/parent parent))
|
||||
(:db/id parent))]
|
||||
parent-sibling
|
||||
(get-next-outdented-block db (:db/id parent))))))
|
||||
|
||||
(defn top-block?
|
||||
[block]
|
||||
(= (:db/id (:block/parent block))
|
||||
|
||||
50
src/main/frontend/db/validate.cljs
Normal file
50
src/main/frontend/db/validate.cljs
Normal file
@@ -0,0 +1,50 @@
|
||||
(ns frontend.db.validate
|
||||
"DB validation.
|
||||
For pages:
|
||||
1. Each block should has a unique [:block/parent :block/left] position.
|
||||
2. For any block, its children should be connected by :block/left."
|
||||
(:require [datascript.core :as d]
|
||||
[medley.core :as medley]))
|
||||
|
||||
(defn- broken-chain?
|
||||
[page parent-left->eid]
|
||||
(let [parents (->> (:block/_page page)
|
||||
(filter #(seq (:block/_parent %)))
|
||||
(cons page))]
|
||||
(some
|
||||
(fn [parent]
|
||||
(let [parent-id (:db/id parent)
|
||||
blocks (:block/_parent parent)]
|
||||
(when (seq blocks)
|
||||
(when-let [start (parent-left->eid [parent-id parent-id])]
|
||||
(let [chain (loop [current start
|
||||
chain [start]]
|
||||
(let [next (parent-left->eid [parent-id current])]
|
||||
(if next
|
||||
(recur next (conj chain next))
|
||||
chain)))]
|
||||
(when (not= (count chain) (count blocks))
|
||||
{:parent parent
|
||||
:chain chain
|
||||
:broken-blocks (remove (set chain) (map :db/id blocks))
|
||||
:blocks blocks}))))))
|
||||
parents)))
|
||||
|
||||
(defn broken-page?
|
||||
"Whether `page` is broken."
|
||||
[db page-id]
|
||||
(prn :debug " Validate page: " page-id)
|
||||
(let [parent-left-f (fn [b]
|
||||
[(get-in b [:block/parent :db/id])
|
||||
(get-in b [:block/left :db/id])])
|
||||
page (d/entity db page-id)
|
||||
blocks (:block/_page page)
|
||||
parent-left->es (group-by parent-left-f blocks)
|
||||
conflicted (filter #(> (count (second %)) 1) parent-left->es)]
|
||||
(if (seq conflicted)
|
||||
[:conflict-parent-left conflicted]
|
||||
|
||||
(let [parent-left->eid (medley/map-vals (fn [c] (:db/id (first c))) parent-left->es)]
|
||||
(if-let [result (broken-chain? page parent-left->eid)]
|
||||
[:broken-chain result]
|
||||
false)))))
|
||||
@@ -1,19 +1,20 @@
|
||||
(ns frontend.modules.outliner.datascript
|
||||
(:require [datascript.core :as d]
|
||||
[frontend.db.conn :as conn]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.react :as react]
|
||||
[frontend.modules.outliner.pipeline :as pipelines]
|
||||
[frontend.modules.editor.undo-redo :as undo-redo]
|
||||
[frontend.state :as state]
|
||||
[frontend.config :as config]
|
||||
[logseq.graph-parser.util :as gp-util]
|
||||
[lambdaisland.glogi :as log]
|
||||
[frontend.search :as search]
|
||||
[clojure.string :as string]
|
||||
[frontend.util :as util]
|
||||
[frontend.util.property-edit :as property-edit]
|
||||
[logseq.graph-parser.util.block-ref :as block-ref]))
|
||||
[frontend.db.conn :as conn]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.react :as react]
|
||||
[frontend.modules.outliner.pipeline :as pipelines]
|
||||
[frontend.modules.editor.undo-redo :as undo-redo]
|
||||
[frontend.state :as state]
|
||||
[frontend.config :as config]
|
||||
[logseq.graph-parser.util :as gp-util]
|
||||
[lambdaisland.glogi :as log]
|
||||
[frontend.search :as search]
|
||||
[clojure.string :as string]
|
||||
[frontend.util :as util]
|
||||
[frontend.util.property-edit :as property-edit]
|
||||
[logseq.graph-parser.util.block-ref :as block-ref]
|
||||
[frontend.db.validate :as db-validate]))
|
||||
|
||||
(defn new-outliner-txs-state [] (atom []))
|
||||
|
||||
@@ -113,6 +114,29 @@
|
||||
(concat txs retracted-tx'))
|
||||
txs))
|
||||
|
||||
(defn validate-db!
|
||||
[{:keys [db-before db-after tx-data]}]
|
||||
(let [changed-pages (->> (filter (fn [d] (contains? #{:block/left :block/parent} (:a d))) tx-data)
|
||||
(map :e)
|
||||
distinct
|
||||
(map (fn [id]
|
||||
(-> (or (d/entity db-after id)
|
||||
(d/entity db-before id))
|
||||
:block/page
|
||||
:db/id)))
|
||||
(remove nil?)
|
||||
(distinct))]
|
||||
(reduce
|
||||
(fn [_ page-id]
|
||||
(if-let [result (db-validate/broken-page? db-after page-id)]
|
||||
(do
|
||||
;; revert db changes
|
||||
(assert (false? result) (str "Broken page: " result))
|
||||
(reduced false))
|
||||
true))
|
||||
true
|
||||
changed-pages)))
|
||||
|
||||
(defn transact!
|
||||
[txs opts before-editor-cursor]
|
||||
(let [repo (state/get-current-repo)
|
||||
@@ -148,6 +172,8 @@
|
||||
conn (conn/get-db repo false)
|
||||
rs (d/transact! conn txs (assoc opts :outliner/transact? true))
|
||||
tx-id (get-tx-id rs)]
|
||||
;; TODO: disable this when db is stable
|
||||
(validate-db! rs)
|
||||
(state/update-state! :history/tx->editor-cursor
|
||||
(fn [m] (assoc m tx-id before-editor-cursor)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user