perf(desktop): fix N+1 query in getAllGrouped workspace procedure#688
perf(desktop): fix N+1 query in getAllGrouped workspace procedure#688
Conversation
Preload all worktrees once and use already-loaded project data from groupsMap instead of calling getWorkspacePath per workspace, which was causing N additional DB queries (one per workspace). Before: 2 + N queries (where N = number of workspaces) After: 3 queries (constant) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR optimizes worktree path resolution in the Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts (1)
98-103: Consider logging when worktree lookup fails.When a workspace has a
worktreeIdbut it's not found inworktreePathMap, this silently falls back to an empty string. This could mask data inconsistency (orphaned workspace referencing a deleted worktree).Per coding guidelines on error handling, consider logging this case:
🔧 Suggested improvement
let worktreePath = ""; if (workspace.type === "worktree" && workspace.worktreeId) { - worktreePath = worktreePathMap.get(workspace.worktreeId) ?? ""; + const resolvedPath = worktreePathMap.get(workspace.worktreeId); + if (resolvedPath) { + worktreePath = resolvedPath; + } else { + console.warn( + `[workspaces/getAllGrouped] Worktree ${workspace.worktreeId} not found for workspace ${workspace.id}`, + ); + } } else if (workspace.type === "branch") { worktreePath = group.project.mainRepoPath; }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid usinganytype - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness
Files:
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
apps/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Drizzle ORM for all database operations - never use raw SQL
Files:
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome for formatting and linting - run at root level with
bun run lint:fixorbiome check --write
Files:
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
🧬 Code graph analysis (1)
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts (2)
apps/desktop/src/main/lib/local-db/index.ts (1)
localDb(82-82)packages/local-db/src/schema/schema.ts (1)
worktrees(50-72)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build
🔇 Additional comments (3)
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts (3)
10-11: LGTM!The type alias provides good self-documentation for the map's purpose.
39-43: Good optimization - reduces N+1 to constant queries.The preloading approach correctly eliminates the per-workspace query overhead. The map construction is clean and efficient.
Optionally, you could filter worktrees to only those belonging to active projects using a
WHERE INclause onprojectId, but the current approach is simpler and likely sufficient given the expected table size.
192-195: The path resolution logic is already consistent betweengetAllGroupedandgetActive. Both approaches produce identical results:getWorkspacePathreturns themainRepoPathfor branch workspaces and theworktreePathfor worktree workspaces, which matches the inline logic ingetAllGrouped(lines 99-103). The only difference is thatgetAllGroupeduses preloaded data for optimization whilegetActivequeries per-workspace, which is appropriate for fetching a single workspace.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Preload all worktrees once and use already-loaded project data from groupsMap instead of calling getWorkspacePath per workspace, which was causing N additional DB queries (one per workspace). Before: 2 + N queries (where N = number of workspaces) After: 3 queries (constant)
Summary
getAllGroupedgroupsMapfor branch workspace pathsPerformance improvement:
Test plan
bun run typecheck --filter=@superset/desktop🤖 Generated with Claude Code
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.