From 8d30cd4a2d4714f1c22fb79ac882d53b4d5dd587 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 30 Mar 2026 17:55:18 -0400 Subject: [PATCH] fix(cli): `upsert property --type` on a property that has property values makes a graph invalid as property values then have the wrong types for their property pair. This isn't possible in the UI because the property type change checks for existing data but the db-worker-node level does not. This :logseq.property/type update bug was also possible from plugin/API calls --- deps/outliner/src/logseq/outliner/property.cljs | 6 ++++++ .../test/logseq/outliner/property_test.cljs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index 5a561ed96d..0358e7dbab 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -221,6 +221,12 @@ {:type :notification :payload {:message "This property can't change from multiple values to one value because it has existing data." :type :warning}}))) + (when (and (contains? changed-property-attrs :logseq.property/type) + (seq (d/datoms @conn :avet db-ident))) + (throw (ex-info "Disallowed type change with existing data" + {:type :notification + :payload {:message "This property's type can't be changed because it has existing data." + :type :error}}))) (when (seq tx-data) (ldb/transact! conn tx-data {:outliner-op :update-property :property-id (:db/id property)})) diff --git a/deps/outliner/test/logseq/outliner/property_test.cljs b/deps/outliner/test/logseq/outliner/property_test.cljs index 057750d90c..1dcfa6910e 100644 --- a/deps/outliner/test/logseq/outliner/property_test.cljs +++ b/deps/outliner/test/logseq/outliner/property_test.cljs @@ -45,6 +45,20 @@ (:block/title (d/entity @conn :user.property/p1-2))) "3rd property gets unique ident")))) +(deftest upsert-property-rejects-type-change-with-existing-data + (testing "Changing type is rejected when property has values" + (let [conn (db-test/create-conn-with-blocks + [{:page {:block/title "page1"} + :blocks [{:block/title "b1" :build/properties {:status "active"}}]}])] + (is (thrown-with-msg? + js/Error #"Disallowed type change with existing data" + (outliner-property/upsert-property! conn :user.property/status {:logseq.property/type :number} {}))))) + + (testing "Changing type is allowed when property has no values" + (let [conn (db-test/create-conn-with-blocks {:properties {:empty-prop {:logseq.property/type :default}}})] + (outliner-property/upsert-property! conn :user.property/empty-prop {:logseq.property/type :number} {}) + (is (= :number (:logseq.property/type (d/entity @conn :user.property/empty-prop))))))) + (deftest convert-property-input-string (testing "Convert property input string according to its schema type" (let [test-uuid (random-uuid)]