mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 14:39:34 +01:00
feat: seperate delta from note storage, improve performance
This commit is contained in:
@@ -64,7 +64,22 @@ test("add note", () =>
|
|||||||
expect(id).toBeDefined();
|
expect(id).toBeDefined();
|
||||||
let note = db.notes.get(id);
|
let note = db.notes.get(id);
|
||||||
expect(note).toBeDefined();
|
expect(note).toBeDefined();
|
||||||
expect(note.content).toStrictEqual(TEST_NOTE.content);
|
expect(note.content.text).toStrictEqual(TEST_NOTE.content.text);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get delta of note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
let delta = await db.notes.delta(id);
|
||||||
|
expect(delta).toStrictEqual(TEST_NOTE.content.delta);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("delete note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
await db.notes.delete(id);
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note).toBeUndefined();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test("get all notes", () =>
|
test("get all notes", () =>
|
||||||
@@ -102,7 +117,7 @@ test("update note", () =>
|
|||||||
id = await db.notes.add(noteData);
|
id = await db.notes.add(noteData);
|
||||||
let note = db.notes.get(id);
|
let note = db.notes.get(id);
|
||||||
expect(note.title).toBe(noteData.title);
|
expect(note.title).toBe(noteData.title);
|
||||||
expect(note.content).toStrictEqual(noteData.content);
|
expect(note.content.text).toStrictEqual(noteData.content.text);
|
||||||
expect(note.pinned).toBe(true);
|
expect(note.pinned).toBe(true);
|
||||||
expect(note.favorite).toBe(true);
|
expect(note.favorite).toBe(true);
|
||||||
}));
|
}));
|
||||||
@@ -226,7 +241,7 @@ test("lock and unlock note", () =>
|
|||||||
expect(note.locked).toBe(true);
|
expect(note.locked).toBe(true);
|
||||||
expect(note.content.iv).toBeDefined();
|
expect(note.content.iv).toBeDefined();
|
||||||
note = await db.notes.unlock(id, "password123");
|
note = await db.notes.unlock(id, "password123");
|
||||||
expect(note.dateCreated).toBe(id);
|
expect(note.id).toBe(id);
|
||||||
expect(note.content.text).toBe(TEST_NOTE.content.text);
|
expect(note.content.text).toBe(TEST_NOTE.content.text);
|
||||||
await db.notes.unlock(id, "password123", true);
|
await db.notes.unlock(id, "password123", true);
|
||||||
note = db.notes.get(id);
|
note = db.notes.get(id);
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import Collection from "../database/collection";
|
import CachedCollection from "../database/cached-collection";
|
||||||
import fuzzysearch from "fuzzysearch";
|
import fuzzysearch from "fuzzysearch";
|
||||||
import Tags from "./tags";
|
import Tags from "./tags";
|
||||||
import { groupBy } from "../utils";
|
import { groupBy } from "../utils";
|
||||||
|
import sort from "fast-sort";
|
||||||
import {
|
import {
|
||||||
getWeekGroupFromTimestamp,
|
getWeekGroupFromTimestamp,
|
||||||
months,
|
months,
|
||||||
getLastWeekTimestamp
|
getLastWeekTimestamp
|
||||||
} from "../utils/date";
|
} from "../utils/date";
|
||||||
|
import Storage from "../database/storage";
|
||||||
var tfun = require("transfun/transfun.js").tfun;
|
var tfun = require("transfun/transfun.js").tfun;
|
||||||
if (!tfun) {
|
if (!tfun) {
|
||||||
tfun = global.tfun;
|
tfun = global.tfun;
|
||||||
@@ -14,7 +16,8 @@ if (!tfun) {
|
|||||||
|
|
||||||
export default class Notes {
|
export default class Notes {
|
||||||
constructor(context) {
|
constructor(context) {
|
||||||
this.collection = new Collection(context, "notes");
|
this.collection = new CachedCollection(context, "notes");
|
||||||
|
this.deltaStorage = new Storage(context);
|
||||||
this.tagsCollection = new Tags(context);
|
this.tagsCollection = new Tags(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +28,7 @@ export default class Notes {
|
|||||||
async add(noteArg) {
|
async add(noteArg) {
|
||||||
if (!noteArg) return;
|
if (!noteArg) return;
|
||||||
|
|
||||||
let id = noteArg.id || Date.now();
|
let id = noteArg.id || Date.now().toString() + "_note";
|
||||||
let oldNote = this.get(id);
|
let oldNote = this.get(id);
|
||||||
let note = {
|
let note = {
|
||||||
...oldNote,
|
...oldNote,
|
||||||
@@ -37,11 +40,13 @@ export default class Notes {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.deltaStorage.write(id + "_delta", note.content.delta);
|
||||||
|
|
||||||
note = {
|
note = {
|
||||||
id,
|
id,
|
||||||
type: "note",
|
type: "note",
|
||||||
title: getNoteTitle(note),
|
title: getNoteTitle(note),
|
||||||
content: getNoteContent(note),
|
content: getNoteContent(note, id),
|
||||||
pinned: !!note.pinned,
|
pinned: !!note.pinned,
|
||||||
locked: !!note.locked,
|
locked: !!note.locked,
|
||||||
notebook: note.notebook || {},
|
notebook: note.notebook || {},
|
||||||
@@ -50,7 +55,7 @@ export default class Notes {
|
|||||||
favorite: !!note.favorite,
|
favorite: !!note.favorite,
|
||||||
headline: getNoteHeadline(note),
|
headline: getNoteHeadline(note),
|
||||||
dateEdited: Date.now(),
|
dateEdited: Date.now(),
|
||||||
dateCreated: id
|
dateCreated: note.dateCreated || Date.now()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (oldNote) {
|
if (oldNote) {
|
||||||
@@ -62,7 +67,11 @@ export default class Notes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.collection.addItem(note);
|
await this.collection.addItem(note);
|
||||||
return id;
|
return note.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async delta(id) {
|
||||||
|
return await this.deltaStorage.read(id + "_delta");
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id) {
|
get(id) {
|
||||||
@@ -103,7 +112,8 @@ export default class Notes {
|
|||||||
switch (by) {
|
switch (by) {
|
||||||
case "abc":
|
case "abc":
|
||||||
return groupBy(
|
return groupBy(
|
||||||
notes.sort((a, b) => a.title.localeCompare(b.title)),
|
//notes.sort((a, b) => a.title.localeCompare(b.title)),
|
||||||
|
sort(notes).asc(t => t.title),
|
||||||
note => note.title[0].toUpperCase(),
|
note => note.title[0].toUpperCase(),
|
||||||
special
|
special
|
||||||
);
|
);
|
||||||
@@ -266,12 +276,13 @@ function getNoteTitle(note) {
|
|||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteContent(note) {
|
function getNoteContent(note, id) {
|
||||||
if (note.locked) {
|
if (note.locked) {
|
||||||
return note.content;
|
return note.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text: note.content.text.trim(),
|
text: note.content.text.trim(),
|
||||||
delta: note.content.delta
|
delta: id + "_delta"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import Collection from "../database/collection";
|
import CachedCollection from "../database/cached-collection";
|
||||||
|
|
||||||
export default class Tags {
|
export default class Tags {
|
||||||
constructor(context) {
|
constructor(context) {
|
||||||
this.collection = new Collection(context, "tags");
|
this.collection = new CachedCollection(context, "tags");
|
||||||
}
|
}
|
||||||
|
|
||||||
async add(id) {
|
async add(id) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Indexer from "./indexer";
|
import Indexer from "./indexer";
|
||||||
|
|
||||||
export default class Collection {
|
export default class CachedCollection {
|
||||||
constructor(context, type) {
|
constructor(context, type) {
|
||||||
this.map = new Map();
|
this.map = new Map();
|
||||||
this.indexer = new Indexer(context, type);
|
this.indexer = new Indexer(context, type);
|
||||||
@@ -14,6 +14,8 @@ export default class Collection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async addItem(item) {
|
async addItem(item) {
|
||||||
|
if (!item.id) throw new Error("The item must contain the id field.");
|
||||||
|
|
||||||
let exists = this.map.has(item.id);
|
let exists = this.map.has(item.id);
|
||||||
await this.updateItem(item);
|
await this.updateItem(item);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
@@ -22,6 +24,8 @@ export default class Collection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateItem(item) {
|
async updateItem(item) {
|
||||||
|
if (!item.id) throw new Error("The item must contain the id field.");
|
||||||
|
|
||||||
this.map.set(item.id, item);
|
this.map.set(item.id, item);
|
||||||
await this.indexer.write(item.id, item);
|
await this.indexer.write(item.id, item);
|
||||||
}
|
}
|
||||||
@@ -11,18 +11,16 @@ export default class Indexer extends Storage {
|
|||||||
this.indices = (await this.read(this.type)) || [];
|
this.indices = (await this.read(this.type)) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async index(key) {
|
async exists(key) {
|
||||||
if (this.indices.length <= 0) {
|
return this.indices.includes(key);
|
||||||
this.indices = (await this.read(this.type)) || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async index(key) {
|
||||||
this.indices[this.indices.length] = key;
|
this.indices[this.indices.length] = key;
|
||||||
await this.write(this.type, this.indices);
|
await this.write(this.type, this.indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getIndices() {
|
async getIndices() {
|
||||||
if (this.indices.length <= 0) {
|
|
||||||
this.indices = (await this.read(this.type)) || [];
|
|
||||||
}
|
|
||||||
return this.indices;
|
return this.indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import Convert from "../utils/convert";
|
|
||||||
|
|
||||||
export default class Storage {
|
export default class Storage {
|
||||||
constructor(context) {
|
constructor(context) {
|
||||||
this.storage = context;
|
this.storage = context;
|
||||||
}
|
}
|
||||||
async write(key, data) {
|
async write(key, data) {
|
||||||
await this.storage.write(key, Convert.toString(data));
|
await this.storage.write(key, data);
|
||||||
}
|
}
|
||||||
async read(key) {
|
async read(key) {
|
||||||
let data = await this.storage.read(key);
|
let data = await this.storage.read(key);
|
||||||
return Convert.fromString(data);
|
return data;
|
||||||
}
|
}
|
||||||
clear() {
|
clear() {
|
||||||
this.storage.clear();
|
this.storage.clear();
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"fast-sort": "^2.0.1",
|
||||||
"fuzzysearch": "^1.0.3",
|
"fuzzysearch": "^1.0.3",
|
||||||
"transfun": "^1.0.2",
|
"node-fetch": "^2.6.0",
|
||||||
"node-fetch": "^2.6.0"
|
"transfun": "^1.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2171,6 +2171,11 @@ fast-levenshtein@~2.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
|
fast-sort@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-sort/-/fast-sort-2.0.1.tgz#71d932d2de380d0d6ca449fdc5dbdefdc437e84a"
|
||||||
|
integrity sha512-61gSQXW5KavRau+RBlQbpD3q+tUyrHSKiU/wob4RP58s99uIpydII6MaRpA+t6Td6/WhvU0lgL8UoMPKKv4xYg==
|
||||||
|
|
||||||
fb-watchman@^2.0.0:
|
fb-watchman@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
|
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
|
||||||
|
|||||||
Reference in New Issue
Block a user