Explorar o código

Add tests for core sqlite db fns

These core db fns have been split out to be platform agnostic
so they can be run on CLI or non electron platforms
Gabriel Horner %!s(int64=2) %!d(string=hai) anos
pai
achega
2ab6370dda

+ 4 - 0
deps/db/nbb.edn

@@ -0,0 +1,4 @@
+{:paths ["src"]
+ :deps
+ {io.github.nextjournal/nbb-test-runner
+  {:git/sha "60ed57aa04bca8d604f5ba6b28848bd887109347"}}}

+ 6 - 0
deps/db/package.json

@@ -4,5 +4,11 @@
   "private": true,
   "devDependencies": {
     "@logseq/nbb-logseq": "^1.2.173"
+  },
+  "dependencies": {
+    "better-sqlite3": "8.0.1"
+  },
+  "scripts": {
+    "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner"
   }
 }

+ 140 - 0
deps/db/src/logseq/db/sqlite/db.cljs

@@ -0,0 +1,140 @@
+(ns logseq.db.sqlite.db
+  "Main entry point for using sqlite with db graphs"
+  (:require ["path" :as node-path]
+            ["better-sqlite3" :as sqlite3]
+            [clojure.string :as string]
+            [cljs-bean.core :as bean]))
+
+;; use built-in blocks to represent db schema, config, custom css, custom js, etc.
+
+;; Store databases for db graphs
+(defonce databases (atom nil))
+;; Reference same sqlite default class in cljs + nbb without needing .cljc
+(def sqlite (if (find-ns 'nbb.core) (aget sqlite3 "default") sqlite3))
+
+(defn close!
+  []
+  (when @databases
+    (doseq [[_ database] @databases]
+      (.close database))
+    (reset! databases nil)))
+
+(defn sanitize-db-name
+  [db-name]
+  (-> db-name
+      (string/replace "logseq_db_" "")
+      (string/replace "/" "_")
+      (string/replace "\\" "_")
+      (string/replace ":" "_"))) ;; windows
+
+(defn get-db
+  [repo]
+  (get @databases (sanitize-db-name repo)))
+
+(defn prepare
+  [^object db sql db-name]
+  (when db
+    (try
+      (.prepare db sql)
+      (catch :default e
+        (js/console.error (str "SQLite prepare failed: " e ": " db-name))
+        (throw e)))))
+
+(defn create-blocks-table!
+  [db db-name]
+  (let [stmt (prepare db "CREATE TABLE IF NOT EXISTS blocks (
+                        uuid TEXT PRIMARY KEY,
+                        type INTEGER,
+                        page_uuid TEXT,
+                        page_journal_day INTEGER,
+                        name TEXT,
+                        content TEXT,
+                        datoms TEXT,
+                        created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
+                        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL
+                        )"
+                      db-name)]
+    (.run ^object stmt)
+    (let [create-index-stmt (prepare db "CREATE INDEX IF NOT EXISTS block_type ON blocks(type)" db-name)]
+      (.run ^object create-index-stmt))))
+
+;; TODO: Wrap in electron with (fs/ensureDirSync graph-dir)
+(defn get-db-full-path
+  [graphs-dir db-name]
+  (let [db-name' (sanitize-db-name db-name)
+        graph-dir (node-path/join graphs-dir db-name')]
+    [db-name' (node-path/join graph-dir "db.sqlite")]))
+
+;; TODO: Wrap in electron with try
+(defn open-db!
+  [graphs-dir db-name]
+  (let [[db-sanitized-name db-full-path] (get-db-full-path graphs-dir db-name)
+        db (new sqlite db-full-path nil)]
+    (create-blocks-table! db db-name)
+    (swap! databases assoc db-sanitized-name db)))
+
+(defn- clj-list->sql
+  "Turn clojure list into SQL list
+   '(1 2 3 4)
+   ->
+   \"('1','2','3','4')\""
+  [ids]
+  (str "(" (->> (map (fn [id] (str "'" id "'")) ids)
+                (string/join ", ")) ")"))
+
+(defn upsert-blocks!
+  [graphs-dir repo blocks]
+  (if-let [db (get-db repo)]
+    (let [insert (prepare db "INSERT INTO blocks (uuid, type, page_uuid, page_journal_day, name, content,datoms, created_at, updated_at) VALUES (@uuid, @type, @page_uuid, @page_journal_day, @name, @content, @datoms, @created_at, @updated_at) ON CONFLICT (uuid) DO UPDATE SET (type, page_uuid, page_journal_day, name, content, datoms, created_at, updated_at) = (@type, @page_uuid, @page_journal_day, @name, @content, @datoms, @created_at, @updated_at)"
+                          repo)
+          insert-many (.transaction ^object db
+                                    (fn [blocks]
+                                      (doseq [block blocks]
+                                        (.run ^object insert block))))]
+      (insert-many blocks))
+    (do
+      (open-db! graphs-dir repo)
+      (upsert-blocks! graphs-dir repo blocks))))
+
+(defn delete-blocks!
+  [repo uuids]
+  (when-let [db (get-db repo)]
+    (let [sql (str "DELETE from blocks WHERE uuid IN " (clj-list->sql uuids))
+          stmt (prepare db sql repo)]
+      (.run ^object stmt))))
+
+
+;; Initial data:
+;; All pages and block ids
+;; latest 3 journals
+;; other data such as config.edn, custom css/js
+;; current page, sidebar blocks
+
+(defn- query
+  [repo db sql]
+  (let [stmt (prepare db sql repo)]
+    (.all ^object stmt)))
+
+(defn get-initial-data
+  [repo]
+  (when-let [db (get-db repo)]
+    (let [all-pages (query repo db "select * from blocks where type = 2") ; 2 = page block
+          ;; 1 = normal block
+          all-block-ids (query repo db "select uuid, page_uuid from blocks where type = 1")
+          recent-journal (some-> (query repo db "select uuid from blocks where type = 2 order by page_journal_day desc limit 1")
+                                 first
+                                 bean/->clj
+                                 :uuid)
+          latest-journal-blocks (when recent-journal
+                                  (query repo db (str "select * from blocks where type = 1 and page_uuid = '" recent-journal "'")))
+          init-data (query repo db "select * from blocks where type in (3, 4, 5, 6)")]
+      {:all-pages all-pages
+       :all-blocks all-block-ids
+       :journal-blocks latest-journal-blocks
+       :init-data init-data})))
+
+(defn get-other-data
+  [repo journal-block-uuids]
+  (when-let [db (get-db repo)]
+    (query repo db (str "select * from blocks where type = 1 and uuid not in "
+                        (clj-list->sql journal-block-uuids)))))

+ 42 - 0
deps/db/src/logseq/db/sqlite/util.cljs

@@ -0,0 +1,42 @@
+(ns logseq.db.sqlite.util
+  "Utils fns for backend sqlite db"
+  (:require [cljs-time.coerce :as tc]
+            [cljs-time.core :as t]))
+
+(defn- type-of-block
+  "
+  TODO: use :block/type
+  | value | meaning                                        |
+  |-------+------------------------------------------------|
+  |     1 | normal block                                   |
+  |     2 | page block                                     |
+  |     3 | init data, (config.edn, custom.js, custom.css) |
+  |     4 | db schema                                      |
+  |     5 | unknown type                                   |
+  |     6 | property block                                 |
+  "
+  [block]
+  (cond
+    (:block/page block) 1
+    (:file/content block) 3
+    (= "property" (:block/type block)) 6
+    (:block/name block) 2
+    :else 5))
+
+(defn time-ms
+  "Copy of util/time-ms. Too basic to couple this to main app"
+  []
+  (tc/to-long (t/now)))
+
+(defn ds->sqlite-block
+  "Convert a datascript block to a sqlite map in preparation for a sqlite-db fn"
+  [b]
+  {:uuid (str (:block/uuid b))
+   :type (type-of-block b)
+   :page_uuid (str (:page_uuid b))
+   :page_journal_day (:block/journal-day b)
+   :name (:block/name b)
+   :content (or (:file/content b) (:block/content b))
+   :datoms (:datoms b)
+   :created_at (or (:block/created-at b) (time-ms))
+   :updated_at (or (:block/updated-at b) (time-ms))})

+ 100 - 0
deps/db/test/logseq/db/sqlite/db_test.cljs

@@ -0,0 +1,100 @@
+(ns logseq.db.sqlite.db-test
+  (:require [cljs.test :refer [deftest async use-fixtures is testing]]
+            ["fs" :as fs]
+            ["path" :as node-path]
+            [cljs-bean.core :as bean]
+            [logseq.db.sqlite.db :as sqlite-db]
+            [logseq.db.sqlite.util :as sqlite-util]))
+
+(use-fixtures
+  :each
+ ;; Cleaning tmp/ before leaves last tmp/ after a test run for dev and debugging
+  {:before
+   #(async done
+           (if (fs/existsSync "tmp")
+             (fs/rm "tmp" #js {:recursive true} (fn [err]
+                                                  (when err (js/console.log err))
+                                                  (done)))
+             (done)))})
+
+(defn- create-graph-dir
+  [dir db-name]
+  (fs/mkdirSync (node-path/join dir db-name) #js {:recursive true}))
+
+(deftest upsert-blocks!
+  (let [page-uuid (random-uuid)
+        block-uuid (random-uuid)
+        created-at 1688054127299]
+    (create-graph-dir "tmp/graphs" "test-db")
+    (sqlite-db/open-db! "tmp/graphs" "test-db")
+
+    (testing "create a journal block"
+      (let [blocks (mapv sqlite-util/ds->sqlite-block
+                         [{:block/uuid page-uuid
+                           :block/journal-day 20230629
+                           :block/name "jun 29th, 2023"
+                           :block/created-at created-at
+                           :block/updated-at created-at}
+                          {:block/content "test"
+                           :block/uuid block-uuid
+                           :block/page {:db/id 100022}
+                           :block/created-at created-at
+                           :block/updated-at created-at
+                           :page_uuid page-uuid}])
+            _ (sqlite-db/upsert-blocks! "tmp/graphs" "test-db" (bean/->js blocks))
+            db-data (sqlite-db/get-initial-data "test-db")]
+        (is (= {:uuid (str page-uuid) :page_journal_day 20230629
+                :name "jun 29th, 2023" :type 2
+                :created_at created-at}
+               (-> db-data
+                   :all-pages
+                   first
+                   bean/->clj
+                   (select-keys [:uuid :page_journal_day :type :name :created_at])))
+            "New journal page is saved")
+
+        (is (= {:content "test" :name nil
+                :uuid (str block-uuid) :type 1
+                :created_at created-at}
+               (-> db-data
+                   :journal-blocks
+                   first
+                   bean/->clj
+                   (select-keys [:uuid :type :content :name :created_at])))
+            "New journal block content is saved")
+
+        (is (= [{:uuid (str block-uuid) :page_uuid (str page-uuid)}]
+               (-> db-data :all-blocks bean/->clj))
+            "Correct block and page uuid pairs exist")))
+
+    (testing "update a block"
+      (let [updated-at 1688072416134
+            blocks (mapv sqlite-util/ds->sqlite-block
+                         [{:block/uuid page-uuid
+                           :block/journal-day 20230629
+                           :block/name "jun 29th, 2023"
+                           :block/created-at created-at
+                           :block/updated-at updated-at}
+                          {:block/content "test edit"
+                           :block/uuid block-uuid
+                           :block/page {:db/id 100022}
+                           :block/created-at created-at
+                           :block/updated-at updated-at
+                           :page_uuid page-uuid}])
+            _ (sqlite-db/upsert-blocks! "tmp/graphs" "test-db" (bean/->js blocks))
+            db-data (sqlite-db/get-initial-data "test-db")]
+        (is (= {:uuid (str page-uuid) :updated_at updated-at :created_at created-at}
+               (-> db-data
+                   :all-pages
+                   first
+                   bean/->clj
+                   (select-keys [:uuid :updated_at :created_at])))
+            "Updated page has correct timestamps")
+
+        (is (= {:content "test edit" :created_at created-at :updated_at updated-at}
+               (-> db-data
+                   :journal-blocks
+                   first
+                   bean/->clj
+                   (select-keys [:content :created_at :updated_at])))
+            "Updated block has correct content and timestamps")))))

+ 268 - 0
deps/db/yarn.lock

@@ -9,7 +9,275 @@
   dependencies:
     import-meta-resolve "^2.1.0"
 
+base64-js@^1.3.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+  integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
[email protected]:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.0.1.tgz#3a596d21fbcefadf36f94e126c5cf24d5697d0b8"
+  integrity sha512-JhTZjpyapA1icCEjIZB4TSSgkGdFgpWZA2Wszg7Cf4JwJwKQmbvuNnJBeR+EYG/Z29OXvR4G//Rbg31BW/Z7Yg==
+  dependencies:
+    bindings "^1.5.0"
+    prebuild-install "^7.1.0"
+
+bindings@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+  integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+  dependencies:
+    file-uri-to-path "1.0.0"
+
+bl@^4.0.3:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+  integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+  dependencies:
+    buffer "^5.5.0"
+    inherits "^2.0.4"
+    readable-stream "^3.4.0"
+
+buffer@^5.5.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+  integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.1.13"
+
+chownr@^1.1.1:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+  integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
+decompress-response@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+  integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+  dependencies:
+    mimic-response "^3.1.0"
+
+deep-extend@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+detect-libc@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
+  integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
+
+end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
+expand-template@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
+  integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+
[email protected]:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+  integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
+fs-constants@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+  integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
[email protected]:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
+  integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==
+
+ieee754@^1.1.13:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+  integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
 import-meta-resolve@^2.1.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.1.tgz#80fdeddbc15d7f3992c37425023ffb4aca7cb583"
   integrity sha512-C6lLL7EJPY44kBvA80gq4uMsVFw5x3oSKfuMl1cuZ2RkI5+UJqQXgn+6hlUew0y4ig7Ypt4CObAAIzU53Nfpuw==
+
+inherits@^2.0.3, inherits@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ini@~1.3.0:
+  version "1.3.8"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+  integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
+mimic-response@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+  integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
+minimist@^1.2.0, minimist@^1.2.3:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+  integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
+  integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
+
+napi-build-utils@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
+  integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
+
+node-abi@^3.3.0:
+  version "3.45.0"
+  resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.45.0.tgz#f568f163a3bfca5aacfce1fbeee1fa2cc98441f5"
+  integrity sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==
+  dependencies:
+    semver "^7.3.5"
+
+once@^1.3.1, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+  dependencies:
+    wrappy "1"
+
+prebuild-install@^7.1.0:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
+  integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==
+  dependencies:
+    detect-libc "^2.0.0"
+    expand-template "^2.0.3"
+    github-from-package "0.0.0"
+    minimist "^1.2.3"
+    mkdirp-classic "^0.5.3"
+    napi-build-utils "^1.0.1"
+    node-abi "^3.3.0"
+    pump "^3.0.0"
+    rc "^1.2.7"
+    simple-get "^4.0.0"
+    tar-fs "^2.0.0"
+    tunnel-agent "^0.6.0"
+
+pump@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+rc@^1.2.7:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+  dependencies:
+    deep-extend "^0.6.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+readable-stream@^3.1.1, readable-stream@^3.4.0:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+  integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.2.0:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+semver@^7.3.5:
+  version "7.5.3"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
+  integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
+  dependencies:
+    lru-cache "^6.0.0"
+
+simple-concat@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
+  integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
+
+simple-get@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543"
+  integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
+  dependencies:
+    decompress-response "^6.0.0"
+    once "^1.3.1"
+    simple-concat "^1.0.0"
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+  integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
+
+tar-fs@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
+  integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
+  dependencies:
+    chownr "^1.1.1"
+    mkdirp-classic "^0.5.2"
+    pump "^3.0.0"
+    tar-stream "^2.1.4"
+
+tar-stream@^2.1.4:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+  integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
+  dependencies:
+    bl "^4.0.3"
+    end-of-stream "^1.4.1"
+    fs-constants "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^3.1.1"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
+  dependencies:
+    safe-buffer "^5.0.1"
+
+util-deprecate@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

+ 2 - 0
src/electron/electron/handler.cljs

@@ -403,6 +403,8 @@
                         :created_at (or (:block/created-at b) (utils/time-ms))
                         :updated_at (or (:block/updated-at b) (utils/time-ms))})
                      blocks)]
+        (prn :BLOCKS blocks)
+        (prn :BLOCKS' blocks')
 
         (db/upsert-blocks! repo (bean/->js blocks'))))))