mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 06:59:31 +01:00
feat: implement notes api
This commit is contained in:
234
packages/core/__tests__/notes.test.js
Normal file
234
packages/core/__tests__/notes.test.js
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
import DB from "../api";
|
||||||
|
import StorageInterface from "../__mocks__/storage.mock";
|
||||||
|
import { getLastWeekTimestamp } from "../utils/date";
|
||||||
|
|
||||||
|
var TEST_NOTE = {
|
||||||
|
content: { delta: "I am a delta", text: "I am a text" }
|
||||||
|
};
|
||||||
|
|
||||||
|
const LONG_TEXT =
|
||||||
|
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
|
||||||
|
|
||||||
|
function databaseTest() {
|
||||||
|
let db = new DB(StorageInterface);
|
||||||
|
return db.init().then(() => db);
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteTest = (note = TEST_NOTE) =>
|
||||||
|
databaseTest().then(async db => {
|
||||||
|
let id = await db.notes.add(note);
|
||||||
|
return { db, id };
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupedTest = (type, special = false) =>
|
||||||
|
noteTest().then(async ({ db }) => {
|
||||||
|
await db.notes.add({ ...TEST_NOTE, title: "HELLO WHAT!" });
|
||||||
|
await db.notes.add({
|
||||||
|
...TEST_NOTE,
|
||||||
|
title: "Some title",
|
||||||
|
dateCreated: getLastWeekTimestamp() - 604800000
|
||||||
|
});
|
||||||
|
await db.notes.add({
|
||||||
|
...TEST_NOTE,
|
||||||
|
title: "Some title and title title",
|
||||||
|
dateCreated: getLastWeekTimestamp() - 604800000 * 2
|
||||||
|
});
|
||||||
|
let grouped = db.notes.group(type, special);
|
||||||
|
if (special) {
|
||||||
|
expect(grouped.items.length).toBeGreaterThan(0);
|
||||||
|
expect(grouped.groups.length).toBeGreaterThan(0);
|
||||||
|
expect(grouped.groupCounts.length).toBeGreaterThan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(grouped.length).toBeGreaterThan(0);
|
||||||
|
expect(grouped[0].data.length).toBeGreaterThan(0);
|
||||||
|
expect(grouped[0].title.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
StorageInterface.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add invalid note", () =>
|
||||||
|
databaseTest().then(async db => {
|
||||||
|
let id = await db.notes.add();
|
||||||
|
expect(id).toBeUndefined();
|
||||||
|
id = await db.notes.add({});
|
||||||
|
expect(id).toBeUndefined();
|
||||||
|
id = await db.notes.add({ hello: "world" });
|
||||||
|
expect(id).toBeUndefined();
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("add note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note).toBeDefined();
|
||||||
|
expect(note.content).toStrictEqual(TEST_NOTE.content);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get all notes", () =>
|
||||||
|
noteTest().then(async ({ db }) => {
|
||||||
|
expect(db.notes.all.length).toBeGreaterThan(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("search all notes", () =>
|
||||||
|
noteTest({
|
||||||
|
content: { delta: "5", text: "5" }
|
||||||
|
}).then(async ({ db }) => {
|
||||||
|
let filtered = db.notes.filter("5");
|
||||||
|
expect(filtered.length).toBeGreaterThan(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("note without a title should get title from content", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note.title).toBe("I am a");
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("update note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
let noteData = {
|
||||||
|
id,
|
||||||
|
title: "I am a new title",
|
||||||
|
content: {
|
||||||
|
text: LONG_TEXT,
|
||||||
|
delta: []
|
||||||
|
},
|
||||||
|
pinned: true,
|
||||||
|
favorite: true
|
||||||
|
// colors: ["red", "blue"]
|
||||||
|
};
|
||||||
|
id = await db.notes.add(noteData);
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note.title).toBe(noteData.title);
|
||||||
|
expect(note.content).toStrictEqual(noteData.content);
|
||||||
|
expect(note.pinned).toBe(true);
|
||||||
|
expect(note.favorite).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("updating empty note should delete it", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
id = await db.notes.add({
|
||||||
|
id,
|
||||||
|
title: "\n\n",
|
||||||
|
content: {
|
||||||
|
text: "",
|
||||||
|
delta: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(id).toBeUndefined();
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note).toBeUndefined();
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("add tag to note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
await db.notes.tag(id, "hello");
|
||||||
|
expect(db.notes.get(id).tags[0]).toBe("hello");
|
||||||
|
expect(db.notes.tags[0].title).toBe("hello");
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("remove tag from note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
await db.notes.tag(id, "hello");
|
||||||
|
expect(db.notes.get(id).tags[0]).toBe("hello");
|
||||||
|
expect(db.notes.tags[0].title).toBe("hello");
|
||||||
|
await db.notes.untag(id, "hello");
|
||||||
|
expect(db.notes.get(id).tags.length).toBe(0);
|
||||||
|
expect(db.notes.tags.length).toBe(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("note with text longer than 150 characters should have ... in the headline", () =>
|
||||||
|
noteTest({
|
||||||
|
content: {
|
||||||
|
text: LONG_TEXT,
|
||||||
|
delta: []
|
||||||
|
}
|
||||||
|
}).then(({ db, id }) => {
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note.headline.includes("...")).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get tags", () =>
|
||||||
|
noteTest({
|
||||||
|
...TEST_NOTE,
|
||||||
|
tags: ["new", "tag", "goes", "here"]
|
||||||
|
}).then(async ({ db }) => {
|
||||||
|
expect(db.notes.tags.length).toBeGreaterThan(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get notes in tag", () =>
|
||||||
|
noteTest({
|
||||||
|
...TEST_NOTE,
|
||||||
|
tags: ["new", "tag", "goes", "here"]
|
||||||
|
}).then(async ({ db }) => {
|
||||||
|
expect(db.notes.tagged("tag")[0].tags).toStrictEqual([
|
||||||
|
"new",
|
||||||
|
"tag",
|
||||||
|
"goes",
|
||||||
|
"here"
|
||||||
|
]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get favorite notes", () =>
|
||||||
|
noteTest({
|
||||||
|
favorite: true,
|
||||||
|
content: { delta: "Hello", text: "Hello" }
|
||||||
|
}).then(({ db }) => {
|
||||||
|
expect(db.notes.favorites.length).toBeGreaterThan(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get pinned notes", () =>
|
||||||
|
noteTest({
|
||||||
|
pinned: true,
|
||||||
|
content: { delta: "Hello", text: "Hello" }
|
||||||
|
}).then(({ db }) => {
|
||||||
|
expect(db.notes.pinned.length).toBeGreaterThan(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("get grouped notes by abc", () => groupedTest("abc"));
|
||||||
|
|
||||||
|
test("get grouped notes by abc (special)", () => groupedTest("abc", true));
|
||||||
|
|
||||||
|
test("get grouped notes by month", () => groupedTest("month"));
|
||||||
|
|
||||||
|
test("get grouped notes by month (special)", () => groupedTest("month", true));
|
||||||
|
|
||||||
|
test("get grouped notes by year", () => groupedTest("year"));
|
||||||
|
|
||||||
|
test("get grouped notes by year (special)", () => groupedTest("year", true));
|
||||||
|
|
||||||
|
test("get grouped notes by weak", () => groupedTest("week"));
|
||||||
|
|
||||||
|
test("get grouped notes by weak (special)", () => groupedTest("week", true));
|
||||||
|
|
||||||
|
test("get grouped notes default", () => groupedTest());
|
||||||
|
|
||||||
|
test("get grouped notes default (special)", () => groupedTest("", true));
|
||||||
|
|
||||||
|
test("pin note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
await db.notes.pin(id);
|
||||||
|
expect(db.notes.get(id).pinned).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("favorite note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
await db.notes.favorite(id);
|
||||||
|
expect(db.notes.get(id).favorite).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
test("lock and unlock note", () =>
|
||||||
|
noteTest().then(async ({ db, id }) => {
|
||||||
|
expect(await db.notes.lock(id, "password123")).toBe(true);
|
||||||
|
let note = db.notes.get(id);
|
||||||
|
expect(note.locked).toBe(true);
|
||||||
|
expect(note.content.iv).toBeDefined();
|
||||||
|
note = await db.notes.unlock(id, "password123");
|
||||||
|
expect(note.dateCreated).toBe(id);
|
||||||
|
expect(note.content.text).toBe(TEST_NOTE.content.text);
|
||||||
|
await db.notes.unlock(id, "password123", true);
|
||||||
|
note = db.notes.get(id);
|
||||||
|
expect(note.locked).toBe(false);
|
||||||
|
}));
|
||||||
12
packages/core/api/index.js
Normal file
12
packages/core/api/index.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Notes from "../collections/notes";
|
||||||
|
|
||||||
|
class DB {
|
||||||
|
constructor(context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
async init() {
|
||||||
|
this.notes = new Notes(this.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DB;
|
||||||
277
packages/core/collections/notes.js
Normal file
277
packages/core/collections/notes.js
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import Collection from "../database/collection";
|
||||||
|
import fuzzysearch from "fuzzysearch";
|
||||||
|
import Tags from "./tags";
|
||||||
|
import { groupBy } from "../utils";
|
||||||
|
import {
|
||||||
|
getWeekGroupFromTimestamp,
|
||||||
|
months,
|
||||||
|
getLastWeekTimestamp
|
||||||
|
} from "../utils/date";
|
||||||
|
var tfun = require("transfun/transfun.js").tfun;
|
||||||
|
if (!tfun) {
|
||||||
|
tfun = global.tfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Notes {
|
||||||
|
constructor(context) {
|
||||||
|
this.collection = new Collection(context, "notes");
|
||||||
|
this.tagsCollection = new Tags(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.collection.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(noteArg) {
|
||||||
|
if (!noteArg) return;
|
||||||
|
|
||||||
|
let id = noteArg.id || Date.now();
|
||||||
|
let oldNote = this.get(id);
|
||||||
|
let note = {
|
||||||
|
...oldNote,
|
||||||
|
...noteArg
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isNoteEmpty(note)) {
|
||||||
|
if (oldNote) await this.delete(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
note = {
|
||||||
|
id,
|
||||||
|
type: "note",
|
||||||
|
title: getNoteTitle(note),
|
||||||
|
content: getNoteContent(note),
|
||||||
|
pinned: !!note.pinned,
|
||||||
|
locked: !!note.locked,
|
||||||
|
notebook: note.notebook || {},
|
||||||
|
colors: note.colors || [],
|
||||||
|
tags: note.tags || [],
|
||||||
|
favorite: !!note.favorite,
|
||||||
|
headline: getNoteHeadline(note),
|
||||||
|
dateEdited: Date.now(),
|
||||||
|
dateCreated: id
|
||||||
|
};
|
||||||
|
|
||||||
|
if (oldNote) {
|
||||||
|
// note.colors = setManipulator.union(oldNote.colors, note.colors);
|
||||||
|
} else {
|
||||||
|
for (let tag of note.tags) {
|
||||||
|
await this.tagsCollection.add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.collection.addItem(note);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(id) {
|
||||||
|
return this.collection.getItem(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get all() {
|
||||||
|
return this.collection.getAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
get pinned() {
|
||||||
|
return tfun.filter(".pinned === true")(this.all);
|
||||||
|
}
|
||||||
|
|
||||||
|
get favorites() {
|
||||||
|
return tfun.filter(".favorite === true")(this.all);
|
||||||
|
}
|
||||||
|
|
||||||
|
tagged(tag) {
|
||||||
|
return tfun.filter(`.tags.includes('${tag}')`)(this.all);
|
||||||
|
}
|
||||||
|
|
||||||
|
colored(color) {
|
||||||
|
return tfun.filter(`.colors.includes('${color}')`)(this.all);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(query) {
|
||||||
|
if (!query) return [];
|
||||||
|
return tfun.filter(v => fuzzysearch(query, v.title + " " + v.content.text))(
|
||||||
|
this.all
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
group(by, special = false) {
|
||||||
|
let notes = !special
|
||||||
|
? tfun.filter(".pinned === false")(this.all)
|
||||||
|
: this.all;
|
||||||
|
switch (by) {
|
||||||
|
case "abc":
|
||||||
|
return groupBy(
|
||||||
|
notes.sort((a, b) => a.title.localeCompare(b.title)),
|
||||||
|
note => note.title[0].toUpperCase(),
|
||||||
|
special
|
||||||
|
);
|
||||||
|
case "month":
|
||||||
|
return groupBy(
|
||||||
|
notes,
|
||||||
|
note => months[new Date(note.dateCreated).getMonth()],
|
||||||
|
special
|
||||||
|
);
|
||||||
|
case "week":
|
||||||
|
return groupBy(
|
||||||
|
notes,
|
||||||
|
note => getWeekGroupFromTimestamp(note.dateCreated),
|
||||||
|
special
|
||||||
|
);
|
||||||
|
case "year":
|
||||||
|
return groupBy(
|
||||||
|
notes,
|
||||||
|
note => new Date(note.dateCreated).getFullYear().toString(),
|
||||||
|
special
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
let timestamps = {
|
||||||
|
recent: getLastWeekTimestamp(7),
|
||||||
|
lastWeek: getLastWeekTimestamp(7) - 604800000 //seven day timestamp value
|
||||||
|
};
|
||||||
|
return groupBy(
|
||||||
|
notes,
|
||||||
|
note =>
|
||||||
|
note.dateCreated >= timestamps.recent
|
||||||
|
? "Recent"
|
||||||
|
: note.dateCreated >= timestamps.lastWeek
|
||||||
|
? "Last week"
|
||||||
|
: "Older",
|
||||||
|
special
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(...ids) {
|
||||||
|
if (!ids || ids.length <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let id of ids) {
|
||||||
|
let item = this.get(id);
|
||||||
|
if (!id) continue;
|
||||||
|
/* TODO if (
|
||||||
|
item.notebook.hasOwnProperty("topic") &&
|
||||||
|
!(await this.deleteNoteFromTopic(
|
||||||
|
item.notebook.id,
|
||||||
|
item.notebook.topic,
|
||||||
|
item.dateCreated
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
for (let tag of item.tags) {
|
||||||
|
await this.tagsCollection.remove(tag);
|
||||||
|
}
|
||||||
|
await this.collection.removeItem(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get tags() {
|
||||||
|
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 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) {
|
||||||
|
return (
|
||||||
|
!note.content ||
|
||||||
|
!note.content.delta ||
|
||||||
|
(!note.locked &&
|
||||||
|
(!note.title || note.title.trim().length <= 0) &&
|
||||||
|
(!note.content.text || note.content.text.trim().length <= 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoteHeadline(note) {
|
||||||
|
if (note.locked) return "";
|
||||||
|
return (
|
||||||
|
note.content.text.substring(0, 150) +
|
||||||
|
(note.content.text.length > 150 ? "..." : "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoteTitle(note) {
|
||||||
|
if (note.title && note.title.length > 0) return note.title.trim();
|
||||||
|
return note.content.text
|
||||||
|
.split(" ")
|
||||||
|
.slice(0, 3)
|
||||||
|
.join(" ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoteContent(note) {
|
||||||
|
if (note.locked) {
|
||||||
|
return note.content;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
text: note.content.text.trim(),
|
||||||
|
delta: note.content.delta
|
||||||
|
};
|
||||||
|
}
|
||||||
34
packages/core/collections/tags.js
Normal file
34
packages/core/collections/tags.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import Collection from "../database/collection";
|
||||||
|
|
||||||
|
export default class Tags {
|
||||||
|
constructor(context) {
|
||||||
|
this.collection = new Collection(context, "tags");
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(id) {
|
||||||
|
if (!id || id.trim().length <= 0) return;
|
||||||
|
let tag = (await this.collection.getItem(id)) || {
|
||||||
|
id,
|
||||||
|
title: id,
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
tag.count++;
|
||||||
|
await this.collection.addItem(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
all() {
|
||||||
|
return this.collection.getAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id) {
|
||||||
|
if (!id || id.trim().length <= 0) return;
|
||||||
|
let tag = this.collection.getItem(id);
|
||||||
|
if (!tag) return;
|
||||||
|
if (tag.count <= 1) {
|
||||||
|
await this.collection.removeItem(id);
|
||||||
|
} else {
|
||||||
|
tag.count--;
|
||||||
|
await this.collection.addItem(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +1,46 @@
|
|||||||
import Indexer from "./indexer";
|
import Indexer from "./indexer";
|
||||||
|
|
||||||
export default class Collection extends Indexer {
|
export default class Collection {
|
||||||
constructor(context, type) {
|
constructor(context, type) {
|
||||||
super(context, type);
|
this.map = new Map();
|
||||||
this.collection = new Map();
|
this.indexer = new Indexer(context, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
async initCollection() {
|
async init() {
|
||||||
await this.initIndexer();
|
await this.indexer.init();
|
||||||
|
for (let id of this.indexer.indices) {
|
||||||
|
this.map.set(id, await this.indexer.read(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async addItem(item) {
|
async addItem(item) {
|
||||||
this.collection.set(item.id, item);
|
let exists = this.map.has(item.id);
|
||||||
await this.write(item.id, item);
|
await this.updateItem(item);
|
||||||
await this.index(item.id);
|
if (!exists) {
|
||||||
|
await this.indexer.index(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateItem(item) {
|
||||||
|
this.map.set(item.id, item);
|
||||||
|
await this.indexer.write(item.id, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeItem(id) {
|
async removeItem(id) {
|
||||||
if (this.collection.delete(id)) {
|
if (this.map.delete(id)) {
|
||||||
this.remove(id);
|
this.indexer.remove(id);
|
||||||
await this.deindex(id);
|
await this.indexer.deindex(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getItem(id) {
|
getItem(id) {
|
||||||
if (this.collection.has(id)) {
|
return this.map.get(id);
|
||||||
return this.collection.get(id);
|
|
||||||
} else {
|
|
||||||
return await this.read(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllItems() {
|
getAllItems() {
|
||||||
let items = [];
|
let items = [];
|
||||||
for (let id of await this.getIndices()) {
|
for (let value of this.map.values()) {
|
||||||
let item = await this.getItem(id);
|
items[items.length] = value;
|
||||||
if (item) {
|
|
||||||
items[items.length] = item;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default class Indexer extends Storage {
|
|||||||
this.indices = [];
|
this.indices = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async initIndexer() {
|
async init() {
|
||||||
this.indices = (await this.read(this.type)) || [];
|
this.indices = (await this.read(this.type)) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user