Repository navigation
Optimize getProjects action with pagination and reduced column selection - #116
Conversation
WalkthroughgetProjects was rewritten to accept pagination (page, perPage), normalize and bound inputs, build a filtered where clause, run parallel findMany/count queries, and return { projects: ProjectListItem[]; total }. Call sites and the export helper were updated to call getProjects({ userId, ... }) and consume the new response shape. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant ServerAction as getProjects
participant Database as Prisma
Browser->>ServerAction: call getProjects({ userId, search?, type?, page?, perPage? })
ServerAction->>ServerAction: normalize page/perPage, build where, compute skip/take
par Queries
ServerAction->>Database: findMany(select, where, skip, take)
ServerAction->>Database: count(where)
end
Database-->>ServerAction: projects[], total
ServerAction-->>Browser: Result<{ projects, total }>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/actions/projects/getProjects.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/actions/projects/getProjects.ts (2)
src/lib/result.ts (2)
Result(18-18)success(25-30)src/lib/prisma.ts (1)
prisma(14-18)
🔇 Additional comments (2)
src/actions/projects/getProjects.ts (2)
15-24: LGTM on the where clause construction.The conditional filter logic using spread operators is clean and correct. The case-insensitive search mode is appropriate for user-facing search functionality.
35-35: LGTM on the return statement.Correctly uses the
successhelper and matches the updated return type.
| orderBy: { createdAt: 'desc' } | ||
| }); | ||
| return success(projects); | ||
| export async function getProjects({ userId, search, type, page = 1, perPage = 10 }: GetProjectsParams): Promise<Result<{ projects: Project[]; total: number }>> { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all imports and calls to getProjects to verify breaking change handling
echo "=== Searching for getProjects imports ==="
rg -n --type=ts --type=tsx "import.*getProjects" -A 2
echo ""
echo "=== Searching for getProjects function calls ==="
rg -n --type=ts --type=tsx "getProjects\s*\(" -B 2 -A 5Repository: Authormaton/authormaton
Length of output: 231
🏁 Script executed:
#!/bin/bash
# Find all imports and calls to getProjects - adjusted for environment
echo "=== Searching for getProjects imports ==="
rg -n "import.*getProjects" --type=ts -A 2
echo ""
echo "=== Searching for getProjects function calls ==="
rg -n "getProjects\s*\(" --type=ts -B 2 -A 5
echo ""
echo "=== Broader search for getProjects ==="
rg -n "getProjects" --type=tsRepository: Authormaton/authormaton
Length of output: 3260
🏁 Script executed:
#!/bin/bash
# Examine each caller in detail
echo "=== src/lib/export.ts context ==="
sed -n '1,15p' src/lib/export.ts
echo ""
echo "=== src/app/(general)/page.tsx context ==="
sed -n '1,30p' src/app/\(general\)/page.tsx
echo ""
echo "=== src/components/pages/home/HomePageContainer.tsx context ==="
sed -n '1,30p' src/components/pages/home/HomePageContainer.tsx
echo ""
echo "=== Check getProjects function signature and return handling ==="
sed -n '1,40p' src/actions/projects/getProjects.tsRepository: Authormaton/authormaton
Length of output: 4004
Fix critical parameter passing and return type handling errors in all callers of getProjects.
The function signature requires an object parameter { userId, search?, type?, page?, perPage? }, but callers are passing arguments incorrectly:
src/lib/export.ts:4callsgetProjects()with no arguments (userId is required) and then accessesresult.dataas an array, but the new return type is{ projects: Project[]; total: number }src/app/(general)/page.tsx:19callsgetProjects(userId)but should pass{ userId }object, and incorrectly accessesresult.dataas an array instead of destructuring{ projects }from the objectsrc/components/pages/home/HomePageContainer.tsx:23callsfetchProjects(userId)but should pass{ userId }object, and incorrectly accessesresult.dataas an array
Update all three call sites to pass the correct object parameter and handle the new return structure properly.
🤖 Prompt for AI Agents
In src/actions/projects/getProjects.ts around line 13, the function expects a
single object parameter { userId, search?, type?, page?, perPage? } and returns
Result<{ projects: Project[]; total: number }>, so update all callers: in
src/lib/export.ts (line ~4) change the call from getProjects() to pass a valid
object including userId (e.g., getProjects({ userId })) and handle the return by
destructuring or accessing result.data.projects and result.data.total; in
src/app/(general)/page.tsx (line ~19) change getProjects(userId) to
getProjects({ userId }) and replace uses of result.data as an array with const {
projects, total } = result.data (or use result.data.projects); and in
src/components/pages/home/HomePageContainer.tsx (line ~23) change
fetchProjects(userId) to fetchProjects({ userId }) (or adapt the wrapper to
accept the object) and update code to read projects from result.data.projects
(and total from result.data.total) instead of treating result.data as an array.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/components/pages/home/HomePageContainer.tsx (1)
21-25: Client usage ofgetProjectslooks correct; consider dropping unusedtotal.The switch to
fetchProjects({ userId })and destructuring{ projects: fetchedProjects }aligns with the newgetProjectssignature and payload shape.If you don’t plan to use
totalhere, you can omit it from the destructuring to avoid unused‑variable lint noise:- const result = await fetchProjects({ userId }); - if (result.success) { - const { projects: fetchedProjects, total } = result.data; - setProjects(fetchedProjects); + const result = await fetchProjects({ userId }); + if (result.success) { + const { projects: fetchedProjects } = result.data; + setProjects(fetchedProjects); }src/app/(general)/page.tsx (1)
19-31: NewgetProjectscall/shape wiring is correct; unusedtotalcan be dropped.The adaptation to
getProjects({ userId })and destructuring{ projects: initialProjects }fits the updated Result payload and keeps the data flow intoHomePageContainerintact.Unless you plan to surface pagination metadata on this page, you can skip
totalin the destructuring to keep things cleaner:- const { projects: initialProjects, total } = projectsResult.data; + const { projects: initialProjects } = projectsResult.data;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/actions/projects/getProjects.ts(1 hunks)src/app/(general)/page.tsx(2 hunks)src/components/pages/home/HomePageContainer.tsx(1 hunks)src/lib/export.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/lib/export.ts (1)
src/actions/projects/getProjects.ts (1)
getProjects(13-48)
src/actions/projects/getProjects.ts (2)
src/lib/result.ts (2)
Result(18-18)success(25-30)src/lib/prisma.ts (1)
prisma(14-18)
src/app/(general)/page.tsx (2)
src/lib/async.ts (1)
safeAwait(3-10)src/actions/projects/getProjects.ts (1)
getProjects(13-48)
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/lib/export.ts (1)
3-22: Avoid repeatedconcatin the pagination loop to reduce copying overheadThe pagination logic looks sound, but
allProjects = allProjects.concat(result.data.projects);reallocates and copies the entire array on every page, which becomes O(n²) for large exports. You can keep the same behavior with linear cost by pushing into the existing array:- allProjects = allProjects.concat(result.data.projects); + allProjects.push(...result.data.projects);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/actions/projects/getProjects.ts(1 hunks)src/lib/export.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/actions/projects/getProjects.ts (2)
src/lib/result.ts (2)
Result(18-18)success(25-30)src/lib/prisma.ts (1)
prisma(14-18)
src/lib/export.ts (1)
src/actions/projects/getProjects.ts (2)
ProjectListItem(5-12)getProjects(22-57)
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/actions/projects/getProjects.ts(1 hunks)src/lib/export.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/export.ts (1)
src/actions/projects/getProjects.ts (2)
ProjectListItem(5-12)getProjects(22-57)
🪛 Biome (2.1.2)
src/lib/export.ts
[error] 13-13: unterminated string literal
The closing quote must be on the same line.
(parse)
🔇 Additional comments (3)
src/actions/projects/getProjects.ts (1)
1-57: LGTM! All previous concerns have been properly addressed.The implementation successfully incorporates pagination with type-safe normalization, reduced column selection via
ProjectListItem, and parallel queries. The code handles edge cases (NaN, undefined, invalid ranges) correctly and maintains backward compatibility through the Result wrapper.src/lib/export.ts (2)
19-38: Pagination loop correctly fetches all projects for export.The implementation successfully addresses the previous concern about only exporting the first page. The loop continues until all projects are fetched (
fetchedCount < total), ensuring complete data export.
42-52: CSV generation properly uses escaping and handles empty projects.The CSV generation correctly applies the
escapeCsvValuehelper to both headers and row values, and includes a sensible fallback for empty project lists. The type-safe access viakeyof ProjectListItemis appropriate.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/lib/export.ts (2)
19-38: Pagination loop correctly fetches all projects; consider a small efficiency tweakThe do/while with
fetchedCount < totalsafely fetches all pages (including the 0‑projects case) and restores full‑export behavior. You can avoid repeated array reallocation by pushing in place:- allProjects = allProjects.concat(result.data.projects); + allProjects.push(...result.data.projects);Optionally, you could also only assign
totalfrom the first page, since it should remain constant.
42-48: CSV header/row generation is correct; tighten typing and consider a typed header constantUsing
Object.keys(allProjects[0])and theescapeCsvValuehelper yields well‑formed CSV and keeps headers/data aligned. To catch future schema drift at compile time (esp. the fallback branch), you could make the headers explicitly typed:const DEFAULT_HEADERS: (keyof ProjectListItem)[] = ['id', 'title', 'createdAt', 'updatedAt', 'type', 'userId']; const headers: (keyof ProjectListItem)[] = allProjects.length > 0 ? (Object.keys(allProjects[0]) as (keyof ProjectListItem)[]) : DEFAULT_HEADERS;and then drop the casts at the usage sites.
Also applies to: 52-52
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/lib/export.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/lib/export.ts (1)
src/actions/projects/getProjects.ts (2)
ProjectListItem(5-12)getProjects(22-57)
🔇 Additional comments (1)
src/lib/export.ts (1)
3-17: CSV escaping helper correctly handles dates, quotes, and CSV/Excel injection vectorsThis implementation covers the key edge cases (Date normalization, quote escaping, and guarding against
= + - @prefixes) and is a substantial improvement over the previous naive join approach.
Overview: This PR optimizes the
getProjectsaction by implementing pagination defaults and minimizing selected columns to improve performance and reduce database load.Changes
take,skip) to thegetProjectsfunction insrc/actions/projects/getProjects.ts.Summary by CodeRabbit
New Features
Improvements
Compatibility
✏️ Tip: You can customize this high-level summary in your review settings.