diff --git a/apps/server/src/becca/becca-interface.ts b/apps/server/src/becca/becca-interface.ts index 005a5cc52..1a8203f43 100644 --- a/apps/server/src/becca/becca-interface.ts +++ b/apps/server/src/becca/becca-interface.ts @@ -13,10 +13,6 @@ import BBlob from "./entities/bblob.js"; import BRecentNote from "./entities/brecent_note.js"; import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js"; -interface AttachmentOpts { - includeContentLength?: boolean; -} - /** * Becca is a backend cache of all notes, branches, and attributes. * There's a similar frontend cache Froca, and share cache Shaca. @@ -167,21 +163,18 @@ export default class Becca { return revision; } - getAttachment(attachmentId: string, opts: AttachmentOpts = {}): BAttachment | null { - opts.includeContentLength = !!opts.includeContentLength; - - const query = opts.includeContentLength - ? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength - FROM attachments - JOIN blobs USING (blobId) - WHERE attachmentId = ? AND isDeleted = 0` - : /*sql*/`SELECT * FROM attachments WHERE attachmentId = ? AND isDeleted = 0`; + getAttachment(attachmentId: string): BAttachment | null { + const query = /*sql*/`\ + SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE attachmentId = ? AND isDeleted = 0`; return sql.getRows(query, [attachmentId]).map((row) => new BAttachment(row))[0]; } - getAttachmentOrThrow(attachmentId: string, opts: AttachmentOpts = {}): BAttachment { - const attachment = this.getAttachment(attachmentId, opts); + getAttachmentOrThrow(attachmentId: string): BAttachment { + const attachment = this.getAttachment(attachmentId); if (!attachment) { throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`); } diff --git a/apps/server/src/becca/entities/bnote.ts b/apps/server/src/becca/entities/bnote.ts index dd05fd974..a2ff4c282 100644 --- a/apps/server/src/becca/entities/bnote.ts +++ b/apps/server/src/becca/entities/bnote.ts @@ -61,10 +61,6 @@ interface ContentOpts { forceFrontendReload?: boolean; } -interface AttachmentOpts { - includeContentLength?: boolean; -} - interface Relationship { parentNoteId: string; childNoteId: string; @@ -1102,31 +1098,23 @@ class BNote extends AbstractBeccaEntity { return sql.getRows("SELECT * FROM revisions WHERE noteId = ? ORDER BY revisions.utcDateCreated ASC", [this.noteId]).map((row) => new BRevision(row)); } - getAttachments(opts: AttachmentOpts = {}) { - opts.includeContentLength = !!opts.includeContentLength; - // from testing, it looks like calculating length does not make a difference in performance even on large-ish DB - // given that we're always fetching attachments only for a specific note, we might just do it always - - const query = opts.includeContentLength - ? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength - FROM attachments - JOIN blobs USING (blobId) - WHERE ownerId = ? AND isDeleted = 0 - ORDER BY position` - : /*sql*/`SELECT * FROM attachments WHERE ownerId = ? AND isDeleted = 0 ORDER BY position`; + getAttachments() { + const query = /*sql*/`\ + SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE ownerId = ? AND isDeleted = 0 + ORDER BY position`; return sql.getRows(query, [this.noteId]).map((row) => new BAttachment(row)); } - getAttachmentById(attachmentId: string, opts: AttachmentOpts = {}) { - opts.includeContentLength = !!opts.includeContentLength; - - const query = opts.includeContentLength - ? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength - FROM attachments - JOIN blobs USING (blobId) - WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0` - : /*sql*/`SELECT * FROM attachments WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`; + getAttachmentById(attachmentId: string) { + const query = /*sql*/`\ + SELECT attachments.*, LENGTH(blobs.content) AS contentLength + FROM attachments + JOIN blobs USING (blobId) + WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`; return sql.getRows(query, [this.noteId, attachmentId]).map((row) => new BAttachment(row))[0]; } diff --git a/apps/server/src/etapi/etapi_utils.ts b/apps/server/src/etapi/etapi_utils.ts index a50434f70..131916257 100644 --- a/apps/server/src/etapi/etapi_utils.ts +++ b/apps/server/src/etapi/etapi_utils.ts @@ -92,7 +92,7 @@ function getAndCheckNote(noteId: string) { } function getAndCheckAttachment(attachmentId: string) { - const attachment = becca.getAttachment(attachmentId, { includeContentLength: true }); + const attachment = becca.getAttachment(attachmentId); if (attachment) { return attachment; diff --git a/apps/server/src/etapi/notes.ts b/apps/server/src/etapi/notes.ts index 2a556dd40..9fae83070 100644 --- a/apps/server/src/etapi/notes.ts +++ b/apps/server/src/etapi/notes.ts @@ -185,7 +185,7 @@ function register(router: Router) { eu.route(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => { const note = eu.getAndCheckNote(req.params.noteId); - const attachments = note.getAttachments({ includeContentLength: true }); + const attachments = note.getAttachments(); res.json(attachments.map((attachment) => mappers.mapAttachmentToPojo(attachment))); }); diff --git a/apps/server/src/routes/api/attachments.ts b/apps/server/src/routes/api/attachments.ts index 0da59b721..b2c877fcb 100644 --- a/apps/server/src/routes/api/attachments.ts +++ b/apps/server/src/routes/api/attachments.ts @@ -14,13 +14,13 @@ function getAttachmentBlob(req: Request) { function getAttachments(req: Request) { const note = becca.getNoteOrThrow(req.params.noteId); - return note.getAttachments({ includeContentLength: true }); + return note.getAttachments(); } function getAttachment(req: Request) { const { attachmentId } = req.params; - return becca.getAttachmentOrThrow(attachmentId, { includeContentLength: true }); + return becca.getAttachmentOrThrow(attachmentId); } function getAllAttachments(req: Request) { @@ -28,7 +28,7 @@ function getAllAttachments(req: Request) { // one particular attachment is requested, but return all note's attachments const attachment = becca.getAttachmentOrThrow(attachmentId); - return attachment.getNote()?.getAttachments({ includeContentLength: true }) || []; + return attachment.getNote()?.getAttachments() || []; } function saveAttachment(req: Request) { diff --git a/apps/server/src/services/notes.ts b/apps/server/src/services/notes.ts index 3de73bc21..ae8b24c0b 100644 --- a/apps/server/src/services/notes.ts +++ b/apps/server/src/services/notes.ts @@ -764,7 +764,7 @@ function updateNoteData(noteId: string, content: string, attachments: Attachment note.setContent(newContent, { forceFrontendReload }); if (attachments?.length > 0) { - const existingAttachmentsByTitle = toMap(note.getAttachments({ includeContentLength: false }), "title"); + const existingAttachmentsByTitle = toMap(note.getAttachments(), "title"); for (const { attachmentId, role, mime, title, position, content } of attachments) { const existingAttachment = existingAttachmentsByTitle.get(title); diff --git a/apps/server/src/services/ws.ts b/apps/server/src/services/ws.ts index 132d71928..9dfcbc019 100644 --- a/apps/server/src/services/ws.ts +++ b/apps/server/src/services/ws.ts @@ -150,7 +150,7 @@ function fillInAdditionalProperties(entityChange: EntityChange) { entityChange.entity = sql.getRow(/*sql*/`SELECT * FROM options WHERE name = ?`, [entityChange.entityId]); } } else if (entityChange.entityName === "attachments") { - entityChange.entity = becca.getAttachment(entityChange.entityId, { includeContentLength: true }); + entityChange.entity = becca.getAttachment(entityChange.entityId); if (!entityChange.entity) { entityChange.entity = sql.getRow(