mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 22:25:01 +00:00
fix(db-sync): worker server unit-tests
This commit is contained in:
5
bb.edn
5
bb.edn
@@ -174,8 +174,9 @@
|
||||
:task (clojure {:dir "clj-e2e"} "-X:dev-run-rtc-extra-part2-test")}
|
||||
|
||||
dev:db-sync-test
|
||||
{:doc "Run db-sync unit tests"
|
||||
:task (shell {:dir "deps/db-sync"} "clojure -M:cljs compile db-sync-test && node worker/dist/worker-test.js")}
|
||||
{:doc "Run db-sync server unit tests"
|
||||
:task (do (shell {:dir "deps/db-sync"} "clojure -M:cljs compile db-sync-test")
|
||||
(shell {:dir "deps/db-sync"} "node worker/dist/worker-test.js"))}
|
||||
|
||||
dev:db-sync-start
|
||||
{:doc "Start db-sync local server + client watch processes in foreground"
|
||||
|
||||
48
deps/db-sync/src/logseq/db_sync/cycle.cljs
vendored
48
deps/db-sync/src/logseq/db_sync/cycle.cljs
vendored
@@ -45,18 +45,29 @@
|
||||
(keyword? entity) [:db/ident entity]
|
||||
:else entity))
|
||||
|
||||
(defn- next-parent-eid [db attr eid]
|
||||
(when-let [entity (d/entity db eid)]
|
||||
(let [value (get entity attr)]
|
||||
(:db/id value))))
|
||||
(defn- next-parent-eid [db attr eid updates-by-eid]
|
||||
(if (contains? updates-by-eid eid)
|
||||
(get updates-by-eid eid)
|
||||
(when-let [entity (d/entity db eid)]
|
||||
(let [value (get entity attr)]
|
||||
(cond
|
||||
(instance? Entity value) (:db/id value)
|
||||
:else (ref->eid db (normalize-entity-ref value)))))))
|
||||
|
||||
(defn- cycle-from-eid? [db attr eid]
|
||||
(loop [seen #{eid}
|
||||
current (next-parent-eid db attr eid)]
|
||||
(defn- cycle-from-eid? [db attr start-eid target-eid updates-by-eid]
|
||||
(loop [seen #{target-eid}
|
||||
current start-eid]
|
||||
(cond
|
||||
(nil? current) false
|
||||
(contains? seen current) true
|
||||
:else (recur (conj seen current) (next-parent-eid db attr current)))))
|
||||
:else (recur (conj seen current)
|
||||
(next-parent-eid db attr current updates-by-eid)))))
|
||||
|
||||
(defn- normalize-entity-ref-for-result [db entity-ref]
|
||||
(if (number? entity-ref)
|
||||
(when-let [ent (d/entity db entity-ref)]
|
||||
[:block/uuid (:block/uuid ent)])
|
||||
entity-ref))
|
||||
|
||||
(defn detect-cycle
|
||||
"Returns a map with cycle details when applying tx-data would introduce a cycle.
|
||||
@@ -65,16 +76,31 @@
|
||||
(reduce
|
||||
(fn [_ attr]
|
||||
(let [updates (attr-updates-from-tx tx-data attr)
|
||||
updates-by-eid
|
||||
(reduce
|
||||
(fn [acc {:keys [entity value]}]
|
||||
(let [entity-ref (normalize-entity-ref entity)
|
||||
eid (ref->eid db entity-ref)
|
||||
value-ref (normalize-entity-ref value)
|
||||
value-eid (ref->eid db value-ref)]
|
||||
(if eid
|
||||
(assoc acc eid value-eid)
|
||||
acc)))
|
||||
{}
|
||||
updates)
|
||||
result
|
||||
(reduce
|
||||
(fn [_ {:keys [entity value]}]
|
||||
(if (nil? value)
|
||||
nil
|
||||
(let [entity-ref (normalize-entity-ref entity)
|
||||
eid (ref->eid db entity-ref)]
|
||||
(when (and eid (cycle-from-eid? db attr eid))
|
||||
eid (ref->eid db entity-ref)
|
||||
value-ref (normalize-entity-ref value)
|
||||
value-eid (ref->eid db value-ref)]
|
||||
(when (and eid value-eid
|
||||
(cycle-from-eid? db attr value-eid eid updates-by-eid))
|
||||
{:attr attr
|
||||
:entity entity-ref}))))
|
||||
:entity (normalize-entity-ref-for-result db entity-ref)}))))
|
||||
nil
|
||||
updates)]
|
||||
(when result
|
||||
|
||||
98
deps/db-sync/src/logseq/db_sync/worker_core.cljs
vendored
98
deps/db-sync/src/logseq/db_sync/worker_core.cljs
vendored
@@ -2,39 +2,77 @@
|
||||
(:require [datascript.core :as d]
|
||||
[logseq.db.common.order :as db-order]))
|
||||
|
||||
(defn- attr-updates-from-tx [tx-data attr]
|
||||
(filter (fn [d] (= attr (:a d))) tx-data))
|
||||
(defn- normalize-eid [db entity]
|
||||
(cond
|
||||
(number? entity) (when (pos? entity) entity)
|
||||
(vector? entity) (d/entid db entity)
|
||||
(uuid? entity) (d/entid db [:block/uuid entity])
|
||||
(keyword? entity) (d/entid db [:db/ident entity])
|
||||
:else nil))
|
||||
|
||||
(defn- attr-updates-from-tx [db tx-data attr]
|
||||
(keep (fn [tx]
|
||||
(cond
|
||||
(and (vector? tx)
|
||||
(= :db/add (first tx))
|
||||
(= attr (nth tx 2 nil)))
|
||||
(let [eid (normalize-eid db (nth tx 1 nil))]
|
||||
(when eid
|
||||
{:e eid
|
||||
:a attr
|
||||
:v (nth tx 3 nil)}))
|
||||
|
||||
(and (map? tx) (contains? tx attr))
|
||||
(let [entity (or (:db/id tx) (:block/uuid tx) (:db/ident tx))
|
||||
eid (normalize-eid db entity)]
|
||||
(when eid
|
||||
{:e eid
|
||||
:a attr
|
||||
:v (get tx attr)}))
|
||||
|
||||
:else nil))
|
||||
tx-data))
|
||||
|
||||
(defn fix-duplicate-orders [db tx-data]
|
||||
(let [updates (attr-updates-from-tx tx-data :block/order)
|
||||
fixes (reduce
|
||||
(fn [acc d]
|
||||
(let [eid (:e d)
|
||||
value (:v d)
|
||||
parent (when eid (:block/parent (d/entity db eid)))
|
||||
parent-eid (:db/id parent)]
|
||||
(if (and eid parent-eid value)
|
||||
(let [siblings (d/datoms db :avet :block/parent parent-eid)
|
||||
same-order-siblings (-> (filter
|
||||
(fn [datom]
|
||||
(let [sib-eid (:e datom)]
|
||||
(when (and (not= sib-eid eid)
|
||||
(= value (:block/order (d/entity db sib-eid))))
|
||||
sib-eid)))
|
||||
siblings)
|
||||
sort
|
||||
vec)
|
||||
orders (map (fn [d] (:block/order (d/entity db (:e d)))) siblings)
|
||||
start (some (fn [order] (when (< order value) order)) orders)
|
||||
end (some (fn [order] (when (> order value) order)) orders)]
|
||||
(if same-order-siblings
|
||||
(let [orders (db-order/gen-n-keys (inc (count same-order-siblings)) start end)]
|
||||
(into acc
|
||||
(map-indexed (fn [idx id] [:db/add id :block/order (nth orders idx)]) (conj same-order-siblings eid))))
|
||||
acc))
|
||||
acc)))
|
||||
(let [updates (->> (attr-updates-from-tx db tx-data :block/order)
|
||||
(filter (fn [{:keys [e v]}] (and e v))))
|
||||
groups (group-by (fn [{:keys [e v]}]
|
||||
(let [parent (:block/parent (d/entity db e))]
|
||||
[(:db/id parent) v]))
|
||||
updates)
|
||||
fixes (reduce-kv
|
||||
(fn [acc [parent-eid value] group]
|
||||
(if (and parent-eid value)
|
||||
(let [update-eids (->> group (map :e) sort vec)
|
||||
siblings (d/datoms db :avet :block/parent parent-eid)
|
||||
update-eids-set (set update-eids)
|
||||
existing-same (->> siblings
|
||||
(keep (fn [datom]
|
||||
(let [sib-eid (:e datom)]
|
||||
(when (and (not (contains? update-eids-set sib-eid))
|
||||
(= value (:block/order (d/entity db sib-eid))))
|
||||
sib-eid)))))
|
||||
need-fix? (or (seq existing-same)
|
||||
(> (count update-eids) 1))]
|
||||
(if need-fix?
|
||||
(let [orders (->> siblings
|
||||
(keep (fn [d]
|
||||
(let [sib-eid (:e d)]
|
||||
(when-not (contains? update-eids-set sib-eid)
|
||||
(:block/order (d/entity db sib-eid)))))))
|
||||
end (some (fn [order]
|
||||
(when (> (compare order value) 0)
|
||||
order))
|
||||
orders)
|
||||
new-orders (db-order/gen-n-keys (count update-eids) value end)]
|
||||
(into acc
|
||||
(map-indexed (fn [idx id]
|
||||
[:db/add id :block/order (nth new-orders idx)])
|
||||
update-eids)))
|
||||
acc))
|
||||
acc))
|
||||
[]
|
||||
updates)]
|
||||
groups)]
|
||||
(if (seq fixes)
|
||||
(into tx-data fixes)
|
||||
tx-data)))
|
||||
|
||||
@@ -46,10 +46,7 @@ This guide helps AI agents implement and review db-sync features consistently ac
|
||||
|
||||
## Testing & Verification
|
||||
- Local dev(client+server): `bb dev:db-sync-start` runs the db-sync watcher, `wrangler dev`, and `yarn watch` with `ENABLE_DB_SYNC_LOCAL=true`
|
||||
- Unit tests: `bb dev:lint-and-test`
|
||||
- DB-sync tests: `bb dev:db-sync-test`
|
||||
- Single test example: `bb dev:test -v logseq.db-sync.storage-test/foo`
|
||||
- Worker local build: `clojure -M:cljs release db-sync`
|
||||
- DB-sync server side unit-tests: `bb dev:db-sync-test`
|
||||
|
||||
## Review Checklist
|
||||
- Protocol versioning and error handling are consistent across client/server.
|
||||
|
||||
Reference in New Issue
Block a user