server-ts: Fix errors in becca-interface

This commit is contained in:
Elian Doran 2024-02-17 11:24:50 +02:00
parent 2c0063a5cc
commit 26388ad3b6
No known key found for this signature in database
4 changed files with 57 additions and 60 deletions

View File

@ -6,6 +6,15 @@ import BNote = require('./entities/bnote');
import BEtapiToken = require('./entities/betapi_token'); import BEtapiToken = require('./entities/betapi_token');
import BAttribute = require('./entities/battribute'); import BAttribute = require('./entities/battribute');
import BBranch = require('./entities/bbranch'); import BBranch = require('./entities/bbranch');
import BRevision = require('./entities/brevision');
import BAttachment = require('./entities/battachment');
import { AttachmentRow, RevisionRow } from './entities/rows';
import BBlob = require('./entities/bblob');
import BRecentNote = require('./entities/brecent_note');
interface AttachmentOpts {
includeContentLength?: boolean;
}
/** /**
* Becca is a backend cache of all notes, branches, and attributes. * Becca is a backend cache of all notes, branches, and attributes.
@ -23,8 +32,11 @@ class Becca {
options!: Record<string, BOption>; options!: Record<string, BOption>;
etapiTokens!: Record<string, BEtapiToken>; etapiTokens!: Record<string, BEtapiToken>;
allNoteSetCache: NoteSet | null;
constructor() { constructor() {
this.reset(); this.reset();
this.allNoteSetCache = null;
} }
reset() { reset() {
@ -45,8 +57,7 @@ class Becca {
return this.getNote('root'); return this.getNote('root');
} }
/** @returns {BAttribute[]} */ findAttributes(type: string, name: string): BAttribute[] {
findAttributes(type, name) {
name = name.trim().toLowerCase(); name = name.trim().toLowerCase();
if (name.startsWith('#') || name.startsWith('~')) { if (name.startsWith('#') || name.startsWith('~')) {
@ -56,8 +67,7 @@ class Becca {
return this.attributeIndex[`${type}-${name}`] || []; return this.attributeIndex[`${type}-${name}`] || [];
} }
/** @returns {BAttribute[]} */ findAttributesWithPrefix(type: string, name: string): BAttribute[] {
findAttributesWithPrefix(type, name) {
const resArr = []; const resArr = [];
const key = `${type}-${name}`; const key = `${type}-${name}`;
@ -76,18 +86,16 @@ class Becca {
} }
} }
addNote(noteId, note) { addNote(noteId: string, note: BNote) {
this.notes[noteId] = note; this.notes[noteId] = note;
this.dirtyNoteSetCache(); this.dirtyNoteSetCache();
} }
/** @returns {BNote|null} */ getNote(noteId: string): BNote | null {
getNote(noteId) {
return this.notes[noteId]; return this.notes[noteId];
} }
/** @returns {BNote|null} */ getNoteOrThrow(noteId: string): BNote | null {
getNoteOrThrow(noteId) {
const note = this.notes[noteId]; const note = this.notes[noteId];
if (!note) { if (!note) {
throw new NotFoundError(`Note '${noteId}' doesn't exist.`); throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
@ -96,8 +104,7 @@ class Becca {
return note; return note;
} }
/** @returns {BNote[]} */ getNotes(noteIds: string[], ignoreMissing: boolean = false): BNote[] {
getNotes(noteIds, ignoreMissing = false) {
const filteredNotes = []; const filteredNotes = [];
for (const noteId of noteIds) { for (const noteId of noteIds) {
@ -117,13 +124,11 @@ class Becca {
return filteredNotes; return filteredNotes;
} }
/** @returns {BBranch|null} */ getBranch(branchId: string): BBranch | null {
getBranch(branchId) {
return this.branches[branchId]; return this.branches[branchId];
} }
/** @returns {BBranch|null} */ getBranchOrThrow(branchId: string): BBranch | null {
getBranchOrThrow(branchId) {
const branch = this.getBranch(branchId); const branch = this.getBranch(branchId);
if (!branch) { if (!branch) {
throw new NotFoundError(`Branch '${branchId}' was not found in becca.`); throw new NotFoundError(`Branch '${branchId}' was not found in becca.`);
@ -131,13 +136,11 @@ class Becca {
return branch; return branch;
} }
/** @returns {BAttribute|null} */ getAttribute(attributeId: string): BAttribute | null {
getAttribute(attributeId) {
return this.attributes[attributeId]; return this.attributes[attributeId];
} }
/** @returns {BAttribute} */ getAttributeOrThrow(attributeId: string): BAttribute {
getAttributeOrThrow(attributeId) {
const attribute = this.getAttribute(attributeId); const attribute = this.getAttribute(attributeId);
if (!attribute) { if (!attribute) {
throw new NotFoundError(`Attribute '${attributeId}' does not exist.`); throw new NotFoundError(`Attribute '${attributeId}' does not exist.`);
@ -146,21 +149,18 @@ class Becca {
return attribute; return attribute;
} }
/** @returns {BBranch|null} */ getBranchFromChildAndParent(childNoteId: string, parentNoteId: string): BBranch | null {
getBranchFromChildAndParent(childNoteId, parentNoteId) {
return this.childParentToBranch[`${childNoteId}-${parentNoteId}`]; return this.childParentToBranch[`${childNoteId}-${parentNoteId}`];
} }
/** @returns {BRevision|null} */ getRevision(revisionId: string): BRevision | null {
getRevision(revisionId) {
const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]); const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]);
const BRevision = require('./entities/brevision'); // avoiding circular dependency problems const BRevision = require('./entities/brevision'); // avoiding circular dependency problems
return row ? new BRevision(row) : null; return row ? new BRevision(row) : null;
} }
/** @returns {BAttachment|null} */ getAttachment(attachmentId: string, opts: AttachmentOpts = {}): BAttachment | null {
getAttachment(attachmentId, opts = {}) {
opts.includeContentLength = !!opts.includeContentLength; opts.includeContentLength = !!opts.includeContentLength;
const query = opts.includeContentLength const query = opts.includeContentLength
@ -176,8 +176,7 @@ class Becca {
.map(row => new BAttachment(row))[0]; .map(row => new BAttachment(row))[0];
} }
/** @returns {BAttachment} */ getAttachmentOrThrow(attachmentId: string, opts: AttachmentOpts = {}): BAttachment {
getAttachmentOrThrow(attachmentId, opts = {}) {
const attachment = this.getAttachment(attachmentId, opts); const attachment = this.getAttachment(attachmentId, opts);
if (!attachment) { if (!attachment) {
throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`); throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`);
@ -185,38 +184,33 @@ class Becca {
return attachment; return attachment;
} }
/** @returns {BAttachment[]} */ getAttachments(attachmentIds: string[]): BAttachment[] {
getAttachments(attachmentIds) {
const BAttachment = require('./entities/battachment'); // avoiding circular dependency problems const BAttachment = require('./entities/battachment'); // avoiding circular dependency problems
return sql.getManyRows("SELECT * FROM attachments WHERE attachmentId IN (???) AND isDeleted = 0", attachmentIds) return sql.getManyRows<AttachmentRow>("SELECT * FROM attachments WHERE attachmentId IN (???) AND isDeleted = 0", attachmentIds)
.map(row => new BAttachment(row)); .map(row => new BAttachment(row));
} }
/** @returns {BBlob|null} */ getBlob(entity: { blobId: string }): BBlob | null {
getBlob(entity) {
const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [entity.blobId]); const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [entity.blobId]);
const BBlob = require('./entities/bblob'); // avoiding circular dependency problems const BBlob = require('./entities/bblob'); // avoiding circular dependency problems
return row ? new BBlob(row) : null; return row ? new BBlob(row) : null;
} }
/** @returns {BOption|null} */ getOption(name: string): BOption | null {
getOption(name) {
return this.options[name]; return this.options[name];
} }
/** @returns {BEtapiToken[]} */ getEtapiTokens(): BEtapiToken[] {
getEtapiTokens() {
return Object.values(this.etapiTokens); return Object.values(this.etapiTokens);
} }
/** @returns {BEtapiToken|null} */ getEtapiToken(etapiTokenId: string): BEtapiToken | null {
getEtapiToken(etapiTokenId) {
return this.etapiTokens[etapiTokenId]; return this.etapiTokens[etapiTokenId];
} }
/** @returns {AbstractBeccaEntity|null} */ /** @returns {AbstractBeccaEntity|null} */
getEntity(entityName, entityId) { getEntity(entityName: string, entityId: string) {
if (!entityName || !entityId) { if (!entityName || !entityId) {
return null; return null;
} }
@ -238,20 +232,18 @@ class Becca {
throw new Error(`Unknown entity name '${camelCaseEntityName}' (original argument '${entityName}')`); throw new Error(`Unknown entity name '${camelCaseEntityName}' (original argument '${entityName}')`);
} }
return this[camelCaseEntityName][entityId]; return (this as any)[camelCaseEntityName][entityId];
} }
/** @returns {BRecentNote[]} */ getRecentNotesFromQuery(query: string, params = []): BRecentNote[] {
getRecentNotesFromQuery(query, params = []) {
const rows = sql.getRows(query, params); const rows = sql.getRows(query, params);
const BRecentNote = require('./entities/brecent_note'); // avoiding circular dependency problems const BRecentNote = require('./entities/brecent_note'); // avoiding circular dependency problems
return rows.map(row => new BRecentNote(row)); return rows.map(row => new BRecentNote(row));
} }
/** @returns {BRevision[]} */ getRevisionsFromQuery(query: string, params = []): BRevision[] {
getRevisionsFromQuery(query, params = []) { const rows = sql.getRows<RevisionRow>(query, params);
const rows = sql.getRows(query, params);
const BRevision = require('./entities/brevision'); // avoiding circular dependency problems const BRevision = require('./entities/brevision'); // avoiding circular dependency problems
return rows.map(row => new BRevision(row)); return rows.map(row => new BRevision(row));
@ -267,8 +259,8 @@ class Becca {
if (!this.allNoteSetCache) { if (!this.allNoteSetCache) {
const allNotes = []; const allNotes = [];
for (const noteId in becca.notes) { for (const noteId in this.notes) {
const note = becca.notes[noteId]; const note = this.notes[noteId];
// in the process of loading data sometimes we create "skeleton" note instances which are expected to be filled later // in the process of loading data sometimes we create "skeleton" note instances which are expected to be filled later
// in case of inconsistent data this might not work and search will then crash on these // in case of inconsistent data this might not work and search will then crash on these

View File

@ -33,4 +33,4 @@ class BRecentNote extends AbstractBeccaEntity<BRecentNote> {
} }
} }
module.exports = BRecentNote; export = BRecentNote;

View File

@ -1,40 +1,45 @@
"use strict"; "use strict";
import BNote = require("../../becca/entities/bnote");
class NoteSet { class NoteSet {
constructor(notes = []) {
/** @type {BNote[]} */ private notes: BNote[];
private noteIdSet: Set<string>;
private sorted: boolean;
constructor(notes: BNote[] = []) {
this.notes = notes; this.notes = notes;
this.noteIdSet = new Set(notes.map(note => note.noteId)); this.noteIdSet = new Set(notes.map(note => note.noteId));
/** @type {boolean} */
this.sorted = false; this.sorted = false;
} }
add(note) { add(note: BNote) {
if (!this.hasNote(note)) { if (!this.hasNote(note)) {
this.notes.push(note); this.notes.push(note);
this.noteIdSet.add(note.noteId); this.noteIdSet.add(note.noteId);
} }
} }
addAll(notes) { addAll(notes: BNote[]) {
for (const note of notes) { for (const note of notes) {
this.add(note); this.add(note);
} }
} }
hasNote(note) { hasNote(note: BNote) {
return this.hasNoteId(note.noteId); return this.hasNoteId(note.noteId);
} }
hasNoteId(noteId) { hasNoteId(noteId: string) {
return this.noteIdSet.has(noteId); return this.noteIdSet.has(noteId);
} }
mergeIn(anotherNoteSet) { mergeIn(anotherNoteSet: NoteSet) {
this.addAll(anotherNoteSet.notes); this.addAll(anotherNoteSet.notes);
} }
minus(anotherNoteSet) { minus(anotherNoteSet: NoteSet) {
const newNoteSet = new NoteSet(); const newNoteSet = new NoteSet();
for (const note of this.notes) { for (const note of this.notes) {
@ -46,7 +51,7 @@ class NoteSet {
return newNoteSet; return newNoteSet;
} }
intersection(anotherNoteSet) { intersection(anotherNoteSet: NoteSet) {
const newNoteSet = new NoteSet(); const newNoteSet = new NoteSet();
for (const note of this.notes) { for (const note of this.notes) {

View File

@ -110,7 +110,7 @@ function getValue<T>(query: string, params: Params = []): T {
// smaller values can result in better performance due to better usage of statement cache // smaller values can result in better performance due to better usage of statement cache
const PARAM_LIMIT = 100; const PARAM_LIMIT = 100;
function getManyRows<T>(query: string, params: Params): T[] | null { function getManyRows<T>(query: string, params: Params): T[] {
let results: unknown[] = []; let results: unknown[] = [];
while (params.length > 0) { while (params.length > 0) {
@ -136,7 +136,7 @@ function getManyRows<T>(query: string, params: Params): T[] | null {
results = results.concat(subResults); results = results.concat(subResults);
} }
return results as (T[] | null); return (results as (T[] | null) || []);
} }
function getRows<T>(query: string, params: Params = []): T[] { function getRows<T>(query: string, params: Params = []): T[] {