feat: implement fluent api

This commit is contained in:
thecodrr
2020-02-05 20:57:43 +05:00
parent 0678ee4566
commit 90124ca43d
9 changed files with 309 additions and 239 deletions

View File

@@ -12,7 +12,7 @@ beforeEach(async () => {
test("add a notebook", () => test("add a notebook", () =>
notebookTest().then(({ db, id }) => { notebookTest().then(({ db, id }) => {
expect(id).toBeDefined(); expect(id).toBeDefined();
let notebook = db.notebooks.get(id); let notebook = db.notebooks.notebook(id);
expect(notebook).toBeDefined(); expect(notebook).toBeDefined();
expect(notebook.title).toBe(TEST_NOTEBOOK.title); expect(notebook.title).toBe(TEST_NOTEBOOK.title);
})); }));
@@ -34,42 +34,46 @@ test("search all notebooks", () =>
test("pin a notebook", () => test("pin a notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
await db.notebooks.pin(id); let notebook = db.notebooks.notebook(id);
let notebook = db.notebooks.get(id); await notebook.pin();
expect(notebook.pinned).toBe(true); expect(notebook.data.pinned).toBe(true);
})); }));
test("unpin a notebook", () => test("unpin a notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
await db.notebooks.unpin(id); let notebook = db.notebooks.notebook(id);
let notebook = db.notebooks.get(id); await notebook.pin();
expect(notebook.pinned).toBe(false); expect(notebook.data.pinned).toBe(true);
await notebook.pin();
expect(notebook.data.pinned).toBe(false);
})); }));
test("favorite a notebook", () => test("favorite a notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
await db.notebooks.favorite(id); let notebook = db.notebooks.notebook(id);
let notebook = db.notebooks.get(id); await notebook.favorite();
expect(notebook.favorite).toBe(true); expect(notebook.data.favorite).toBe(true);
})); }));
test("unfavorite a notebook", () => test("unfavorite a notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
await db.notebooks.unfavorite(id); let notebook = db.notebooks.notebook(id);
let notebook = db.notebooks.get(id); await notebook.favorite();
expect(notebook.favorite).toBe(false); expect(notebook.data.favorite).toBe(true);
await notebook.favorite();
expect(notebook.data.favorite).toBe(false);
})); }));
test("delete a notebook", () => test("delete a notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
let noteId = await db.notes.add(TEST_NOTE); let noteId = await db.notes.add(TEST_NOTE);
await db.notebooks await db.notebooks
.topics(id) .notebook(id)
.topic("General") .topics.topic("General")
.add(noteId); .add(noteId);
let note = await db.notes.get(noteId); let note = db.notes.note(noteId);
expect(note.notebook.id).toBe(id); expect(note.notebook.id).toBe(id);
await db.notebooks.delete(id); await db.notebooks.delete(id);
note = await db.notes.get(noteId); note = db.notes.note(noteId);
expect(note.notebook.id).toBeUndefined(); expect(note.notebook.id).toBeUndefined();
})); }));

View File

