mirror of
https://github.com/logseq/logseq.git
synced 2026-05-25 05:04:24 +00:00
Add example update script
Split out persist-graph as it is useful outside of just creating graphs. Also updated docstring with more known limitations
This commit is contained in:
@@ -2,41 +2,19 @@
|
||||
"This ns provides fns to create a DB graph using EDN. See `init-conn` for
|
||||
initializing a DB graph with a datascript connection that syncs to a sqlite DB
|
||||
at the given directory. See `create-blocks-tx` for the EDN format to create a
|
||||
graph. Note that block creation is limited to top level blocks for now. This
|
||||
ns can likely be used to also update graphs"
|
||||
graph and current limitations"
|
||||
(:require [logseq.db.sqlite.db :as sqlite-db]
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[cljs-bean.core :as bean]
|
||||
[logseq.tasks.db-graph.persist-graph :as persist-graph]
|
||||
[logseq.db :as ldb]
|
||||
[clojure.string :as string]
|
||||
[datascript.core :as d]
|
||||
["fs" :as fs]
|
||||
["path" :as node-path]
|
||||
[nbb.classpath :as cp]
|
||||
;; TODO: Move these namespaces to more stable deps/ namespaces
|
||||
[frontend.modules.datascript-report.core :as ds-report]
|
||||
[frontend.modules.outliner.pipeline-util :as pipeline-util]
|
||||
;; TODO: Move this namespace to more stable deps/ namespaces
|
||||
[frontend.handler.common.repo :as repo-common-handler]))
|
||||
|
||||
(defn- invoke-hooks
|
||||
"Modified copy frontend.modules.outliner.pipeline/invoke-hooks that doesn't
|
||||
handle :block/path-refs recalculation"
|
||||
[{:keys [db-after] :as tx-report}]
|
||||
(let [{:keys [blocks]} (ds-report/get-blocks-and-pages tx-report)
|
||||
deleted-block-uuids (set (pipeline-util/filter-deleted-blocks (:tx-data tx-report)))
|
||||
upsert-blocks (pipeline-util/build-upsert-blocks blocks deleted-block-uuids db-after)]
|
||||
{:blocks upsert-blocks
|
||||
:deleted-block-uuids deleted-block-uuids}))
|
||||
|
||||
(defn- update-sqlite-db
|
||||
"Modified copy of :db-transact-data defmethod in electron.handler"
|
||||
[db-name {:keys [blocks deleted-block-uuids]}]
|
||||
(when (seq deleted-block-uuids)
|
||||
(sqlite-db/delete-blocks! db-name deleted-block-uuids))
|
||||
(when (seq blocks)
|
||||
(let [blocks' (mapv sqlite-util/ds->sqlite-block blocks)]
|
||||
(sqlite-db/upsert-blocks! db-name (bean/->js blocks')))))
|
||||
|
||||
(defn- find-on-classpath [rel-path]
|
||||
(some (fn [dir]
|
||||
(let [f (node-path/join dir rel-path)]
|
||||
@@ -61,8 +39,7 @@
|
||||
(sqlite-db/open-db! dir db-name)
|
||||
;; Same order as frontend.db.conn/start!
|
||||
(let [conn (ldb/start-conn :create-default-pages? false)]
|
||||
(d/listen! conn :persist-to-sqlite (fn persist-to-sqlite [tx-report]
|
||||
(update-sqlite-db db-name (invoke-hooks tx-report))))
|
||||
(persist-graph/add-listener conn db-name)
|
||||
(ldb/create-default-pages! conn)
|
||||
(setup-init-data conn)
|
||||
conn))
|
||||
@@ -145,8 +122,15 @@
|
||||
|
||||
(defn create-blocks-tx
|
||||
"Given an EDN map for defining pages, blocks and properties, this creates a
|
||||
vector of transactable data for use with d/transact!. The EDN map is basic and
|
||||
only supports defining blocks at the top level. The EDN map has the following keys:
|
||||
vector of transactable data for use with d/transact!. The blocks that can be created
|
||||
have the following limitations:
|
||||
|
||||
* Only top level blocks can be easily defined. Other level blocks can be
|
||||
defined but they require explicit setting of attributes like :block/left and :block/parent
|
||||
* Block content containing page refs or tags is not supported yet
|
||||
* Property types :object and :date aren't supported yet
|
||||
|
||||
The EDN map has the following keys:
|
||||
|
||||
* :pages-and-blocks - This is a vector of maps containing a :page key and optionally a :blocks
|
||||
key when defining a page's blocks. More about each key:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[clojure.string :as string]
|
||||
[datascript.core :as d]
|
||||
["path" :as node-path]
|
||||
["os" :as os]
|
||||
[nbb.core :as nbb]))
|
||||
|
||||
(defn- date-journal-title [date]
|
||||
@@ -67,7 +68,10 @@
|
||||
(when (not= 1 (count args))
|
||||
(println "Usage: $0 GRAPH-DIR")
|
||||
(js/process.exit 1))
|
||||
(let [[dir db-name] ((juxt node-path/dirname node-path/basename) (first args))
|
||||
(let [graph-dir (first args)
|
||||
[dir db-name] (if (string/includes? graph-dir "/")
|
||||
((juxt node-path/dirname node-path/basename) graph-dir)
|
||||
[(node-path/join (os/homedir) "logseq" "graphs") graph-dir])
|
||||
conn (create-graph/init-conn dir db-name)
|
||||
blocks-tx (create-graph/create-blocks-tx (create-init-data))]
|
||||
(println "Generating" (count (filter :block/name blocks-tx)) "pages and"
|
||||
|
||||
38
scripts/src/logseq/tasks/db_graph/persist_graph.cljs
Normal file
38
scripts/src/logseq/tasks/db_graph/persist_graph.cljs
Normal file
@@ -0,0 +1,38 @@
|
||||
(ns logseq.tasks.db-graph.persist-graph
|
||||
"This ns allows DB graphs to persist datascript changes to their respective
|
||||
sqlite db. Since changes are persisted, this can be used to create or update graphs.
|
||||
Known limitations:
|
||||
* Changes to block references don't update :block/path-refs"
|
||||
(:require [datascript.core :as d]
|
||||
[logseq.db.sqlite.db :as sqlite-db]
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[cljs-bean.core :as bean]
|
||||
;; TODO: Move these namespaces to more stable deps/ namespaces
|
||||
[frontend.modules.datascript-report.core :as ds-report]
|
||||
[frontend.modules.outliner.pipeline-util :as pipeline-util]))
|
||||
|
||||
(defn- invoke-hooks
|
||||
"Modified copy frontend.modules.outliner.pipeline/invoke-hooks that doesn't
|
||||
handle :block/path-refs recalculation"
|
||||
[{:keys [db-after] :as tx-report}]
|
||||
(let [{:keys [blocks]} (ds-report/get-blocks-and-pages tx-report)
|
||||
deleted-block-uuids (set (pipeline-util/filter-deleted-blocks (:tx-data tx-report)))
|
||||
upsert-blocks (pipeline-util/build-upsert-blocks blocks deleted-block-uuids db-after)]
|
||||
{:blocks upsert-blocks
|
||||
:deleted-block-uuids deleted-block-uuids}))
|
||||
|
||||
(defn- update-sqlite-db
|
||||
"Modified copy of :db-transact-data defmethod in electron.handler"
|
||||
[db-name {:keys [blocks deleted-block-uuids]}]
|
||||
(when (seq deleted-block-uuids)
|
||||
(sqlite-db/delete-blocks! db-name deleted-block-uuids))
|
||||
(when (seq blocks)
|
||||
(let [blocks' (mapv sqlite-util/ds->sqlite-block blocks)]
|
||||
(sqlite-db/upsert-blocks! db-name (bean/->js blocks')))))
|
||||
|
||||
(defn add-listener
|
||||
"Adds a listener to the datascript connection to persist changes to the given
|
||||
sqlite db name"
|
||||
[conn db-name]
|
||||
(d/listen! conn :persist-to-sqlite (fn persist-to-sqlite [tx-report]
|
||||
(update-sqlite-db db-name (invoke-hooks tx-report)))))
|
||||
@@ -0,0 +1,42 @@
|
||||
(ns logseq.tasks.db-graph.update-graph-to-add-todos
|
||||
"This script updates blocks that match the given query and turns them into TODOs"
|
||||
(:require [logseq.tasks.db-graph.persist-graph :as persist-graph]
|
||||
[logseq.db.sqlite.cli :as sqlite-cli]
|
||||
[logseq.db.sqlite.db :as sqlite-db]
|
||||
[logseq.db.rules :as rules]
|
||||
[datascript.core :as d]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.string :as string]
|
||||
[nbb.core :as nbb]
|
||||
["path" :as node-path]
|
||||
["os" :as os]))
|
||||
|
||||
(defn -main [args]
|
||||
(when (not= 2 (count args))
|
||||
(println "Usage: $0 GRAPH-DIR QUERY")
|
||||
(js/process.exit 1))
|
||||
(let [[graph-dir query*] args
|
||||
[dir db-name] (if (string/includes? graph-dir "/")
|
||||
((juxt node-path/dirname node-path/basename) graph-dir)
|
||||
[(node-path/join (os/homedir) "logseq" "graphs") graph-dir])
|
||||
_ (sqlite-db/open-db! dir db-name)
|
||||
conn (sqlite-cli/read-graph db-name)
|
||||
;; find blocks to update
|
||||
query (into (edn/read-string query*) [:in '$ '%]) ;; assumes no :in are in queries
|
||||
blocks-to-update (mapv first (d/q query @conn (rules/extract-rules rules/db-query-dsl-rules)))
|
||||
;; update
|
||||
todo-id (or (:db/id (d/entity @conn [:block/name "todo"]))
|
||||
(throw (ex-info "No :db/id for TODO" {})))
|
||||
update-tx (vec (keep #(when-not (:block/marker %)
|
||||
(hash-map :db/id (:db/id %)
|
||||
:block/content (str "TODO " (:block/content %))
|
||||
:block/marker "TODO"
|
||||
:block/refs (into [{:db/id todo-id}] (:block/refs %))
|
||||
:block/path-refs (into [{:db/id todo-id}] (:block/path-refs %))))
|
||||
blocks-to-update))]
|
||||
(persist-graph/add-listener conn db-name)
|
||||
(d/transact! conn update-tx)
|
||||
(println "Updated" (count update-tx) "block(s) with a 'TODO' for graph" (str db-name "!"))))
|
||||
|
||||
(when (= nbb/*file* (:file (meta #'-main)))
|
||||
(-main *command-line-args*))
|
||||
Reference in New Issue
Block a user