mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 22:25:01 +00:00
enhance(cli): improve error messages for unspecified graphs
Introduced a breaking change for query and search commands where graph(s) are specified as options instead of arguments. This makes local graph usage consistent across all commands. Also fixed in-app search not working and local query with multiple graphs not querying from the right db
This commit is contained in:
16
deps/cli/README.md
vendored
16
deps/cli/README.md
vendored
@@ -1,6 +1,6 @@
|
||||
## Description
|
||||
|
||||
This library provides a `logseq` CLI for DB graphs. The CLI currently only applies to desktop DB graphs and requires the [database-version](/README.md#-database-version) desktop app to be installed. The CLI works offline by default which means it can also be used on CI/CD platforms like Github Actions. Some CLI commands can also interact with the current DB graph if the [HTTP Server](https://docs.logseq.com/#/page/local%20http%20server) is turned on in the Desktop app.
|
||||
This library provides a `logseq` CLI for DB graphs. The CLI currently only applies to desktop DB graphs and requires the [database-version](/README.md#-database-version) desktop app to be installed. The CLI works offline by default which means it can also be used on CI/CD platforms like Github Actions. Most CLI commands can also interact with the current DB graph if the [HTTP Server](https://docs.logseq.com/#/page/local%20http%20server) is turned on in the Desktop app.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -12,9 +12,9 @@ This section assumes you have installed the CLI from npm or via the [dev
|
||||
setup](#setup). If you haven't, substitute `node cli.mjs` for `logseq` e.g.
|
||||
`node.cli.mjs -h`.
|
||||
|
||||
All commands except for `append` can be used offline or on CI. The `search` command and any command that has an api-server-token option require the [HTTP API Server](https://docs.logseq.com/#/page/local%20http%20server) to be turned on.
|
||||
All commands work with both local graphs and the current in-app graph except for `append` (in-app graph only) and `export` (local graph only). For a command to work with an in-app graph, the [HTTP API Server](https://docs.logseq.com/#/page/local%20http%20server) must be turned on.
|
||||
|
||||
Now let's use it!
|
||||
Now let's use the CLI!
|
||||
|
||||
```
|
||||
$ logseq -h
|
||||
@@ -30,9 +30,9 @@ search [options] Search DB graph
|
||||
query [options] Query DB graph(s)
|
||||
export [options] Export DB graph as Markdown
|
||||
export-edn [options] Export DB graph as EDN
|
||||
import-edn [options] Import into DB graph with EDN
|
||||
append [options] Appends text to current page
|
||||
mcp-server [options] Run a MCP server
|
||||
import-edn [options] Import into DB graph with EDN
|
||||
help Print a command's help
|
||||
|
||||
$ logseq list
|
||||
@@ -68,7 +68,7 @@ $ LOGSEQ_API_SERVER_TOKEN=my-token logseq search woot
|
||||
...
|
||||
|
||||
# Search a local graph
|
||||
$ logseq search woot page
|
||||
$ logseq search page -g woot
|
||||
Search found 23 results:
|
||||
Node page
|
||||
Annotation page
|
||||
@@ -76,7 +76,7 @@ Annotation page
|
||||
|
||||
# Query a graph locally using `d/entity` id(s) like an integer or a :db/ident
|
||||
# Can also specify a uuid string to fetch an entity
|
||||
$ logseq query woot 10 :logseq.class/Tag
|
||||
$ logseq query 10 :logseq.class/Tag -g woot
|
||||
({:db/id 10,
|
||||
:db/ident :logseq.kv/graph-git-sha,
|
||||
:kv/value "f736895b1b-dirty"}
|
||||
@@ -92,7 +92,7 @@ $ logseq query woot 10 :logseq.class/Tag
|
||||
:block/name "tag"})
|
||||
|
||||
# Query a graph using a datalog query
|
||||
$ logseq query woot '[:find (pull ?b [*]) :where [?b :kv/value]]'
|
||||
$ logseq query '[:find (pull ?b [*]) :where [?b :kv/value]]' -g woot
|
||||
[{:db/id 5, :db/ident :logseq.kv/db-type, :kv/value "db"}
|
||||
{:db/id 6,
|
||||
:db/ident :logseq.kv/schema-version,
|
||||
@@ -117,7 +117,7 @@ $ logseq query '(task DOING)' -a my-token
|
||||
...
|
||||
|
||||
# Export local graph as markdown
|
||||
$ logseq export yep
|
||||
$ logseq export -g yep
|
||||
Exported 41 pages to yep_markdown_1756128259.zip
|
||||
|
||||
# Export current graph as EDN
|
||||
|
||||
16
deps/cli/src/logseq/cli.cljs
vendored
16
deps/cli/src/logseq/cli.cljs
vendored
@@ -78,23 +78,27 @@
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.search/search)
|
||||
:desc "Search DB graph"
|
||||
:description "Search a local graph or the current in-app graph if --api-server-token is given. For a local graph it only searches the :block/title of blocks."
|
||||
:args->opts [:graph :search-terms] :coerce {:search-terms []} :require [:graph]
|
||||
:args->opts [:search-terms] :coerce {:search-terms []}
|
||||
:spec cli-spec/search}
|
||||
{:cmds ["query"] :desc "Query DB graph(s)"
|
||||
:description "Query a local graph or the current in-app graph if --api-server-token is given. For a local graph, queries are a datalog query or an entity query. A datalog query can use built-in rules. An entity query consists of one or more integers, uuids or :db/ident keywords. For an in-app query, queries can be an advanced or simple query."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.query/query)
|
||||
:args->opts [:graph :args] :coerce {:args []} :no-keyword-opts true :require [:graph]
|
||||
:args->opts [:args] :coerce {:args []} :no-keyword-opts true
|
||||
:spec cli-spec/query}
|
||||
{:cmds ["export"] :desc "Export DB graph as Markdown"
|
||||
:description "Export a graph to Markdown like the in-app graph export."
|
||||
:description "Export a local graph to Markdown like the in-app graph export."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.export/export)
|
||||
:args->opts [:graph] :require [:graph]
|
||||
:spec cli-spec/export}
|
||||
{:cmds ["export-edn"] :desc "Export DB graph as EDN"
|
||||
:description "Export a local graph to EDN or the current in-app graph if --api-server-token is given. See https://github.com/logseq/docs/blob/master/db-version.md#edn-data-export for more about this export type."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.export-edn/export)
|
||||
:spec cli-spec/export-edn}
|
||||
{:cmds ["import-edn"] :desc "Import into DB graph with EDN"
|
||||
:description "Import with EDN into a local graph or the current in-app graph if --api-server-token is given. See https://github.com/logseq/docs/blob/master/db-version.md#edn-data-export for more about this import type."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.import-edn/import-edn)
|
||||
:spec cli-spec/import-edn}
|
||||
{:cmds ["append"] :desc "Appends text to current page"
|
||||
:description "Append text to current page of current in-app graph."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.append/append)
|
||||
:args->opts [:args] :require [:args] :coerce {:args []}
|
||||
:spec cli-spec/append}
|
||||
@@ -102,10 +106,6 @@
|
||||
:description "Run a MCP server against a local graph if --graph is given or against the current in-app graph. By default the MCP server runs as a HTTP Streamable server. Use --stdio to run it as a stdio server."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.mcp-server/start)
|
||||
:spec cli-spec/mcp-server}
|
||||
{:cmds ["import-edn"] :desc "Import into DB graph with EDN"
|
||||
:description "Import with EDN into a local graph or the current in-app graph if --api-server-token is given. See https://github.com/logseq/docs/blob/master/db-version.md#edn-data-export for more about this import type."
|
||||
:fn (lazy-load-fn 'logseq.cli.commands.import-edn/import-edn)
|
||||
:spec cli-spec/import-edn}
|
||||
{:cmds ["help"] :fn help-command :desc "Print a command's help"
|
||||
:args->opts [:command] :require [:command]}
|
||||
{:cmds []
|
||||
|
||||
2
deps/cli/src/logseq/cli/commands/export.cljs
vendored
2
deps/cli/src/logseq/cli/commands/export.cljs
vendored
@@ -74,6 +74,8 @@
|
||||
(println "Exported" (count exported-files) "pages to" file-name)))))
|
||||
|
||||
(defn export [{{:keys [graph] :as opts} :opts}]
|
||||
(when-not graph
|
||||
(cli-util/error "Command missing required option 'graph'"))
|
||||
(if (fs/existsSync (cli-util/get-graph-path graph))
|
||||
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))]
|
||||
(export-repo-as-markdown! (str common-config/db-version-prefix graph) @conn opts))
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
(p/catch cli-util/command-catch-handler)))
|
||||
|
||||
(defn- local-import [{:keys [graph]} import-map]
|
||||
(when-not graph
|
||||
(cli-util/error "Command missing required option 'graph'"))
|
||||
(if (fs/existsSync (cli-util/get-graph-path graph))
|
||||
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
|
||||
{:keys [init-tx block-props-tx misc-tx]}
|
||||
|
||||
58
deps/cli/src/logseq/cli/commands/query.cljs
vendored
58
deps/cli/src/logseq/cli/commands/query.cljs
vendored
@@ -71,36 +71,36 @@
|
||||
(if (= 1 (count (first res))) (mapv first res) res)))
|
||||
|
||||
(defn- local-query
|
||||
[{{:keys [graph args graphs properties-readable title-query]} :opts}]
|
||||
(let [graphs' (into [graph] graphs)]
|
||||
(doseq [graph' graphs']
|
||||
(if (fs/existsSync (cli-util/get-graph-path graph'))
|
||||
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
|
||||
query* (when (string? (first args)) (common-util/safe-read-string {:log-error? false} (first args)))
|
||||
results (cond
|
||||
;; Run datalog query if detected
|
||||
(and (vector? query*) (= :find (first query*)))
|
||||
(local-datalog-query @conn query*)
|
||||
;; Runs predefined title query. Predefined queries could better off in a separate command
|
||||
;; since they could be more powerful and have different args than query command
|
||||
title-query
|
||||
(let [query '[:find (pull ?b [*])
|
||||
:in $ % ?search-term
|
||||
:where (block-content ?b ?search-term)]
|
||||
res (d/q query @conn (rules/extract-rules rules/db-query-dsl-rules)
|
||||
(string/join " " args))]
|
||||
;; Remove nesting for most queries which just have one :find binding
|
||||
(if (= 1 (count (first res))) (mapv first res) res))
|
||||
:else
|
||||
(local-entities-query @conn properties-readable args))]
|
||||
(when (> (count graphs') 1)
|
||||
(println "Results for graph" (pr-str graph')))
|
||||
(pprint/pprint results))
|
||||
(cli-util/error "Graph" (pr-str graph') "does not exist")))))
|
||||
[{{:keys [args graphs properties-readable title-query]} :opts}]
|
||||
(when-not graphs
|
||||
(cli-util/error "Command missing required option 'graphs'"))
|
||||
(doseq [graph graphs]
|
||||
(if (fs/existsSync (cli-util/get-graph-path graph))
|
||||
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
|
||||
query* (when (string? (first args)) (common-util/safe-read-string {:log-error? false} (first args)))
|
||||
results (cond
|
||||
;; Run datalog query if detected
|
||||
(and (vector? query*) (= :find (first query*)))
|
||||
(local-datalog-query @conn query*)
|
||||
;; Runs predefined title query. Predefined queries could better off in a separate command
|
||||
;; since they could be more powerful and have different args than query command
|
||||
title-query
|
||||
(let [query '[:find (pull ?b [*])
|
||||
:in $ % ?search-term
|
||||
:where (block-content ?b ?search-term)]
|
||||
res (d/q query @conn (rules/extract-rules rules/db-query-dsl-rules)
|
||||
(string/join " " args))]
|
||||
;; Remove nesting for most queries which just have one :find binding
|
||||
(if (= 1 (count (first res))) (mapv first res) res))
|
||||
:else
|
||||
(local-entities-query @conn properties-readable args))]
|
||||
(when (> (count graphs) 1)
|
||||
(println "Results for graph" (pr-str graph)))
|
||||
(pprint/pprint results))
|
||||
(cli-util/error "Graph" (pr-str graph) "does not exist"))))
|
||||
|
||||
(defn query
|
||||
[{{:keys [graph args api-server-token]} :opts :as m}]
|
||||
[{{:keys [args api-server-token]} :opts :as m}]
|
||||
(if api-server-token
|
||||
;; graph can be query since it's not used for api-query
|
||||
(api-query (or graph (first args)) api-server-token)
|
||||
(api-query (first args) api-server-token)
|
||||
(local-query m)))
|
||||
8
deps/cli/src/logseq/cli/commands/search.cljs
vendored
8
deps/cli/src/logseq/cli/commands/search.cljs
vendored
@@ -46,11 +46,13 @@
|
||||
(if (= 200 (.-status resp))
|
||||
(p/let [body (.json resp)]
|
||||
(let [{:keys [blocks]} (js->clj body :keywordize-keys true)]
|
||||
(format-results (map :block/title blocks) search-term {:raw raw :api? true})))
|
||||
(format-results (map :title blocks) search-term {:raw raw :api? true})))
|
||||
(cli-util/api-handle-error-response resp)))
|
||||
(p/catch cli-util/command-catch-handler)))
|
||||
|
||||
(defn- local-search [search-term {{:keys [graph raw limit]} :opts}]
|
||||
(when-not graph
|
||||
(cli-util/error "Command missing required option 'graph'"))
|
||||
(if (fs/existsSync (cli-util/get-graph-path graph))
|
||||
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
|
||||
nodes (->> (d/datoms @conn :aevt :block/title)
|
||||
@@ -61,7 +63,7 @@
|
||||
(format-results nodes search-term {:raw raw}))
|
||||
(cli-util/error "Graph" (pr-str graph) "does not exist")))
|
||||
|
||||
(defn search [{{:keys [graph search-terms api-server-token]} :opts :as m}]
|
||||
(defn search [{{:keys [search-terms api-server-token]} :opts :as m}]
|
||||
(if api-server-token
|
||||
(api-search (string/join " " (into [graph] search-terms)) m)
|
||||
(api-search (string/join " " search-terms) m)
|
||||
(local-search (string/join " " search-terms) m)))
|
||||
8
deps/cli/src/logseq/cli/spec.cljs
vendored
8
deps/cli/src/logseq/cli/spec.cljs
vendored
@@ -3,7 +3,9 @@
|
||||
commands but are separate because command namespaces are lazy loaded")
|
||||
|
||||
(def export
|
||||
{:file {:alias :f
|
||||
{:graph {:alias :g
|
||||
:desc "Local graph to export"}
|
||||
:file {:alias :f
|
||||
:desc "File to save export"}})
|
||||
|
||||
(def export-edn
|
||||
@@ -43,7 +45,7 @@
|
||||
:desc "API server token to query current graph"}
|
||||
:graphs {:alias :g
|
||||
:coerce []
|
||||
:desc "Additional graphs to local query"}
|
||||
:desc "Local graph(s) to query"}
|
||||
:properties-readable {:alias :p
|
||||
:coerce :boolean
|
||||
:desc "Make properties on local, entity queries show property values instead of ids"}
|
||||
@@ -53,6 +55,8 @@
|
||||
(def search
|
||||
{:api-server-token {:alias :a
|
||||
:desc "API server token to search current graph"}
|
||||
:graph {:alias :g
|
||||
:desc "Local graph to search"}
|
||||
:raw {:alias :r
|
||||
:desc "Print raw response"}
|
||||
:limit {:alias :l
|
||||
|
||||
Reference in New Issue
Block a user