From f9edbb087492130680d90fa59d75f1dbf87fa1db Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 1 Apr 2026 09:51:16 -0400 Subject: [PATCH] fix(cli): --update-{tags|properties} can't distinguish between tags/properties with same name. Same bug as 0809a53e796ee6327b838f39d5f2d590c5263505 --- src/main/logseq/cli/command/add.cljs | 46 +++++++++++++++++------ src/main/logseq/cli/command/upsert.cljs | 25 +----------- src/test/logseq/cli/command/add_test.cljs | 41 ++++++++++++++------ 3 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/main/logseq/cli/command/add.cljs b/src/main/logseq/cli/command/add.cljs index 1fb38e8cbe..09fe680f9c 100644 --- a/src/main/logseq/cli/command/add.cljs +++ b/src/main/logseq/cli/command/add.cljs @@ -36,6 +36,32 @@ (transport/invoke config :thread-api/pull false [repo [:db/id :block/uuid :block/name :block/title] [:block/name page-name-lc]])))))) +(defn pull-tag-by-name + "Look up a tag by name, constrained to entities tagged with :logseq.class/Tag." + [config repo tag-name selector] + (p/let [result (transport/invoke config :thread-api/q false + [repo + [{:find [[(list 'pull '?e selector) '...]] + :in '[$ ?name] + :where '[[?e :block/name ?name] + [?e :block/tags ?t] + [?t :db/ident :logseq.class/Tag]]} + (common-util/page-name-sanity-lc tag-name)]])] + (first result))) + +(defn pull-property-by-name + "Look up a property by name, constrained to entities tagged with :logseq.class/Property." + [config repo property-name selector] + (p/let [result (transport/invoke config :thread-api/q false + [repo + [{:find [[(list 'pull '?e selector) '...]] + :in '[$ ?name] + :where '[[?e :block/name ?name] + [?e :block/tags ?t] + [?t :db/ident :logseq.class/Property]]} + (common-util/page-name-sanity-lc property-name)]])] + (first result))) + (def ^:private add-positions #{"first-child" "last-child" "sibling"}) @@ -626,19 +652,18 @@ (uuid? tag) [:block/uuid tag] (and (string? tag) (common-util/uuid-string? (string/trim tag))) [:block/uuid (uuid (string/trim tag))] (keyword? tag) [:db/ident tag] - (string? tag) [:block/name (common-util/page-name-sanity-lc tag)] :else nil)) (defn- resolve-tag-entity [config repo tag] - (let [lookup (tag-lookup-ref tag)] - (when-not lookup - (throw (ex-info "invalid tag value" {:code :invalid-tag :tag tag}))) - (p/let [entity (pull-entity config repo - [:db/id :block/name :block/title :block/uuid - {:block/tags [:db/ident]} - :logseq.property/public? :logseq.property/built-in?] - lookup)] + (let [tag-selector [:db/id :block/name :block/title :block/uuid + {:block/tags [:db/ident]} + :logseq.property/public? :logseq.property/built-in?]] + (p/let [entity (if (string? tag) + (pull-tag-by-name config repo tag tag-selector) + (let [lookup (or (tag-lookup-ref tag) + (throw (ex-info "invalid tag value" {:code :invalid-tag :tag tag})))] + (pull-entity config repo tag-selector lookup)))] (cond (nil? (:db/id entity)) (throw (ex-info (str "tag not found: " (pr-str tag)) {:code :tag-not-found :tag tag})) @@ -761,8 +786,7 @@ (defn- lookup-property-entity [config repo property-key] (let [lookup-by-title (fn [title] - (pull-entity config repo property-entity-selector - [:block/name (common-util/page-name-sanity-lc title)]))] + (pull-property-by-name config repo title property-entity-selector))] (cond (number? property-key) (pull-entity config repo property-entity-selector property-key) diff --git a/src/main/logseq/cli/command/upsert.cljs b/src/main/logseq/cli/command/upsert.cljs index 844472f6f1..07f6f36477 100644 --- a/src/main/logseq/cli/command/upsert.cljs +++ b/src/main/logseq/cli/command/upsert.cljs @@ -345,29 +345,8 @@ (transport/invoke config :thread-api/pull false [repo selector [:block/name (common-util/page-name-sanity-lc page-name)]])) -(defn- pull-tag-by-name - [config repo tag-name selector] - (p/let [result (transport/invoke config :thread-api/q false - [repo - [{:find [[(list 'pull '?e selector) '...]] - :in '[$ ?name] - :where '[[?e :block/name ?name] - [?e :block/tags ?t] - [?t :db/ident :logseq.class/Tag]]} - (common-util/page-name-sanity-lc tag-name)]])] - (first result))) - -(defn- pull-property-by-name - [config repo property-name selector] - (p/let [result (transport/invoke config :thread-api/q false - [repo - [{:find [[(list 'pull '?e selector) '...]] - :in '[$ ?name] - :where '[[?e :block/name ?name] - [?e :block/tags ?t] - [?t :db/ident :logseq.class/Property]]} - (common-util/page-name-sanity-lc property-name)]])] - (first result))) +(def ^:private pull-tag-by-name add-command/pull-tag-by-name) +(def ^:private pull-property-by-name add-command/pull-property-by-name) (defn- ensure-property-identifiers-exist! [config repo property-idents] diff --git a/src/test/logseq/cli/command/add_test.cljs b/src/test/logseq/cli/command/add_test.cljs index 9dff9f1b66..b0f14aafa3 100644 --- a/src/test/logseq/cli/command/add_test.cljs +++ b/src/test/logseq/cli/command/add_test.cljs @@ -48,19 +48,34 @@ (is (= [uuid-b] (-> error ex-data :missing-uuids)))))) (def ^:private mock-transport-invoke - (fn [_ _ _ args] - (let [[_ _ lookup] args] - (p/resolved - (cond - (= lookup [:block/name "plainpage"]) - {:db/id 42 :block/name "plainpage" :block/title "PlainPage" - :block/tags [{:db/ident :logseq.class/Page}]} + (fn [_ method _ args] + (case method + ;; pull-tag-by-name uses :thread-api/q + :thread-api/q + (let [[_ [_ name-arg]] args] + (p/resolved + (cond + (= name-arg "realtag") + [{:db/id 99 :block/name "realtag" :block/title "RealTag" + :block/tags [{:db/ident :logseq.class/Tag}]}] + :else []))) - (= lookup [:block/name "realtag"]) - {:db/id 99 :block/name "realtag" :block/title "RealTag" - :block/tags [{:db/ident :logseq.class/Tag}]} + ;; pull-entity uses :thread-api/pull + :thread-api/pull + (let [[_ _ lookup] args] + (p/resolved + (cond + (= lookup [:block/name "plainpage"]) + {:db/id 42 :block/name "plainpage" :block/title "PlainPage" + :block/tags [{:db/ident :logseq.class/Page}]} - :else {}))))) + (= lookup [:block/name "realtag"]) + {:db/id 99 :block/name "realtag" :block/title "RealTag" + :block/tags [{:db/ident :logseq.class/Tag}]} + + :else {}))) + + (p/rejected (ex-info "unexpected method" {:method method :args args}))))) (deftest test-resolve-tags-accepts-valid-tag (async done @@ -76,7 +91,9 @@ (-> (add-command/resolve-tags {} "demo" ["PlainPage"]) (p/then (fn [_] (is false "expected error for non-tag page"))) (p/catch (fn [e] - (is (= :not-a-tag (-> e ex-data :code))) + ;; String lookup uses pull-tag-by-name which only finds tags, + ;; so a non-tag page results in :tag-not-found + (is (= :tag-not-found (-> e ex-data :code))) (is (string/includes? (ex-message e) "PlainPage")))))) (p/catch (fn [e] (is false (str "unexpected error: " e)))) (p/finally done))))