@@ -24,14 +24,14 @@ test("add invalid note", () =>
test("add note", () => test("add note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note).toBeDefined(); expect(note.data).toBeDefined();
expect(note.content.text).toStrictEqual(TEST_NOTE.content.text); expect(note.text).toStrictEqual(TEST_NOTE.content.text);
})); }));
test("get delta of note", () => test("get delta of note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let delta = await db.notes.delta(id); let delta = await db.notes.note(id).delta();
expect(delta).toStrictEqual(TEST_NOTE.content.delta); expect(delta).toStrictEqual(TEST_NOTE.content.delta);
})); }));
@@ -39,14 +39,12 @@ test("delete note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let notebookId = await db.notebooks.add(TEST_NOTEBOOK); let notebookId = await db.notebooks.add(TEST_NOTEBOOK);
let topic = await db.notebooks let topic = await db.notebooks
.topics(notebookId) .notebook(notebookId)
.topic("General") .topics.topic("General")
.add(id); .add(id);
expect(topic.all.findIndex(v => v.id === id)).toBeGreaterThan(-1); expect(topic.all.findIndex(v => v.id === id)).toBeGreaterThan(-1);
await db.notes.delete(id); await db.notes.delete(id);
let note = db.notes.get(id); expect(db.notes.note(id)).toBeUndefined();
expect(await db.notes.delta(id)).toBeUndefined();
expect(note).toBeUndefined();
expect(topic.all.findIndex(v => v.id === id)).toBe(-1); expect(topic.all.findIndex(v => v.id === id)).toBe(-1);
})); }));
@@ -65,7 +63,7 @@ test("search all notes", () =>
test("note without a title should get title from content", () => test("note without a title should get title from content", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.title).toBe("I am a"); expect(note.title).toBe("I am a");
})); }));
@@ -83,11 +81,11 @@ test("update note", () =>
// colors: ["red", "blue"] // colors: ["red", "blue"]
}; };
id = await db.notes.add(noteData); id = await db.notes.add(noteData);
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.title).toBe(noteData.title); expect(note.title).toBe(noteData.title);
expect(note.content.text).toStrictEqual(noteData.content.text); expect(note.text).toStrictEqual(noteData.content.text);
expect(note.pinned).toBe(true); expect(note.data.pinned).toBe(true);
expect(note.favorite).toBe(true); expect(note.data.favorite).toBe(true);
})); }));
test("updating empty note should delete it", () => test("updating empty note should delete it", () =>
@@ -101,24 +99,26 @@ test("updating empty note should delete it", () =>
} }
}); });
expect(id).toBeUndefined(); expect(id).toBeUndefined();
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note).toBeUndefined(); expect(note).toBeUndefined();
})); }));
test("add tag to note", () => test("add tag to note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
await db.notes.tag(id, "hello"); let note = db.notes.note(id);
expect(db.notes.get(id).tags[0]).toBe("hello"); await note.tag("hello");
expect(note.tags[0]).toBe("hello");
expect(db.notes.tags[0].title).toBe("hello"); expect(db.notes.tags[0].title).toBe("hello");
})); }));
test("remove tag from note", () => test("remove tag from note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
await db.notes.tag(id, "hello"); let note = db.notes.note(id);
expect(db.notes.get(id).tags[0]).toBe("hello"); await note.tag("hello");
expect(note.tags[0]).toBe("hello");
expect(db.notes.tags[0].title).toBe("hello"); expect(db.notes.tags[0].title).toBe("hello");
await db.notes.untag(id, "hello"); await note.untag("hello");
expect(db.notes.get(id).tags.length).toBe(0); expect(note.tags.length).toBe(0);
expect(db.notes.tags.length).toBe(0); expect(db.notes.tags.length).toBe(0);
})); }));
@@ -129,7 +129,7 @@ test("note with text longer than 150 characters should have ... in the headline"
delta: [] delta: []
} }
}).then(({ db, id }) => { }).then(({ db, id }) => {
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.headline.includes("...")).toBe(true); expect(note.headline.includes("...")).toBe(true);
})); }));
@@ -192,45 +192,48 @@ test("get grouped notes default (special)", () => groupedTest("", true));
test("pin note", () => test("pin note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
await db.notes.pin(id); let note = db.notes.note(id);
expect(db.notes.get(id).pinned).toBe(true); await note.pin();
expect(note.data.pinned).toBe(true);
})); }));
test("favorite note", () => test("favorite note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
await db.notes.favorite(id); let note = db.notes.note(id);
expect(db.notes.get(id).favorite).toBe(true); await note.favorite();
expect(note.data.favorite).toBe(true);
})); }));
test("lock and unlock note", () => test("lock and unlock note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
expect(await db.notes.lock(id, "password123")).toBe(true); let note = db.notes.note(id);
let note = db.notes.get(id); await note.lock("password123");
expect(note.locked).toBe(true); expect(note.data.locked).toBe(true);
expect(note.content.iv).toBeDefined(); expect(note.data.content.iv).toBeDefined();
note = await db.notes.unlock(id, "password123"); note = await note.unlock("password123");
expect(note.id).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); note = db.notes.note(id);
note = db.notes.get(id); await note.unlock("password123", true);
expect(note.locked).toBe(false); note = db.notes.note(id);
expect(note.data.locked).toBe(false);
})); }));
test("add note to topic", () => test("add note to topic", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let notebookId = await db.notebooks.add({ title: "Hello" }); let notebookId = await db.notebooks.add({ title: "Hello" });
let topics = db.notebooks.topics(notebookId); let topics = db.notebooks.notebook(notebookId).topics;
let topic = await topics.add("Home"); let topic = await topics.add("Home");
await topic.add(id); await topic.add(id);
expect(topic.all.length).toBe(1); expect(topic.all.length).toBe(1);
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.notebook.id).toBe(notebookId); expect(note.notebook.id).toBe(notebookId);
})); }));
test("duplicate note to topic should not be added", () => test("duplicate note to topic should not be added", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let notebookId = await db.notebooks.add({ title: "Hello" }); let notebookId = await db.notebooks.add({ title: "Hello" });
let topics = db.notebooks.topics(notebookId); let topics = db.notebooks.notebook(notebookId).topics;
let topic = await topics.add("Home"); let topic = await topics.add("Home");
await topic.add(id); await topic.add(id);
expect(topic.all.length).toBe(1); expect(topic.all.length).toBe(1);
@@ -239,14 +242,14 @@ test("duplicate note to topic should not be added", () =>
test("move note", () => test("move note", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let notebookId = await db.notebooks.add({ title: "Hello" }); let notebookId = await db.notebooks.add({ title: "Hello" });
let topics = db.notebooks.topics(notebookId); let topics = db.notebooks.notebook(notebookId).topics;
let topic = await topics.add("Home"); let topic = await topics.add("Home");
await topic.add(id); await topic.add(id);
setTimeout(async () => { setTimeout(async () => {
let notebookId2 = await db.notebooks.add({ title: "Hello2" }); let notebookId2 = await db.notebooks.add({ title: "Hello2" });
await db.notebooks.topics(notebookId2).add("Home2"); await db.notebooks.notebook(notebookId2).topics.add("Home2");
await db.notes.move({ id: notebookId2, topic: "Home2" }, id); await db.notes.move({ id: notebookId2, topic: "Home2" }, id);
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.notebook.id).toBe(notebookId2); expect(note.notebook.id).toBe(notebookId2);
}, 1000); }, 1000);
})); }));
@@ -254,10 +257,10 @@ test("move note", () =>
test("moving note to same notebook and topic should do nothing", () => test("moving note to same notebook and topic should do nothing", () =>
noteTest().then(async ({ db, id }) => { noteTest().then(async ({ db, id }) => {
let notebookId = await db.notebooks.add({ title: "Hello" }); let notebookId = await db.notebooks.add({ title: "Hello" });
let topics = db.notebooks.topics(notebookId); let topics = db.notebooks.notebook(notebookId).topics;
let topic = await topics.add("Home"); let topic = await topics.add("Home");
await topic.add(id); await topic.add(id);
await db.notes.move({ id: notebookId, topic: "Home" }, id); await db.notes.move({ id: notebookId, topic: "Home" }, id);
let note = db.notes.get(id); let note = db.notes.note(id);
expect(note.notebook.id).toBe(notebookId); expect(note.notebook.id).toBe(notebookId);
})); }));

View File

@@ -4,7 +4,7 @@ beforeEach(() => StorageInterface.clear());
test("get empty topic", () => test("get empty topic", () =>
notebookTest().then(({ db, id }) => { notebookTest().then(({ db, id }) => {
let topic = db.notebooks.topics(id).topic("General"); let topic = db.notebooks.notebook(id).topics.topic("General");
expect(topic.all.length).toBe(0); expect(topic.all.length).toBe(0);
})); }));
@@ -15,7 +15,7 @@ test("getting invalid topic should throw", () =>
test("add topic to notebook", () => test("add topic to notebook", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
let topics = db.notebooks.topics(id); let topics = db.notebooks.notebook(id).topics;
await topics.add("Home"); await topics.add("Home");
expect(topics.all.length).toBeGreaterThan(1); expect(topics.all.length).toBeGreaterThan(1);
expect(topics.all.findIndex(v => v.title === "Home")).toBeGreaterThan(-1); expect(topics.all.findIndex(v => v.title === "Home")).toBeGreaterThan(-1);
@@ -23,7 +23,7 @@ test("add topic to notebook", () =>
test("duplicate topic to notebook should not be added", () => test("duplicate topic to notebook should not be added", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
let topics = db.notebooks.topics(id); let topics = db.notebooks.notebook(id).topics;
await topics.add("Home"); await topics.add("Home");
let len = topics.all.length; let len = topics.all.length;
await topics.add("Home"); await topics.add("Home");
@@ -32,7 +32,7 @@ test("duplicate topic to notebook should not be added", () =>
test("get topic", () => test("get topic", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
let topics = db.notebooks.topics(id); let topics = db.notebooks.notebook(id).topics;
let topic = await topics.add("Home"); let topic = await topics.add("Home");
let noteId = await db.notes.add({ content: { text: "Hello", delta: [] } }); let noteId = await db.notes.add({ content: { text: "Hello", delta: [] } });
await topic.add(noteId); await topic.add(noteId);
@@ -41,7 +41,7 @@ test("get topic", () =>
test("delete a topic", () => test("delete a topic", () =>
notebookTest().then(async ({ db, id }) => { notebookTest().then(async ({ db, id }) => {
let topics = db.notebooks.topics(id); let topics = db.notebooks.notebook(id).topics;
await topics.add("Home"); await topics.add("Home");
await topics.delete("Home"); await topics.delete("Home");
expect(topics.all.findIndex(v => v.title === "Home")).toBe(-1); expect(topics.all.findIndex(v => v.title === "Home")).toBe(-1);

View File

@@ -1,6 +1,6 @@
import CachedCollection from "../database/cached-collection"; import CachedCollection from "../database/cached-collection";
import fuzzysearch from "fuzzysearch"; import fuzzysearch from "fuzzysearch";
import Topics from "./topics"; import Notebook from "../models/notebook";
var tfun = require("transfun/transfun.js").tfun; var tfun = require("transfun/transfun.js").tfun;
if (!tfun) { if (!tfun) {
tfun = global.tfun; tfun = global.tfun;
@@ -82,16 +82,18 @@ export default class Notebooks {
return this.collection.getAllItems(); return this.collection.getAllItems();
} }
get(id) { notebook(id) {
return this.collection.getItem(id); let notebook = this.collection.getItem(id);
if (!notebook) return;
return new Notebook(this, notebook);
} }
async delete(...ids) { async delete(...ids) {
for (let id of ids) { for (let id of ids) {
let notebook = this.get(id); let notebook = this.notebook(id);
if (!notebook) continue; if (!notebook) continue;
await this.collection.transaction(() => await this.collection.transaction(() =>
this.topics(id).delete(...notebook.topics) notebook.topics.delete(...notebook.topics.all)
); );
await this.collection.removeItem(id); await this.collection.removeItem(id);
} }
@@ -103,23 +105,6 @@ export default class Notebooks {
this.all this.all
); );
} }
topics(id) {
return new Topics(this, this.notes, id);
}
pin(id) {
return this.add({ id, pinned: true });
}
unpin(id) {
return this.add({ id, pinned: false });
}
favorite(id) {
return this.add({ id, favorite: true });
}
unfavorite(id) {
return this.add({ id, favorite: false });
}
} }
function makeTopic(topic, notebookId) { function makeTopic(topic, notebookId) {

View File

@@ -10,6 +10,7 @@ import {
} from "../utils/date"; } from "../utils/date";
import Storage from "../database/storage"; import Storage from "../database/storage";
import Notebooks from "./notebooks"; import Notebooks from "./notebooks";
import Note from "../models/note";
var tfun = require("transfun/transfun.js").tfun; var tfun = require("transfun/transfun.js").tfun;
if (!tfun) { if (!tfun) {
tfun = global.tfun; tfun = global.tfun;
@@ -36,7 +37,7 @@ export default class Notes {
if (!noteArg) return; if (!noteArg) return;
let id = noteArg.id || Date.now().toString() + "_note"; let id = noteArg.id || Date.now().toString() + "_note";
let oldNote = this.get(id); let oldNote = this.collection.getItem(id);
let note = { let note = {
...oldNote, ...oldNote,
...noteArg ...noteArg
@@ -77,12 +78,10 @@ export default class Notes {
return note.id; return note.id;
} }
async delta(id) { note(id) {
return await this.deltaStorage.read(id + "_delta"); let note = this.collection.getItem(id);
} if (!note) return undefined;
return new Note(this, note);
get(id) {
return this.collection.getItem(id);
} }
get all() { get all() {
@@ -162,13 +161,13 @@ export default class Notes {
async delete(...ids) { async delete(...ids) {
for (let id of ids) { for (let id of ids) {
let item = this.get(id); let item = this.note(id);
if (!id) continue; if (!item) continue;
if (item.notebook && item.notebook.id && item.notebook.topic) { if (item.notebook && item.notebook.id && item.notebook.topic) {
await this.collection.transaction(() => await this.collection.transaction(() =>
this.notebooks this.notebooks
.topics(item.notebook.id) .notebook(item.notebook.id)
.topic(item.notebook.topic) .topics.topic(item.notebook.topic)
.delete(id) .delete(id)
); );
} }
@@ -184,83 +183,18 @@ export default class Notes {
return this.tagsCollection.all(); return this.tagsCollection.all();
} }
async tag(id, tag) {
let note = await this.get(id);
if (!note)
throw new Error(`Couldn't add tag. No note found with id: ${id}.`);
note.tags.push(tag);
await this.tagsCollection.add(tag);
await this.collection.addItem(note);
}
async untag(id, tag) {
let note = await this.get(id);
if (!note)
throw new Error(`Couldn't add tag. No note found with id: ${id}.`);
if (note.tags.indexOf(tag) <= -1)
throw new Error("This note is not tagged by the specified tag.");
note.tags.splice(note.tags.indexOf(tag), 1);
await this.tagsCollection.remove(tag);
await this.collection.addItem(note);
}
async move(to, ...noteIds) { async move(to, ...noteIds) {
if (!to) throw new Error("The destination notebook cannot be undefined."); if (!to) throw new Error("The destination notebook cannot be undefined.");
if (!to.id || !to.topic) if (!to.id || !to.topic)
throw new Error( throw new Error(
"The destination notebook must contain notebookId and topic." "The destination notebook must contain notebookId and topic."
); );
let topic = this.notebooks.topics(to.id).topic(to.topic); let topic = this.notebooks.notebook(to.id).topics.topic(to.topic);
if (!topic) throw new Error("No such topic exists."); if (!topic) throw new Error("No such topic exists.");
await topic.transaction(async () => { await topic.transaction(async () => {
await topic.add(...noteIds); await topic.add(...noteIds);
}); });
} }
async favorite(id) {
await this.add({ id, favorite: true });
}
async unfavorite(id) {
await this.add({ id, favorite: false });
}
async pin(id) {
await this.add({ id, pinned: true });
}
async unpin(id) {
await this.add({ id, pinned: false });
}
async lock(id, password) {
let note = await this.get(id);
if (!note)
throw new Error(`Couldn't lock note. No note found with id: ${id}.`);
note.content = await this.collection.indexer.encrypt(
password,
JSON.stringify(note.content)
);
note.locked = true;
await this.collection.addItem(note);
return true;
}
async unlock(id, password, perm = false) {
let note = await this.get(id);
if (!note)
throw new Error(`Couldn't unlock note. No note found with id: ${id}.`);
let decrypted = await this.collection.indexer.decrypt(
password,
note.content
);
if (perm) {
note.locked = false;
note.content = JSON.parse(decrypted);
await this.collection.addItem(note);
}
return { ...note, content: JSON.parse(decrypted) };
}
} }
function isNoteEmpty(note) { function isNoteEmpty(note) {

View File

@@ -1,5 +1,6 @@
import Notebooks from "./notebooks"; import Notebooks from "./notebooks";
import Notes from "./notes"; import Notes from "./notes";
import Topic from "../models/topic";
export default class Topics { export default class Topics {
/** /**
@@ -23,7 +24,7 @@ export default class Topics {
} }
get all() { get all() {
return this.notebooks.get(this.notebookId).topics; return this.notebooks.notebook(this.notebookId).data.topics;
} }
topic(topic) { topic(topic) {
@@ -35,7 +36,9 @@ export default class Topics {
} }
async delete(...topics) { async delete(...topics) {
let notebook = this.notebooks.get(this.notebookId); let notebook = this.notebooks.notebook(this.notebookId);
if (!notebook) return;
notebook = notebook.data;
for (let topic of topics) { for (let topic of topics) {
if (!topic) continue; if (!topic) continue;
let index = notebook.topics.findIndex( let index = notebook.topics.findIndex(
@@ -53,77 +56,3 @@ export default class Topics {
}); });
} }
} }
class Topic {
/**
*
* @param {Topics} topics
* @param {Object} topic
*/
constructor(topics, topic) {
this.topic = topic;
this.topics = topics;
this.transactionOpen = false;
}
transaction(ops, saveAfter = true) {
this.transactionOpen = true;
ops().then(() => {
this.transactionOpen = false;
});
if (!saveAfter) return this;
return this.save();
}
has(noteId) {
return this.topic.notes.findIndex(n => n === noteId) > -1;
}
async add(...noteIds) {
for (let noteId of noteIds) {
let note = this.topics.notes.get(noteId);
if (this.has(noteId) || !note) return this;
this.topic.notes.push(noteId);
if (note.notebook && note.notebook.id && note.notebook.topic) {
if (
note.notebook.id === this.topics.notebookId &&
note.notebook.topic === this.topic.title
)
return this;
await this.topics.notebooks
.topics(note.notebook.id)
.topic(note.notebook.topic)
.delete(note.id);
}
await this.topics.notes.add({
id: noteId,
notebook: { id: this.topics.notebookId, topic: this.topic.title }
});
}
return await this.save();
}
async delete(...noteIds) {
for (let noteId of noteIds) {
if (!this.has(noteId)) return this;
let index = this.topic.notes.findIndex(n => n === noteId);
this.topic.notes.splice(index, 1);
await this.topics.notes.add({
id: noteId,
notebook: {}
});
}
return await this.save();
}
save() {
if (this.transactionOpen) return this;
return this.topics.add(this.topic);
}
get all() {
return this.topic.notes.map(note => this.topics.notes.get(note));
}
}

View File

@@ -0,0 +1,101 @@
import Notes from "../collections/notes";
export default class Note {
/**
*
* @param {Notes} notes
* @param {Object} note
*/
constructor(notes, note) {
this.note = note;
this.notes = notes;
}
get data() {
return this.note;
}
get headline() {
return this.note.headline;
}
get title() {
return this.note.title;
}
get tags() {
return this.note.tags;
}
get id() {
return this.note.id;
}
get notebook() {
return this.note.notebook;
}
get text() {
return this.note.content.text;
}
delta() {
return this.notes.deltaStorage.read(this.note.id + "_delta");
}
async tag(tag) {
if (this.note.tags.indexOf(tag) > -1)
throw new Error("Cannot add a duplicate tag.");
this.note.tags.push(tag);
await this.notes.tagsCollection.add(tag);
await this.notes.collection.addItem(this.note);
}
async untag(tag) {
if (this.note.tags.indexOf(tag) <= -1)
throw new Error("This note is not tagged by the specified tag.");
this.note.tags.splice(this.note.tags.indexOf(tag), 1);
await this.notes.tagsCollection.remove(tag);
await this.notes.collection.addItem(this.note);
}
async save() {
await this.notes.add(this.note);
return this;
}
toggle(prop) {
this.note[prop] = !this.note[prop];
return this.save();
}
favorite() {
return this.toggle("favorite");
}
pin() {
return this.toggle("pinned");
}
async lock(password) {
this.note.content = await this.notes.collection.indexer.encrypt(
password,
JSON.stringify(this.note.content)
);
this.note.locked = true;
return await this.notes.collection.addItem(this.note);
}
async unlock(password, perm = false) {
let decrypted = await this.notes.collection.indexer.decrypt(
password,
this.note.content
);
if (perm) {
this.note.locked = false;
this.note.content = JSON.parse(decrypted);
await this.notes.collection.addItem(this.note);
}
return { ...this.note, content: JSON.parse(decrypted) };
}
}

View File

@@ -0,0 +1,39 @@
import Notebooks from "../collections/notebooks";
import Topics from "../collections/topics";
export default class Notebook {
/**
*
* @param {Notebooks} notebooks
* @param {Object} notebook
*/
constructor(notebooks, notebook) {
this.notebook = notebook;
this.notebooks = notebooks;
}
get title() {
return this.notebook.title;
}
get data() {
return this.notebook;
}
get topics() {
return new Topics(this.notebooks, this.notebooks.notes, this.notebook.id);
}
toggle(prop) {
this.notebook[prop] = !this.notebook[prop];
return this.notebooks.add(this.notebook);
}
pin() {
return this.toggle("pinned");
}
favorite() {
return this.toggle("favorite");
}
}

View File

@@ -0,0 +1,75 @@
import Topics from "../collections/topics";
export default class Topic {
/**
*
* @param {Topics} topics
* @param {Object} topic
*/
constructor(topics, topic) {
this.topic = topic;
this.topics = topics;
this.transactionOpen = false;
}
transaction(ops, saveAfter = true) {
this.transactionOpen = true;
ops().then(() => {
this.transactionOpen = false;
});
if (!saveAfter) return this;
return this.save();
}
has(noteId) {
return this.topic.notes.findIndex(n => n === noteId) > -1;
}
async add(...noteIds) {
for (let noteId of noteIds) {
let note = this.topics.notes.note(noteId);
if (this.has(noteId) || !note) return this;
this.topic.notes.push(noteId);
if (note.notebook && note.notebook.id && note.notebook.topic) {
if (
note.notebook.id === this.topics.notebookId &&
note.notebook.topic === this.topic.title
)
return this;
await this.topics.notebooks
.topics(note.notebook.id)
.topic(note.notebook.topic)
.delete(note.id);
}
await this.topics.notes.add({
id: noteId,
notebook: { id: this.topics.notebookId, topic: this.topic.title }
});
}
return await this.save();
}
async delete(...noteIds) {
for (let noteId of noteIds) {
if (!this.has(noteId)) return this;
let index = this.topic.notes.findIndex(n => n === noteId);
this.topic.notes.splice(index, 1);
await this.topics.notes.add({
id: noteId,
notebook: {}
});
}
return await this.save();
}
save() {
if (this.transactionOpen) return this;
return this.topics.add(this.topic);
}
get all() {
return this.topic.notes.map(note => this.topics.notes.note(note).note);
}
}