feat: import SQLite db to create a new graph

feat/datascript-storage-test
Tienson Qin 2023-12-11 21:08:05 +08:00
parent 59fb0a58c7
commit 6684f28043
8 changed files with 89 additions and 28 deletions

View File

@ -11,7 +11,8 @@
[frontend.handler.import :as import-handler]
[clojure.string :as string]
[goog.object :as gobj]
[frontend.components.onboarding.setups :as setups]))
[frontend.components.onboarding.setups :as setups]
[frontend.util.text :as text-util]))
;; Can't name this component as `frontend.components.import` since shadow-cljs
;; will complain about it.
@ -45,13 +46,40 @@
:error))))
(defn- lsq-import-handler
[e]
[e & {:keys [sqlite?]}]
(let [file (first (array-seq (.-files (.-target e))))
file-name (some-> (gobj/get file "name")
(string/lower-case))
edn? (string/ends-with? file-name ".edn")
json? (string/ends-with? file-name ".json")]
(if (or edn? json?)
(cond
sqlite?
(let [graph-name (-> (js/prompt "Please specify a name for the new graph:")
str
string/trim)
all-graphs (->> (state/get-repos)
(map #(text-util/get-graph-name-from-path (:url %)))
set)]
(cond
(string/blank? graph-name)
(notification/show! "Empty graph name." :error)
(contains? all-graphs graph-name)
(notification/show! "Please specify another name as another graph with this name already exists!" :error)
:else
(let [reader (js/FileReader.)]
(set! (.-onload reader)
(fn []
(let [buffer (.-result ^js reader)]
(import-handler/import-from-sqlite-db! buffer graph-name finished-cb))))
(set! (.-onerror reader) (fn [e] (js/console.error e)))
(set! (.-onabort reader) (fn [e]
(prn :debug :aborted)
(js/console.error e)))
(.readAsArrayBuffer reader file))))
(or edn? json?)
(do
(state/set-state! :graph/importing :logseq)
(let [reader (js/FileReader.)
@ -67,6 +95,8 @@
(state/set-state! :graph/importing nil)
(finished-cb))))))
(.readAsText reader file)))
:else
(notification/show! "Please choose an EDN or a JSON file."
:error))))
@ -110,16 +140,17 @@
[:section.c.text-center
[:h1 (t :on-boarding/importing-title)]
[:h2 (t :on-boarding/importing-desc)]]
[:section.d.md:flex
[:section.d.md:flex.flex-col
[:label.action-input.flex.items-center.mx-2.my-2
[:span.as-flex-center [:i (svg/roam-research 28)]]
[:div.flex.flex-col
[[:strong "RoamResearch"]
[:small (t :on-boarding/importing-roam-desc)]]]
[:span.as-flex-center [:i (svg/logo 28)]]
[:span.flex.flex-col
[[:strong "SQLite"]
[:small (t :on-boarding/importing-sqlite-desc)]]]
[:input.absolute.hidden
{:id "import-roam"
{:id "import-sqlite-db"
:type "file"
:on-change roam-import-handler}]]
:on-change (fn [e]
(lsq-import-handler e {:sqlite? true}))}]]
[:label.action-input.flex.items-center.mx-2.my-2
[:span.as-flex-center [:i (svg/logo 28)]]
@ -132,7 +163,17 @@
:on-change lsq-import-handler}]]
[:label.action-input.flex.items-center.mx-2.my-2
[:span.as-flex-center (ui/icon "sitemap" {:style {:fontSize "26px"}})]
[:span.as-flex-center [:i (svg/roam-research 28)]]
[:div.flex.flex-col
[[:strong "RoamResearch"]
[:small (t :on-boarding/importing-roam-desc)]]]
[:input.absolute.hidden
{:id "import-roam"
:type "file"
:on-change roam-import-handler}]]
[:label.action-input.flex.items-center.mx-2.my-2
[:span.as-flex-center.ml-1 (ui/icon "sitemap" {:size 26})]
[:span.flex.flex-col
[[:strong "OPML"]
[:small (t :on-boarding/importing-opml-desc)]]]

View File

@ -380,7 +380,7 @@
[s]
(boolean
(and (string? s)
(string/starts-with? s db-version-prefix))))
(string/starts-with? s db-version-prefix))))
(defn get-local-asset-absolute-path
[s]

View File

@ -59,7 +59,7 @@
[repo data]
(p/let [^js pool (<get-opfs-pool repo)]
(when pool
(.importDB ^js pool (get-repo-path repo) data))))
(.importDb ^js pool (get-repo-path repo) data))))
(defn upsert-addr-content!
"Upsert addr+data-seq"
@ -254,11 +254,10 @@
[_this repo]
(<export-db-file repo))
(importDB
(importDb
[this repo data]
;; FIXME: repo not exists yet
(when-not (string/blank? repo)
(p/let [_ (.createOrOpenDB this repo)
(p/let [pool (<get-opfs-pool repo)
data (<import-db repo data)]
nil))))

View File

@ -402,7 +402,7 @@
[repo]
(p/let [data (persist-db/<export-db repo {:return-data? true})
filename (file-name repo "sqlite")
url (js/URL.createObjectURL (js/Blob. data))]
url (js/URL.createObjectURL (js/Blob. #js [data]))]
(when-not (mobile-util/native-platform?)
(when-let [anchor (gdom/getElement "download-as-sqlite-db")]
(.setAttribute anchor "href" url)

View File

@ -21,7 +21,9 @@
[frontend.handler.notification :as notification]
[frontend.util :as util]
[clojure.core.async :as async]
[medley.core :as medley]))
[medley.core :as medley]
[frontend.persist-db :as persist-db]
[promesa.core :as p]))
(defn index-files!
"Create file structure, then parse into DB (client only)"
@ -218,6 +220,22 @@
form))]
(walk/postwalk tree-trans-fn tree-vec))))
(defn import-from-sqlite-db!
[buffer bare-graph-name finished-ok-handler]
(let [graph (str config/db-version-prefix bare-graph-name)]
(-> (do
(persist-db/<import-db graph buffer)
(repo-handler/new-db! bare-graph-name))
(p/then
(fn [result]
(finished-ok-handler)))
(p/catch
(fn [e]
(js/console.error e)
(notification/show!
(str (.-message e))
:error))))))
(defn import-from-edn!
[raw finished-ok-handler]
(try

View File

@ -106,7 +106,7 @@
(<import-db [_this repo data]
(when-let [^js sqlite @*sqlite]
(-> (.importDB sqlite repo data)
(-> (.importDb sqlite repo data)
(p/catch (fn [error]
(prn :debug :import-db-error repo)
(js/console.error error)

View File

@ -147,12 +147,14 @@
On iOS, repo-url might be nil"
[repo-url]
(when (not-empty repo-url)
(let [path (config/get-local-dir repo-url)
path (if (path/is-file-url? path)
(path/url-to-path path)
path)
parts (->> (string/split path #"/")
(take-last 2))]
(if (not= (first parts) "0")
(util/string-join-path parts)
(last parts)))))
(if (config/db-based-graph? repo-url)
(string/replace-first repo-url config/db-version-prefix "")
(let [path (config/get-local-dir repo-url)
path (if (path/is-file-url? path)
(path/url-to-path path)
path)
parts (->> (string/split path #"/")
(take-last 2))]
(if (not= (first parts) "0")
(util/string-join-path parts)
(last parts))))))

View File

@ -51,6 +51,7 @@
:on-boarding/importing-desc "If they are in a JSON, EDN or Markdown format Logseq can work with them."
:on-boarding/importing-roam-desc "Import a JSON Export of your Roam graph"
:on-boarding/importing-lsq-desc "Import an EDN or a JSON Export of your Logseq graph"
:on-boarding/importing-sqlite-desc "Import an SQLite DB Export of your Logseq graph, this will create a new graph with your input name"
:on-boarding/importing-opml-desc " Import OPML files"
:on-boarding/main-title (fn [] ["Welcome to " [:strong "Logseq!"]])
:on-boarding/main-desc "First you need to choose a folder where Logseq will store your thoughts, ideas, notes."