Skip to content

Commit

Permalink
Use better-sqlite3 (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
vangberg committed Dec 19, 2024
1 parent a4744ae commit f4aaadd
Show file tree
Hide file tree
Showing 12 changed files with 937 additions and 1,022 deletions.
1,551 changes: 741 additions & 810 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "skrift",
"version": "0.23.0",
"version": "0.24.0",
"description": "Networked notes",
"main": "build/main.js",
"scripts": {
Expand All @@ -10,9 +10,7 @@
"start:electron": "npm run build:main && electron ./build/main.js",
"start:react": "webpack serve --config ./webpack.renderer.config.js",
"start": "concurrently \"npm:start:*\"",
"dist:mac": "electron-builder -m",
"dist:linux": "electron-builder -l",
"dist:win": "electron-builder -w",
"dist": "electron-builder -mwl",
"publish": "electron-builder --publish always",
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx",
"test": "jest",
Expand Down Expand Up @@ -74,6 +72,7 @@
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
"@nytimes/react-prosemirror": "^1.0.0",
"@sentry/electron": "^5.8.0",
"@types/better-sqlite3": "^7.6.12",
"@types/jest": "^29.5.14",
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.10.2",
Expand Down Expand Up @@ -115,8 +114,6 @@
"prosemirror-view": "^1.37.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.6",
"style-loader": "^4.0.0",
"tailwindcss": "^3.4.16",
"tiny-invariant": "^1.3.3",
Expand All @@ -127,5 +124,8 @@
"webpack": "^5.37.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.2.0"
},
"dependencies": {
"better-sqlite3": "^11.7.0"
}
}
80 changes: 40 additions & 40 deletions src/skrift-electron/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
IpcDeleteNoteCommand,
IpcSetNoteCommand,
} from "../shared/types";
import { Database } from "sqlite";
import BetterSqlite3 from "better-sqlite3";
import path from "path";
import { TSet } from "../../skrift/tset";
import { Note, NoteLink, NoteWithLinks } from "../../skrift/note";
Expand All @@ -17,13 +17,13 @@ import { NotesFS } from "../../skrift/notes_fs";
const dir = app.isPackaged ? "Skrift" : "Skrift.dev";
const _path = path.join(app.getPath("documents"), dir);

