Files
notesnook/packages/core/api/database.js

267 lines
6.9 KiB
JavaScript
Raw Normal View History

import Storage from "../helpers/storage";
2019-11-29 21:28:31 +05:00
import fuzzysearch from "fuzzysearch";
import ff from "fast-filter";
import { extractValues } from "../utils";
2019-11-27 21:58:41 +05:00
const KEYS = {
2019-12-04 15:08:01 +05:00
notes: "notes",
notebooks: "notebooks"
2019-11-27 21:58:41 +05:00
};
class Database {
constructor(storage) {
this.storage = new Storage(storage);
this.notes = {};
2019-12-04 15:08:01 +05:00
this.notebooks = {};
2019-12-04 17:16:21 +05:00
// fill data
2019-12-04 17:21:07 +05:00
for (let key of extractValues(KEYS)) {
this.storage.read(key).then(data => (this[key] = data || {}));
2019-12-04 17:16:21 +05:00
}
}
/**
2019-12-04 17:16:21 +05:00
* Get all notes
*/
getNotes() {
return extractValues(this.notes);
}
/**
2019-12-04 17:16:21 +05:00
* Adds or updates a note
* @param {object} note The note to add or update
*/
async addNote(note) {
2019-12-05 15:58:11 +05:00
if (!note || (!note.title && !note.content)) return undefined;
let timestamp = note.dateCreated || Date.now();
//add or update a note into the database
let title =
note.title ||
note.content.text
.split(" ")
.slice(0, 3)
.join(" ");
this.notes[timestamp] = {
title,
content: note.content,
pinned: note.pinned || false,
tags: note.tags || [],
2019-12-05 16:17:55 +05:00
notebooks: note.notebooks || {},
colors: note.colors || [],
favorite: note.favorite || false,
2019-12-01 00:01:09 +05:00
headline: note.content.text.substring(0, 150) + "...",
length: note.content.text.length,
dateEditted: Date.now(),
dateCreated: timestamp
};
2019-11-27 21:58:41 +05:00
await this.storage.write(KEYS.notes, this.notes);
return timestamp;
}
/**
2019-12-04 17:16:21 +05:00
* Deletes one or more notes
* @param {array} notes the notes to be deleted
*/
async deleteNotes(notes) {
2019-12-05 15:58:11 +05:00
await deleteItems.call(this, notes, KEYS.notes);
}
/**
2019-12-04 17:16:21 +05:00
* Gets a note
* @param {string} id the id of the note (must be a timestamp)
*/
getNote(id) {
2019-12-05 15:58:11 +05:00
return getItem.call(this, id, KEYS.notes);
}
2019-11-29 21:28:31 +05:00
/**
2019-12-04 17:16:21 +05:00
* Searches all notes with the given query
2019-11-29 21:28:31 +05:00
* @param {string} query the search query
2019-12-04 17:16:21 +05:00
* @returns An array containing the filtered notes
2019-11-29 21:28:31 +05:00
*/
searchNotes(query) {
if (!query) return [];
2019-11-29 21:28:31 +05:00
return ff(
2019-12-04 17:16:21 +05:00
extractValues(this.notes),
v => fuzzysearch(query, v.title + " " + v.content.text),
2019-11-29 21:28:31 +05:00
this
);
}
2019-12-04 17:16:21 +05:00
/**
* Get all notebooks
* @returns An array containing all the notebooks
*/
getNotebooks() {
2019-12-04 15:08:01 +05:00
return extractValues(this.notebooks);
}
2019-12-04 17:16:21 +05:00
/**
* Add a notebook
* @param {object} notebook The notebook to add
* @returns The ID of the added notebook
*/
2019-12-04 15:08:01 +05:00
async addNotebook(notebook) {
if (!notebook || !notebook.title) return;
const id = notebook.dateCreated || Date.now();
let topics = { General: [] };
if (notebook.topics) {
for (let topic of notebook.topics) {
if (!topic) continue;
topics[topic] = [];
}
2019-12-04 15:08:01 +05:00
}
this.notebooks[id] = {
title: notebook.title,
description: notebook.description,
dateCreated: id,
2019-12-04 15:08:01 +05:00
pinned: notebook.pinned || false,
favorite: notebook.favorite || false,
topics,
totalNotes: 0,
tags: [],
colors: []
};
await this.storage.write(KEYS.notebooks, this.notebooks);
return id;
}
2019-12-04 17:16:21 +05:00
/**
* Add a topic to the notebook
* @param {number} notebookId The ID of notebook
* @param {string} topic The topic to add
*/
addTopicToNotebook(notebookId, topic) {
2019-12-05 15:58:11 +05:00
return notebookTopicFn.call(
this,
2019-12-04 17:16:21 +05:00
notebookId,
topic,
notebook => ((notebook.topics[topic] = []), true)
2019-12-04 17:16:21 +05:00
);
}
/**
* Delete a topic from the notebook
* @param {number} notebookId The ID of the notebook
* @param {string} topic The topic to delete
*/
deleteTopicFromNotebook(notebookId, topic) {
2019-12-05 15:58:11 +05:00
return notebookTopicFn.call(this, notebookId, topic, notebook => {
if (!notebook.topics[topic]) return false;
delete notebook.topics[topic];
return true;
});
2019-12-04 17:16:21 +05:00
}
/**
* Add a note to a topic in a notebook
* @param {number} notebookId The ID of the notebook
* @param {string} topic The topic to add note to
* @param {number} noteId The ID of the note
*/
addNoteToTopic(notebookId, topic, noteId) {
2019-12-05 16:17:55 +05:00
return topicNoteFn.call(this, notebookId, topic, noteId, async notebook => {
notebook.topics[topic][notebook.topics[topic].length] = noteId;
//add notebookId to the note
this.notes[noteId].notebooks[notebookId] = notebook.title;
return true;
2019-12-04 17:16:21 +05:00
});
}
/**
* Delete a note from a topic in a notebook
* @param {number} notebookId The ID of the notebook
* @param {string} topic The topic to delete note from
* @param {number} noteId The ID of the note
*/
deleteNoteFromTopic(notebookId, topic, noteId) {
2019-12-05 16:17:55 +05:00
return topicNoteFn.call(this, notebookId, topic, noteId, async notebook => {
let index = notebook.topics[topic].indexOf(noteId);
if (index <= -1) return false;
notebook.topics[topic].splice(index, 1);
2019-12-05 16:17:55 +05:00
//delete notebook from note
delete this.notes[noteId].notebooks[notebookId];
return true;
2019-12-04 17:16:21 +05:00
});
}
/**
* Get all the notes in a topic
* @param {number} notebookId The ID of the notebook
* @param {string} topic The topic
* @returns An array containing the topic notes
*/
getTopic(notebookId, topic) {
if (!notebookId || !topic || !this.notebooks[notebookId]) return;
let notebook = this.notebooks[notebookId];
if (!notebook.topics[topic]) return;
2019-12-04 17:21:07 +05:00
let nbTopic = notebook.topics[topic];
if (nbTopic.length <= 0) return [];
return nbTopic.map(note => this.getNote(note));
2019-12-04 17:16:21 +05:00
}
/**
* Get a notebook
* @param {number} id The ID of the notebook
* @returns The notebook
*/
getNotebook(id) {
2019-12-05 15:58:11 +05:00
return getItem.call(this, id, KEYS.notebooks);
2019-12-04 17:16:21 +05:00
}
/**
* Delete notebooks
* @param {array} notebooks The notebooks to delete
*/
async deleteNotebooks(notebooks) {
2019-12-05 15:58:11 +05:00
await deleteItems.call(this, notebooks, KEYS.notebooks);
2019-12-04 17:16:21 +05:00
}
2019-12-05 15:58:11 +05:00
}
2019-12-04 17:16:21 +05:00
2019-12-05 15:58:11 +05:00
export default Database;
2019-12-04 17:16:21 +05:00
2019-12-05 15:58:11 +05:00
async function deleteItems(items, key) {
if (!items || items.length <= 0 || !this[key] || this[key].length <= 0)
return; //TODO add test
for (let item of items) {
if (this[key].hasOwnProperty(item.dateCreated)) {
delete this[key][item.dateCreated];
2019-12-04 17:16:21 +05:00
}
}
2019-12-05 15:58:11 +05:00
await this.storage.write(key, this[key]);
}
2019-12-04 17:16:21 +05:00
2019-12-05 15:58:11 +05:00
function notebookTopicFn(notebookId, topic, fn) {
if (!notebookId || !topic || !this.notebooks[notebookId]) return;
let notebook = this.notebooks[notebookId];
if (fn(notebook)) {
this.notes[notebookId] = notebook;
return this.storage.write(KEYS.notebooks, this.notebooks);
2019-12-04 17:16:21 +05:00
}
2019-12-05 15:58:11 +05:00
//TODO add test
return Promise.resolve();
}
2019-12-05 16:17:55 +05:00
function topicNoteFn(notebookId, topic, noteId, fn) {
return notebookTopicFn.call(this, notebookId, topic, async notebook => {
if (
!notebook.topics.hasOwnProperty(topic) ||
!this.notes.hasOwnProperty(noteId)
)
return false;
if (fn(notebook)) {
await this.storage.write(KEYS.notes, this.notes);
return true;
}
return false;
});
}
2019-12-05 15:58:11 +05:00
function getItem(id, key) {
if (this[key].hasOwnProperty(id)) {
return this[key][id];
}
}