trilium/src/public/javascripts/services/tree_cache.js

181 lines
5.2 KiB
JavaScript
Raw Normal View History

import utils from "./utils.js";
import Branch from "../entities/branch.js";
import NoteShort from "../entities/note_short.js";
2019-08-27 02:21:43 +08:00
import ws from "./ws.js";
import server from "./server.js";
/**
* TreeCache keeps a read only cache of note tree structure in frontend's memory.
*/
class TreeCache {
constructor() {
this.init();
}
init() {
/** @type {Object.<string, NoteShort>} */
this.notes = {};
/** @type {Object.<string, Branch>} */
this.branches = {};
}
load(noteRows, branchRows) {
this.init();
this.addResp(noteRows, branchRows);
}
addResp(noteRows, branchRows) {
2019-10-26 15:51:08 +08:00
const branchesByNotes = {};
for (const branchRow of branchRows) {
const branch = new Branch(this, branchRow);
this.addBranch(branch);
2019-10-26 15:51:08 +08:00
branchesByNotes[branch.noteId] = branchesByNotes[branch.noteId] || [];
branchesByNotes[branch.noteId].push(branch);
branchesByNotes[branch.parentNoteId] = branchesByNotes[branch.parentNoteId] || [];
branchesByNotes[branch.parentNoteId].push(branch);
}
2019-10-26 15:51:08 +08:00
for (const noteRow of noteRows) {
const {noteId} = noteRow;
const oldNote = this.notes[noteId];
if (oldNote) {
for (const childNoteId of oldNote.children) {
const childNote = this.notes[childNoteId];
if (childNote) {
childNote.parents = childNote.parents.filter(p => p !== noteId);
const branchId = childNote.parentToBranch[noteId];
if (branchId in this.branches) {
delete this.branches[branchId];
}
delete childNote.parentToBranch[noteId];
}
}
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
for (const parentNoteId of oldNote.parents) {
const parentNote = this.notes[parentNoteId];
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
if (parentNote) {
parentNote.children = parentNote.children.filter(p => p !== noteId);
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
const branchId = parentNote.childToBranch[noteId];
if (branchId in this.branches) {
delete this.branches[branchId];
}
delete parentNote.childToBranch[noteId];
}
}
2019-10-20 18:29:34 +08:00
}
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
const note = new NoteShort(this, noteRow, branchesByNotes[noteId]);
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
this.notes[note.noteId] = note;
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
for (const childNoteId of note.children) {
const childNote = this.notes[childNoteId];
2019-04-14 04:10:16 +08:00
2019-10-26 15:51:08 +08:00
if (childNote) {
childNote.addParent(noteId, note.childToBranch[childNoteId]);
}
}
2019-10-26 15:51:08 +08:00
for (const parentNoteId of note.parents) {
const parentNote = this.notes[parentNoteId];
2019-10-26 15:51:08 +08:00
if (parentNote) {
parentNote.addChild(noteId, note.parentToBranch[parentNoteId]);
}
}
}
}
async reloadNotes(noteIds) {
// first load the data before clearing the cache
const resp = await server.post('tree/load', { noteIds });
this.addResp(resp.notes, resp.branches);
}
2019-04-14 04:10:16 +08:00
/** @return {Promise<NoteShort[]>} */
async getNotes(noteIds, silentNotFoundError = false) {
const missingNoteIds = noteIds.filter(noteId => this.notes[noteId] === undefined);
if (missingNoteIds.length > 0) {
const resp = await server.post('tree/load', { noteIds: missingNoteIds });
this.addResp(resp.notes, resp.branches);
}
return noteIds.map(noteId => {
if (!this.notes[noteId] && !silentNotFoundError) {
2019-08-27 02:21:43 +08:00
ws.logError(`Can't find note "${noteId}"`);
2018-08-06 17:30:37 +08:00
2018-08-12 18:59:38 +08:00
return null;
}
else {
return this.notes[noteId];
}
2018-08-12 18:59:38 +08:00
}).filter(note => note !== null);
}
2019-04-14 04:10:16 +08:00
/** @return {Promise<boolean>} */
async noteExists(noteId) {
const notes = await this.getNotes([noteId], true);
return notes.length === 1;
}
/** @return {Promise<NoteShort>} */
2019-09-08 17:25:57 +08:00
async getNote(noteId, silentNotFoundError = false) {
2018-05-27 04:16:34 +08:00
if (noteId === 'none') {
return null;
}
2019-09-08 17:25:57 +08:00
return (await this.getNotes([noteId], silentNotFoundError))[0];
}
addBranch(branch) {
this.branches[branch.branchId] = branch;
}
async getBranches(branchIds) {
const missingBranchIds = branchIds.filter(branchId => this.branches[branchId] === undefined);
if (missingBranchIds.length > 0) {
const resp = await server.post('tree/load', { branchIds: branchIds });
this.addResp(resp.notes, resp.branches);
}
return branchIds.map(branchId => {
if (!this.branches[branchId]) {
throw new Error(`Can't find branch ${branchId}`);
}
else {
return this.branches[branchId];
}
});
}
/** @return Branch */
async getBranch(branchId) {
return (await this.getBranches([branchId]))[0];
}
}
const treeCache = new TreeCache();
export default treeCache;