mirror of
https://github.com/logseq/logseq.git
synced 2026-05-24 20:54:09 +00:00
fix: multiple issues with --fields option for list* commands
- 4 visible fields couldn't be used with --fields - Only print selected fields/columns. Previous behavior didn't make sense as unspecified fields were still listed and took up horizontal space - Allow --fields to work when --expand isn't used. Previous behavior wasn't explained to user and needlessly limiting
This commit is contained in:
@@ -79,7 +79,7 @@ List page options:
|
||||
| --include-hidden | Include hidden pages | Requires a flag to bypass entity-util/hidden? filtering. |
|
||||
| --updated-after ISO8601 | Filter by updated-at | Compare to :block/updated-at. |
|
||||
| --created-after ISO8601 | Filter by created-at | Compare to :block/created-at. |
|
||||
| --fields FIELD,FIELD | Select output fields | Applies when --expand is true. |
|
||||
| --fields FIELD,FIELD | Select output fields | |
|
||||
|
||||
List tag options:
|
||||
|
||||
@@ -88,7 +88,7 @@ List tag options:
|
||||
| --include-built-in | Include built-in classes | Built-in tags are currently included by default, clarify behavior. |
|
||||
| --with-properties | Include class properties | Uses :logseq.property.class/properties when expanded. |
|
||||
| --with-extends | Include class extends | Uses :logseq.property.class/extends when expanded. |
|
||||
| --fields FIELD,FIELD | Select output fields | Applies when --expand is true. |
|
||||
| --fields FIELD,FIELD | Select output fields | |
|
||||
|
||||
List property options:
|
||||
|
||||
@@ -97,7 +97,7 @@ List property options:
|
||||
| --include-built-in | Include built-in properties | Built-in properties are currently included by default, clarify behavior. |
|
||||
| --with-classes | Include property classes | Uses :logseq.property/classes when expanded. |
|
||||
| --with-type | Include property type | Uses :logseq.property/type when expanded. |
|
||||
| --fields FIELD,FIELD | Select output fields | Applies when --expand is true. |
|
||||
| --fields FIELD,FIELD | Select output fields | |
|
||||
|
||||
List block is removed to avoid overlap with search.
|
||||
|
||||
|
||||
@@ -94,23 +94,31 @@
|
||||
:options options}}))
|
||||
|
||||
(def ^:private list-page-field-map
|
||||
{"title" :block/title
|
||||
{"id" :db/id
|
||||
"ident" :db/ident
|
||||
"title" :block/title
|
||||
"uuid" :block/uuid
|
||||
"created-at" :block/created-at
|
||||
"updated-at" :block/updated-at})
|
||||
|
||||
(def ^:private list-tag-field-map
|
||||
{"name" :block/title
|
||||
{"id" :db/id
|
||||
"ident" :db/ident
|
||||
"title" :block/title
|
||||
"uuid" :block/uuid
|
||||
"created-at" :block/created-at
|
||||
"updated-at" :block/updated-at
|
||||
"properties" :logseq.property.class/properties
|
||||
"extends" :logseq.property.class/extends
|
||||
"description" :logseq.property/description})
|
||||
|
||||
(def ^:private list-property-field-map
|
||||
{"name" :block/title
|
||||
{"id" :db/id
|
||||
"ident" :db/ident
|
||||
"title" :block/title
|
||||
"uuid" :block/uuid
|
||||
"created-at" :block/created-at
|
||||
"updated-at" :block/updated-at
|
||||
"classes" :logseq.property/classes
|
||||
"type" :logseq.property/type
|
||||
"description" :logseq.property/description})
|
||||
@@ -178,9 +186,7 @@
|
||||
fields (parse-field-list (:fields options))
|
||||
sorted (apply-sort items (:sort options) order list-page-field-map)
|
||||
limited (apply-offset-limit sorted (:offset options) (:limit options))
|
||||
final (if (:expand options)
|
||||
(apply-fields limited fields list-page-field-map)
|
||||
limited)]
|
||||
final (apply-fields limited fields list-page-field-map)]
|
||||
{:status :ok
|
||||
:data {:items final}})))
|
||||
|
||||
@@ -195,9 +201,7 @@
|
||||
prepared (mapv #(prepare-tag-item % options) items)
|
||||
sorted (apply-sort prepared (:sort options) order list-tag-field-map)
|
||||
limited (apply-offset-limit sorted (:offset options) (:limit options))
|
||||
final (if (:expand options)
|
||||
(apply-fields limited fields list-tag-field-map)
|
||||
limited)]
|
||||
final (apply-fields limited fields list-tag-field-map)]
|
||||
{:status :ok
|
||||
:data {:items final}})))
|
||||
|
||||
@@ -212,8 +216,6 @@
|
||||
prepared (mapv #(prepare-property-item % options) items)
|
||||
sorted (apply-sort prepared (:sort options) order list-property-field-map)
|
||||
limited (apply-offset-limit sorted (:offset options) (:limit options))
|
||||
final (if (:expand options)
|
||||
(apply-fields limited fields list-property-field-map)
|
||||
limited)]
|
||||
final (apply-fields limited fields list-property-field-map)]
|
||||
{:status :ok
|
||||
:data {:items final}})))
|
||||
|
||||
@@ -122,11 +122,6 @@
|
||||
candidates* (str candidates*)
|
||||
hint (str "\nHint: " hint)))))
|
||||
|
||||
(defn- maybe-ident-header
|
||||
[items]
|
||||
(when (some :db/ident items)
|
||||
["IDENT"]))
|
||||
|
||||
(defn- parse-ts
|
||||
[value]
|
||||
(cond
|
||||
@@ -154,37 +149,36 @@
|
||||
:else (str years "y ago")))
|
||||
"-"))
|
||||
|
||||
(defn- format-list-row
|
||||
[item include-ident? now-ms]
|
||||
(let [base [(or (:db/id item) (:id item))
|
||||
(or (:title item) (:block/title item) (:name item))]
|
||||
with-ident (cond-> base
|
||||
include-ident? (conj (:db/ident item)))
|
||||
updated (human-ago (or (:updated-at item) (:block/updated-at item)) now-ms)
|
||||
created (human-ago (or (:created-at item) (:block/created-at item)) now-ms)]
|
||||
(conj with-ident updated created)))
|
||||
(defn- items-have-key?
|
||||
[items & ks]
|
||||
(some (fn [item] (some #(contains? item %) ks)) items))
|
||||
|
||||
(def ^:private list-columns
|
||||
[["ID" (fn [item _] (or (:db/id item) (:id item))) [:db/id :id]]
|
||||
["TITLE" (fn [item _] (or (:title item) (:block/title item) (:name item))) [:title :block/title :name]]
|
||||
["IDENT" (fn [item _] (:db/ident item)) [:db/ident]]
|
||||
["UPDATED-AT" (fn [item now-ms] (human-ago (or (:updated-at item) (:block/updated-at item)) now-ms)) [:updated-at :block/updated-at]]
|
||||
["CREATED-AT" (fn [item now-ms] (human-ago (or (:created-at item) (:block/created-at item)) now-ms)) [:created-at :block/created-at]]])
|
||||
|
||||
(defn- format-list-dynamic
|
||||
[items now-ms columns]
|
||||
(let [items (or items [])
|
||||
active (filterv (fn [[_ _ ks always?]]
|
||||
(or always? (apply items-have-key? items ks)))
|
||||
columns)
|
||||
headers (mapv first active)
|
||||
rows (mapv (fn [item]
|
||||
(mapv (fn [[_ extractor _]] (extractor item now-ms)) active))
|
||||
items)]
|
||||
(format-counted-table headers rows)))
|
||||
|
||||
(defn- format-list-page
|
||||
[items now-ms]
|
||||
(let [items (or items [])
|
||||
include-ident? (boolean (some :db/ident items))
|
||||
headers (into ["ID" "TITLE"]
|
||||
(concat (or (maybe-ident-header items) [])
|
||||
["UPDATED-AT" "CREATED-AT"]))]
|
||||
(format-counted-table
|
||||
headers
|
||||
(mapv #(format-list-row % include-ident? now-ms) items))))
|
||||
(format-list-dynamic items now-ms list-columns))
|
||||
|
||||
(defn- format-list-tag
|
||||
[items now-ms]
|
||||
(let [items (or items [])
|
||||
include-ident? (boolean (some :db/ident items))
|
||||
headers (into ["ID" "TITLE"]
|
||||
(concat (or (maybe-ident-header items) [])
|
||||
["UPDATED-AT" "CREATED-AT"]))]
|
||||
(format-counted-table
|
||||
headers
|
||||
(mapv #(format-list-row % include-ident? now-ms) items))))
|
||||
(format-list-dynamic items now-ms list-columns))
|
||||
|
||||
(defn- normalize-property-type
|
||||
[value]
|
||||
@@ -193,27 +187,17 @@
|
||||
(nil? value) "-"
|
||||
:else (str value)))
|
||||
|
||||
(defn- format-list-property-row
|
||||
[item include-ident? now-ms]
|
||||
(let [base [(or (:db/id item) (:id item))
|
||||
(or (:title item) (:block/title item) (:name item))
|
||||
(normalize-property-type (:logseq.property/type item))]
|
||||
with-ident (cond-> base
|
||||
include-ident? (conj (:db/ident item)))
|
||||
updated (human-ago (or (:updated-at item) (:block/updated-at item)) now-ms)
|
||||
created (human-ago (or (:created-at item) (:block/created-at item)) now-ms)]
|
||||
(conj with-ident updated created)))
|
||||
(def ^:private list-property-columns
|
||||
[["ID" (fn [item _] (or (:db/id item) (:id item))) [:db/id :id]]
|
||||
["TITLE" (fn [item _] (or (:title item) (:block/title item) (:name item))) [:title :block/title :name]]
|
||||
["TYPE" (fn [item _] (normalize-property-type (:logseq.property/type item))) [:logseq.property/type]]
|
||||
["IDENT" (fn [item _] (:db/ident item)) [:db/ident]]
|
||||
["UPDATED-AT" (fn [item now-ms] (human-ago (or (:updated-at item) (:block/updated-at item)) now-ms)) [:updated-at :block/updated-at]]
|
||||
["CREATED-AT" (fn [item now-ms] (human-ago (or (:created-at item) (:block/created-at item)) now-ms)) [:created-at :block/created-at]]])
|
||||
|
||||
(defn- format-list-property
|
||||
[items now-ms]
|
||||
(let [items (or items [])
|
||||
include-ident? (boolean (some :db/ident items))
|
||||
headers (into ["ID" "TITLE" "TYPE"]
|
||||
(concat (or (maybe-ident-header items) [])
|
||||
["UPDATED-AT" "CREATED-AT"]))]
|
||||
(format-counted-table
|
||||
headers
|
||||
(mapv #(format-list-property-row % include-ident? now-ms) items))))
|
||||
(format-list-dynamic items now-ms list-property-columns))
|
||||
|
||||
(defn- format-graph-list
|
||||
[graphs current-graph]
|
||||
|
||||
@@ -133,15 +133,21 @@
|
||||
(testing "list property renders missing type as -"
|
||||
(let [result (format/format-result {:status :ok
|
||||
:command :list-property
|
||||
:data {:items [{:block/title "Untyped"
|
||||
:data {:items [{:block/title "Prop"
|
||||
:db/id 99
|
||||
:logseq.property/type :node
|
||||
:block/created-at 40000
|
||||
:block/updated-at 90000}
|
||||
{:block/title "Untyped"
|
||||
:db/id 100
|
||||
:block/created-at 40000
|
||||
:block/updated-at 90000}]}}
|
||||
{:output-format nil
|
||||
:now-ms 100000})]
|
||||
(is (= (str "ID TITLE TYPE UPDATED-AT CREATED-AT\n"
|
||||
"99 Prop node 10s ago 1m ago\n"
|
||||
"100 Untyped - 10s ago 1m ago\n"
|
||||
"Count: 1")
|
||||
"Count: 2")
|
||||
result)))))
|
||||
|
||||
(deftest test-human-output-add-upsert-remove
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
:updated-at 1735686000000}
|
||||
overrides)))
|
||||
|
||||
(deftest test-cli-login-integration
|
||||
(deftest ^:long test-cli-login-integration
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "cli-login-data")
|
||||
cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
|
||||
@@ -237,7 +237,7 @@
|
||||
(p/finally (fn []
|
||||
(done))))))))
|
||||
|
||||
(deftest test-cli-logout-integration
|
||||
(deftest ^:long test-cli-logout-integration
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "cli-logout-data")
|
||||
cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
|
||||
@@ -270,7 +270,7 @@
|
||||
(p/finally (fn []
|
||||
(done))))))))
|
||||
|
||||
(deftest test-cli-sync-remote-graphs-refreshes-auth-file-and-injects-runtime-token
|
||||
(deftest ^:long test-cli-sync-remote-graphs-refreshes-auth-file-and-injects-runtime-token
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "cli-sync-auth")
|
||||
cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
|
||||
@@ -316,7 +316,7 @@
|
||||
(p/finally (fn []
|
||||
(done))))))))
|
||||
|
||||
(deftest test-cli-sync-download-and-start-readiness-with-mocked-sync
|
||||
(deftest ^:long test-cli-sync-download-and-start-readiness-with-mocked-sync
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "db-worker-sync-cli")
|
||||
download-repo "sync-download-graph"
|
||||
@@ -390,7 +390,7 @@
|
||||
(is false (str "unexpected error: " e))
|
||||
(done)))))))
|
||||
|
||||
(deftest test-cli-sync-upload-with-mocked-worker-bootstrap
|
||||
(deftest ^:long test-cli-sync-upload-with-mocked-worker-bootstrap
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "db-worker-sync-upload-cli")
|
||||
upload-repo "sync-upload-graph"
|
||||
@@ -432,7 +432,7 @@
|
||||
(is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest test-cli-sync-upload-followed-by-graph-info-shows-graph-uuid-test
|
||||
(deftest ^:long test-cli-sync-upload-followed-by-graph-info-shows-graph-uuid-test
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "db-worker-sync-upload-info-cli")
|
||||
upload-repo "sync-upload-graph-info"
|
||||
@@ -2209,6 +2209,37 @@
|
||||
(is false (str "unexpected error: " e))
|
||||
(done)))))))
|
||||
|
||||
(deftest ^:long test-cli-list-page-fields-filter
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "db-worker")]
|
||||
(-> (p/let [cfg-path (node-path/join (node-helper/create-tmp-dir "cli") "cli.edn")
|
||||
_ (fs/writeFileSync cfg-path "{:output-format :json}")
|
||||
_ (run-cli ["graph" "create" "--graph" "fields-graph"] data-dir cfg-path)
|
||||
_ (run-cli ["upsert" "page" "--page" "FieldTest"] data-dir cfg-path)
|
||||
all-result (run-cli ["list" "page"] data-dir cfg-path)
|
||||
all-payload (parse-json-output all-result)
|
||||
filtered-result (run-cli ["list" "page" "--fields" "title"] data-dir cfg-path)
|
||||
filtered-payload (parse-json-output filtered-result)
|
||||
human-filtered-result (run-cli ["list" "page" "--fields" "title" "--output" "human"] data-dir cfg-path)
|
||||
first-all (first (get-in all-payload [:data :items]))
|
||||
first-filtered (first (get-in filtered-payload [:data :items]))
|
||||
_ (stop-repo! data-dir cfg-path "fields-graph")]
|
||||
(is (= 0 (:exit-code all-result)))
|
||||
(is (= 0 (:exit-code filtered-result)))
|
||||
(is (contains? first-all :title))
|
||||
(is (contains? first-all :updated-at))
|
||||
(is (contains? first-filtered :title))
|
||||
(is (not (contains? first-filtered :updated-at))
|
||||
"--fields title should exclude other fields")
|
||||
(is (= 0 (:exit-code human-filtered-result)))
|
||||
(is (string/includes? (:output human-filtered-result) "TITLE"))
|
||||
(is (not (string/includes? (:output human-filtered-result) "UPDATED-AT"))
|
||||
"--fields title human output should not show UPDATED-AT column")
|
||||
(done))
|
||||
(p/catch (fn [e]
|
||||
(is false (str "unexpected error: " e))
|
||||
(done)))))))
|
||||
|
||||
(deftest ^:long test-cli-show-page-block-by-id-and-uuid
|
||||
(async done
|
||||
(let [data-dir (node-helper/create-tmp-dir "db-worker")]
|
||||
|
||||
Reference in New Issue
Block a user