diff --git a/CHANGELOG.md b/CHANGELOG.md index 598e98fc..2292653c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# WIP + +- Stable sorting of sequences of various types #470 + # 1.6.5 - May 3, 2024 - Regression: fixed some OR queries broken in 1.6.4 #468 #469 diff --git a/src/datascript/db.cljc b/src/datascript/db.cljc index ffac4a4d..91f9e4b5 100644 --- a/src/datascript/db.cljc +++ b/src/datascript/db.cljc @@ -438,11 +438,46 @@ #?(:clj (. clojure.lang.Util (hasheq x)) :cljs (hash x))) -(defn value-compare - ^long [x y] +(declare+ ^number value-compare [x y]) + +(defn- seq-compare [xs ys] + (let [cx (count xs) + cy (count ys)] + (cond + (< cx cy) + -1 + + (> cx cy) + 1 + + :else + (loop [xs xs + ys ys] + (if (empty? xs) + 0 + (let [x (first xs) + y (first ys)] + (cond + (and (nil? x) (nil? y)) + (recur (next xs) (next ys)) + + (nil? x) + -1 + + (nil? y) + 1 + + :else + (let [v (value-compare x y)] + (if (= v 0) + (recur (next xs) (next ys)) + v))))))))) + +(defn+ ^number value-compare [x y] (try (cond (= x y) 0 + (and (sequential? x) (sequential? y)) (seq-compare x y) #?@(:clj [(instance? Number x) (clojure.lang.Numbers/compare x y)]) #?@(:clj [(instance? Comparable x) (.compareTo ^Comparable x y)] :cljs [(satisfies? IComparable x) (-compare x y)]) diff --git a/test/datascript/test/index.cljc b/test/datascript/test/index.cljc index 4d2c798c..81923a84 100644 --- a/test/datascript/test/index.cljc +++ b/test/datascript/test/index.cljc @@ -63,7 +63,25 @@ (d/datoms db :avet :name "Ivan"))) (is (thrown-msg? "Attribute :name should be marked as :db/index true" - (d/datoms db :avet :name "Ivan" 1)))))) + (d/datoms db :avet :name "Ivan" 1)))) + + (testing "Sequence compare issue-470" + (let [db (-> (d/empty-db {:path {:db/index true}}) + (d/db-with [{:db/id 1 :path [1 2]} + {:db/id 2 :path [1 2 3]}]))] + (are [value result] (= result (mapv :e (d/datoms db :avet :path value))) + [1] [] + [1 1] [] + [1 2] [1] + (list 1 2) [1] + (butlast [1 2 3]) [1] + [1 3] [] + [1 2 2] [] + [1 2 3] [2] + (list 1 2 3) [2] + (butlast [1 2 3 4]) [2] + [1 2 4] [] + [1 2 3 4] []))))) (deftest test-datom (let [dvec #(when % (vector (:e %) (:a %) (:v %)))