const getDB: () => Promise<Database> = (() => {
let db: Database;
const getDB = (() => {
let db: BetterSqlite3.Database;

return async (): Promise<Database> => {
return (): BetterSqlite3.Database => {
if (!db) {
db = await NotesDB.file(_path);
await NotesDB.initialize(db);
db = NotesDB.file(_path);
NotesDB.initialize(db);
}

return db;
Expand All @@ -35,12 +35,12 @@ const reply = (event: Electron.IpcMainEvent, reply: IpcReply) => {
};

const handleLoadDir = async (event: Electron.IpcMainEvent) => {
await NotesFS.initialize(_path);
const db = await getDB();
NotesFS.initialize(_path);
const db = getDB();

let loaded = 0;
for await (const note of NotesFS.readDir(_path)) {
await NotesDB.save(db, note.id, note.markdown, note.modifiedAt);
NotesDB.save(db, note.id, note.markdown, note.modifiedAt);
loaded += 1;
if (loaded % 100 === 0) {
reply(event, { type: "event/LOADING_DIR", loaded });
Expand All @@ -49,73 +49,73 @@ const handleLoadDir = async (event: Electron.IpcMainEvent) => {

const initialNoteID = "20210108T145053.970Z.md";

if (await NotesDB.exists(db, initialNoteID)) {
if (NotesDB.exists(db, initialNoteID)) {
reply(event, { type: "event/LOADED_DIR", initialNoteID });
} else {
reply(event, { type: "event/LOADED_DIR", initialNoteID: null });
}
};

const handleLoadNote = async (
const handleLoadNote = (
event: Electron.IpcMainEvent,
cmd: IpcLoadNoteCommand
) => {
const { id } = cmd;
const db = await getDB();
const db = getDB();

const note = await NotesDB.getWithLinks(db, id);
const note = NotesDB.getWithLinks(db, id);
reply(event, { type: "event/SET_NOTE", note });
};

const handleDeleteNote = async (
const handleDeleteNote = (
event: Electron.IpcMainEvent,
cmd: IpcDeleteNoteCommand
) => {
const { id } = cmd;
const db = await getDB();
const db = getDB();

const note = await NotesDB.get(db, id);
await NotesDB.delete(db, id);
await NotesFS.delete(_path, id);
const note = NotesDB.get(db, id);
NotesDB.delete(db, id);
NotesFS.delete(_path, id);

note.linkIds.forEach(async (linkId) => {
const note = await NotesDB.getWithLinks(db, linkId);
note.linkIds.forEach((linkId) => {
const note = NotesDB.getWithLinks(db, linkId);
reply(event, { type: "event/SET_NOTE", note });
});

reply(event, { type: "event/DELETED_NOTE", id });
};

const handleAddNote = async (
const handleAddNote = (
event: Electron.IpcMainEvent,
cmd: IpcAddNoteCommand
) => {
const { id, markdown } = cmd;
const db = await getDB();
const db = getDB();

await NotesDB.save(db, id, markdown);
NotesDB.save(db, id, markdown);

await NotesFS.save(_path, id, markdown);
NotesFS.save(_path, id, markdown);

const note = await NotesDB.getWithLinks(db, id);
const note = NotesDB.getWithLinks(db, id);

reply(event, { type: "event/SET_NOTE", note });
};

const handleSetNote = async (
const handleSetNote = (
event: Electron.IpcMainEvent,
cmd: IpcSetNoteCommand
) => {
const { id, markdown } = cmd;
const db = await getDB();
const db = getDB();

const noteBefore = await NotesDB.get(db, id);
const noteBefore = NotesDB.get(db, id);

await NotesDB.save(db, id, markdown);
NotesDB.save(db, id, markdown);

await NotesFS.save(_path, id, markdown);
NotesFS.save(_path, id, markdown);

const noteAfter = await NotesDB.getWithLinks(db, id);
const noteAfter = NotesDB.getWithLinks(db, id);

const linksAffected = [];

Expand All @@ -131,28 +131,28 @@ const handleSetNote = async (

reply(event, { type: "event/SET_NOTE", note: noteAfter });

linksAffected.forEach(async (link) => {
const note = await NotesDB.getWithLinks(db, link);
linksAffected.forEach((link) => {
const note = NotesDB.getWithLinks(db, link);
reply(event, { type: "event/SET_NOTE", note });
});
};

const handleSearch = async (
const handleSearch = (
event: Electron.IpcMainInvokeEvent,
query: string
): Promise<NoteLink[]> => {
const db = await getDB();
): NoteLink[] => {
const db = getDB();

const ids = await NotesDB.search(db, query);
const links = await NotesDB.getNoteLinks(db, ids);
const ids = NotesDB.search(db, query);
const links = NotesDB.getNoteLinks(db, ids);

return links;
};

const handleWriteHTMLToClipboard = async (
const handleWriteHTMLToClipboard = (
event: Electron.IpcMainInvokeEvent,
html: string
): Promise<void> => {
): void => {
clipboard.writeHTML(html);
};

Expand Down
2 changes: 1 addition & 1 deletion src/skrift/note/fromMarkdown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import markdownit from "markdown-it";
import { Token } from "markdown-it";

interface ParsedNote {
export interface ParsedNote {
markdown: string;
title: string;
body: string;
Expand Down
18 changes: 9 additions & 9 deletions src/skrift/notes_db/delete.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { Database } from "sqlite";
import BetterSqlite3 from "better-sqlite3";
import { NotesDB, NoteNotFoundError } from ".";

describe("NotesDB.delete()", () => {
let db: Database;
let db: BetterSqlite3.Database;

beforeAll(async () => {
db = await NotesDB.memory();
await NotesDB.initialize(db);
beforeAll(() => {
db = NotesDB.memory();
NotesDB.initialize(db);
});

it("deletes a note", async () => {
await NotesDB.save(
it("deletes a note", () => {
NotesDB.save(
db,
"a.md",
"# Added note\n\nLinks: [#](b.md), [#](c.md)",
new Date()
);

await NotesDB.delete(db, "a.md");
await expect(NotesDB.get(db, "a.md")).rejects.toThrow(NoteNotFoundError);
NotesDB.delete(db, "a.md");
expect(() => NotesDB.get(db, "a.md")).toThrow(NoteNotFoundError);
});
});
36 changes: 18 additions & 18 deletions src/skrift/notes_db/get.test.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
import { Database } from "sqlite";
import BetterSqlite3 from "better-sqlite3";
import { NotesDB, NoteNotFoundError } from ".";

describe("NotesDB.get()", () => {
let db: Database;
let db: BetterSqlite3.Database;

beforeAll(async () => {
db = await NotesDB.memory();
await NotesDB.initialize(db);
beforeAll(() => {
db = NotesDB.memory();
NotesDB.initialize(db);
});

it("gets a note", async () => {
it("gets a note", () => {
const date = new Date();
await NotesDB.save(
NotesDB.save(
db,
"a.md",
"# Added note\n\nLinks: [#](b.md), [#](c.md)",
date
);

const result = await NotesDB.get(db, "a.md");
const result = NotesDB.get(db, "a.md");
expect(result.id).toEqual("a.md");
expect(result.title).toEqual("Added note");
expect(result.linkIds).toEqual(new Set(["b.md", "c.md"]));
expect(result.modifiedAt).toEqual(date);
});

it("gets a note with links", async () => {
await NotesDB.save(db, "a.md", "Alpha\n\n[#](b.md) [#](c.md)");
await NotesDB.save(db, "b.md", "Beta\n\n[#](a.md)");
await NotesDB.save(db, "c.md", "Charlie");
it("gets a note with links", () => {
NotesDB.save(db, "a.md", "Alpha\n\n[#](b.md) [#](c.md)");
NotesDB.save(db, "b.md", "Beta\n\n[#](a.md)");
NotesDB.save(db, "c.md", "Charlie");

const result = await NotesDB.getWithLinks(db, "a.md");
const result = NotesDB.getWithLinks(db, "a.md");
expect(result.links.sort()).toEqual(
[
{ id: "b.md", title: "Beta" },
Expand All @@ -42,14 +42,14 @@ describe("NotesDB.get()", () => {

it("gets backlinks", async () => {
const date = new Date();
await NotesDB.save(db, "a.md", "[#](b.md)", date);
await NotesDB.save(db, "b.md", "# B", date);
NotesDB.save(db, "a.md", "[#](b.md)", date);
NotesDB.save(db, "b.md", "# B", date);

const result = await NotesDB.get(db, "b.md");
const result = NotesDB.get(db, "b.md");
expect(result.backlinkIds).toEqual(new Set(["a.md"]));
});

it("fails on unknown note", async () => {
await expect(NotesDB.get(db, "unknown")).rejects.toThrow(NoteNotFoundError);
it("fails on unknown note", () => {
expect(() => NotesDB.get(db, "unknown")).toThrow(NoteNotFoundError);
});
});
20 changes: 10 additions & 10 deletions src/skrift/notes_db/getNoteLinks.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Database } from "sqlite";
import { NotesDB, NoteNotFoundError } from ".";
import BetterSqlite3 from "better-sqlite3";
import { NotesDB } from ".";

describe("NotesDB.getNoteLinks()", () => {
let db: Database;
let db: BetterSqlite3.Database;

beforeAll(async () => {
db = await NotesDB.memory();
await NotesDB.initialize(db);
beforeAll(() => {
db = NotesDB.memory();
NotesDB.initialize(db);
});

it("gets note links in specified order", async () => {
it("gets note links in specified order", () => {
const date = new Date();
await NotesDB.save(db, "a.md", "A", date);
await NotesDB.save(db, "b.md", "B", date);
NotesDB.save(db, "a.md", "A", date);
NotesDB.save(db, "b.md", "B", date);

const result = await NotesDB.getNoteLinks(db, ["b.md", "a.md"]);
const result = NotesDB.getNoteLinks(db, ["b.md", "a.md"]);

expect(result.map((r) => r.id)).toEqual(["b.md", "a.md"]);
});
Expand Down
Loading

0 comments on commit f4aaadd

Please sign in to comment.