Files
crumbs-original/src/routes/api/notes/+server.ts
T
Frederic CabassutandClaude Opus 4.6 ef3ba163dd fix: resolve N+1 queries, add indexes, and improve DB operations
- Batch-fetch tags for notes in a single query instead of per-note loops
- Add composite indexes on notes, note_tags, and sync_log tables
- Wrap sync push in a transaction for atomicity
- Replace O(n) cleanExpiredSessions with single DELETE query
- Use SQL WHERE in getChangesSince instead of loading all notes
- Extract shared syncNoteTags utility to eliminate duplication
- Add root +error.svelte boundary matching app theme

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:12:39 +01:00

72 lines
1.9 KiB
TypeScript

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types.js';
import { db } from '$lib/server/db/index.js';
import { notes } from '$lib/server/db/schema.js';
import { eq, and, desc } from 'drizzle-orm';
import { v4 as uuidv4 } from 'uuid';
import { extractTags } from '$lib/utils/tags.js';
import { fetchTagsForNotes, syncNoteTags } from '$lib/server/tags.js';
export const GET: RequestHandler = async ({ url }) => {
const filter = url.searchParams.get('filter') || 'all';
let conditions;
switch (filter) {
case 'archived':
conditions = and(eq(notes.archived, true), eq(notes.trashed, false));
break;
case 'trashed':
conditions = eq(notes.trashed, true);
break;
default:
conditions = and(eq(notes.archived, false), eq(notes.trashed, false));
}
const result = db
.select()
.from(notes)
.where(conditions)
.orderBy(desc(notes.pinned), desc(notes.updatedAt))
.all();
const tagMap = fetchTagsForNotes(result.map((n) => n.id));
const notesWithTags = result.map((note) => ({
...note,
tags: tagMap.get(note.id) ?? []
}));
return json(notesWithTags);
};
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
const now = new Date();
const id = body.id || uuidv4();
const newNote = {
id,
title: body.title || '',
content: body.content || '',
color: body.color || 'default',
pinned: body.pinned || false,
archived: false,
trashed: false,
trashedAt: null,
checklistMode: body.checklistMode || false,
sortOrder: body.sortOrder || 0,
createdAt: now,
updatedAt: now,
version: 1
};
const content = `${newNote.title} ${newNote.content}`;
const extractedTags = extractTags(content);
db.transaction((tx) => {
tx.insert(notes).values(newNote).run();
});
syncNoteTags(id, extractedTags);
return json({ ...newNote, tags: extractedTags }, { status: 201 });
};