Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2025-05-15 - Batch Database Inserts to Avoid N+1 Bottlenecks
**Learning:** Found multiple instances where the application iterates over an array (e.g., missing seed records, generated request plans) and executes a separate `await db.insert(...).values(...)` for each item. This N+1 query pattern creates an unnecessary performance bottleneck, especially for bulk operations or initialization tasks.
**Action:** Replaced iterative single-record `insert` statements with `map` operations to construct an array of objects, then passed the entire array into a single `await db.insert(...).values([...])` call. This leverages Drizzle ORM's native batch insert capabilities and significantly reduces database round-trips.
27 changes: 13 additions & 14 deletions src/pages/api/forge-chat-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,19 @@ export const POST: APIRoute = async ({ request, locals }) => {

if (orchestrated.plan && orchestrated.plan.length > 0 && projectId) {
const { Request } = await loadAstroDb();
for (const item of orchestrated.plan) {
await db.insert(Request).values({
projectId,
title: item.title,
content: item.content || `Tâche issue du plan de ${agentId}`,
status: 'pending',
priority: 'medium',
author: agentId,
requestType: 'Correction',
assigneeAgentId: item.assignee || undefined,
createdAt: new Date(),
updatedAt: new Date(),
});
}
const planRequests = orchestrated.plan.map((item) => ({
projectId,
title: item.title,
content: item.content || `Tâche issue du plan de ${agentId}`,
status: 'pending',
priority: 'medium',
author: agentId,
requestType: 'Correction',
assigneeAgentId: item.assignee || undefined,
createdAt: new Date(),
updatedAt: new Date(),
}));
await db.insert(Request).values(planRequests);
}

send('done', {
Expand Down
27 changes: 13 additions & 14 deletions src/pages/api/forge-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,19 @@ export const POST: APIRoute = async ({ request, locals }) => {

if (orchestrated.plan && orchestrated.plan.length > 0 && projectId) {
const { Request } = await loadAstroDb();
for (const item of orchestrated.plan) {
await db.insert(Request).values({
projectId,
title: item.title,
content: item.content || `Tâche issue du plan de ${agentId}`,
status: 'pending',
priority: 'medium',
author: agentId,
requestType: 'Correction',
assigneeAgentId: item.assignee || undefined,
createdAt: new Date(),
updatedAt: new Date(),
});
}
const planRequests = orchestrated.plan.map((item) => ({
projectId,
title: item.title,
content: item.content || `Tâche issue du plan de ${agentId}`,
status: 'pending',
priority: 'medium',
author: agentId,
requestType: 'Correction',
assigneeAgentId: item.assignee || undefined,
createdAt: new Date(),
updatedAt: new Date(),
}));
await db.insert(Request).values(planRequests);
}

return new Response(
Expand Down
12 changes: 7 additions & 5 deletions src/pages/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,19 @@ export const GET: APIRoute = async ({ request }) => {
dbCatalog = await db.select().from(AgentModel);
} else {
const existing = new Set(dbCatalog.map((m) => String(m.id).trim()));
for (const m of FORGE_DEFAULT_AGENT_MODELS) {
if (existing.has(m.id)) continue;
await db.insert(AgentModel).values({
const toInsert = FORGE_DEFAULT_AGENT_MODELS
.filter((m) => !existing.has(m.id))
.map((m) => ({
id: m.id,
label: m.label,
source: 'seed',
enabled: 1,
updatedAt: now,
});
}));
if (toInsert.length > 0) {
await db.insert(AgentModel).values(toInsert);
dbCatalog = await db.select().from(AgentModel);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of re-fetching the entire catalog from the database after the batch insert, you can update the local dbCatalog array directly using the toInsert data. This avoids an unnecessary database round-trip, which aligns with the goal of this PR to improve performance by reducing redundant queries.

Suggested change
dbCatalog = await db.select().from(AgentModel);
dbCatalog.push(...toInsert);

}
dbCatalog = await db.select().from(AgentModel);
}
dbEnabled = dbCatalog
.filter((m) => Number(m.enabled) === 1)
Expand Down