|
|
@@ -32,6 +32,40 @@
|
|
|
[tx-data]
|
|
|
(boolean (some structural-tx-item? tx-data)))
|
|
|
|
|
|
+(defn- resolve-entity-id
|
|
|
+ [db value]
|
|
|
+ (cond
|
|
|
+ (int? value) value
|
|
|
+ (vector? value) (d/entid db value)
|
|
|
+ :else nil))
|
|
|
+
|
|
|
+(defn- tx-entity-ids
|
|
|
+ [db tx-data]
|
|
|
+ (->> tx-data
|
|
|
+ (keep (fn [item]
|
|
|
+ (cond
|
|
|
+ (vector? item)
|
|
|
+ (let [e (second item)]
|
|
|
+ (resolve-entity-id db e))
|
|
|
+
|
|
|
+ (d/datom? item)
|
|
|
+ (resolve-entity-id db (:e item))
|
|
|
+
|
|
|
+ (map? item)
|
|
|
+ (or (resolve-entity-id db (:db/id item))
|
|
|
+ (resolve-entity-id db [:block/uuid (:block/uuid item)]))
|
|
|
+
|
|
|
+ :else nil)))
|
|
|
+ (remove nil?)
|
|
|
+ set))
|
|
|
+
|
|
|
+(defn- entities-exist?
|
|
|
+ [db tx-data]
|
|
|
+ (every? (fn [id]
|
|
|
+ (when id
|
|
|
+ (d/entity db id)))
|
|
|
+ (tx-entity-ids db tx-data)))
|
|
|
+
|
|
|
(defn- parent-cycle?
|
|
|
[ent]
|
|
|
(let [start (:block/uuid ent)]
|
|
|
@@ -47,75 +81,6 @@
|
|
|
true
|
|
|
(recur next-ent (conj seen next-uuid) (inc steps))))))))
|
|
|
|
|
|
-(defn- db-issues
|
|
|
- [db]
|
|
|
- (let [ents (->> (d/q '[:find [?e ...]
|
|
|
- :where
|
|
|
- [?e :block/uuid]]
|
|
|
- db)
|
|
|
- (map (fn [e] (d/entity db e))))
|
|
|
- uuid-required-ids (->> (concat
|
|
|
- (d/q '[:find [?e ...]
|
|
|
- :where
|
|
|
- [?e :block/title]]
|
|
|
- db)
|
|
|
- (d/q '[:find [?e ...]
|
|
|
- :where
|
|
|
- [?e :block/page]]
|
|
|
- db)
|
|
|
- (d/q '[:find [?e ...]
|
|
|
- :where
|
|
|
- [?e :block/parent]]
|
|
|
- db))
|
|
|
- distinct)]
|
|
|
- (concat
|
|
|
- (for [e uuid-required-ids
|
|
|
- :let [ent (d/entity db e)]
|
|
|
- :when (nil? (:block/uuid ent))]
|
|
|
- {:type :missing-uuid :e e})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- parent (:block/parent ent)]
|
|
|
- :when (and (not (ldb/page? ent)) (nil? parent))]
|
|
|
- {:type :missing-parent :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- parent (:block/parent ent)]
|
|
|
- :when (and (not (ldb/page? ent)) parent (nil? (:block/uuid parent)))]
|
|
|
- {:type :missing-parent-ref :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- page (:block/page ent)]
|
|
|
- :when (and (not (ldb/page? ent)) (nil? page))]
|
|
|
- {:type :missing-page :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- page (:block/page ent)]
|
|
|
- :when (and (not (ldb/page? ent)) page (not (ldb/page? page)))]
|
|
|
- {:type :page-not-page :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- parent (:block/parent ent)
|
|
|
- page (:block/page ent)
|
|
|
- expected-page (when parent
|
|
|
- (if (ldb/page? parent) parent (:block/page parent)))]
|
|
|
- :when (and (not (ldb/page? ent))
|
|
|
- parent
|
|
|
- page
|
|
|
- expected-page
|
|
|
- (not= (:block/uuid expected-page) (:block/uuid page)))]
|
|
|
- {:type :page-mismatch :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)
|
|
|
- parent (:block/parent ent)]
|
|
|
- :when (and parent (= uuid (:block/uuid parent)))]
|
|
|
- {:type :self-parent :uuid uuid})
|
|
|
- (for [ent ents
|
|
|
- :let [uuid (:block/uuid ent)]
|
|
|
- :when (and (not (ldb/page? ent))
|
|
|
- (parent-cycle? ent))]
|
|
|
- {:type :cycle :uuid uuid}))))
|
|
|
-
|
|
|
(defn- issues-for-entity-ids
|
|
|
[db ids]
|
|
|
(let [id->ent (->> ids
|
|
|
@@ -211,7 +176,11 @@
|
|
|
[conn tx-data]
|
|
|
(try
|
|
|
(if-not (structural-tx? tx-data)
|
|
|
- true
|
|
|
+ (if (entities-exist? @conn tx-data)
|
|
|
+ true
|
|
|
+ (do
|
|
|
+ (log/warn ::undo-redo-invalid {:reason :missing-entities})
|
|
|
+ false))
|
|
|
(let [db-before @conn
|
|
|
tx-report (d/with db-before tx-data)
|
|
|
db-after (:db-after tx-report)
|