-
Notifications
You must be signed in to change notification settings - Fork 3.4k
fix(api): add limit/offset pagination to GET workflows #3443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -62,12 +62,18 @@ export async function GET(request: NextRequest) { | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| let workflows | ||||||||||||||||||||||||||||||
| const pageParam = url.searchParams.get('page') | ||||||||||||||||||||||||||||||
| const limitParam = url.searchParams.get('limit') | ||||||||||||||||||||||||||||||
| const page = pageParam ? parseInt(pageParam, 10) : undefined | ||||||||||||||||||||||||||||||
| const limit = limitParam ? parseInt(limitParam, 10) : undefined | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| let workflows | ||||||||||||||||||||||||||||||
| const orderByClause = [asc(workflow.sortOrder), asc(workflow.createdAt), asc(workflow.id)] | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| let baseQuery: any | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Drizzle ORM queries are strongly typed end-to-end. Using A practical alternative is to union the two concrete query types, or extract the shared query-building logic into a typed helper. At minimum, prefer |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (workspaceId) { | ||||||||||||||||||||||||||||||
| workflows = await db | ||||||||||||||||||||||||||||||
| baseQuery = db | ||||||||||||||||||||||||||||||
| .select() | ||||||||||||||||||||||||||||||
| .from(workflow) | ||||||||||||||||||||||||||||||
| .where(eq(workflow.workspaceId, workspaceId)) | ||||||||||||||||||||||||||||||
|
|
@@ -77,17 +83,29 @@ export async function GET(request: NextRequest) { | |||||||||||||||||||||||||||||
| .select({ workspaceId: permissions.entityId }) | ||||||||||||||||||||||||||||||
| .from(permissions) | ||||||||||||||||||||||||||||||
| .where(and(eq(permissions.userId, userId), eq(permissions.entityType, 'workspace'))) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const workspaceIds = workspacePermissionRows.map((row) => row.workspaceId) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (workspaceIds.length === 0) { | ||||||||||||||||||||||||||||||
| return NextResponse.json({ data: [] }, { status: 200 }) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| workflows = await db | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| baseQuery = db | ||||||||||||||||||||||||||||||
| .select() | ||||||||||||||||||||||||||||||
| .from(workflow) | ||||||||||||||||||||||||||||||
| .where(inArray(workflow.workspaceId, workspaceIds)) | ||||||||||||||||||||||||||||||
| .orderBy(...orderByClause) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (limit && !isNaN(limit) && limit > 0) { | ||||||||||||||||||||||||||||||
| baseQuery = baseQuery.limit(limit) | ||||||||||||||||||||||||||||||
| if (page && !isNaN(page) && page > 1) { | ||||||||||||||||||||||||||||||
| baseQuery = baseQuery.offset((page - 1) * limit) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+100
to
+105
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No upper bound on The entire motivation for this PR is to prevent OOM crashes from unbounded queries. However, because there is no cap on the A maximum limit (e.g. 100 or 500) should be enforced before the query is built:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No upper bound on user-supplied
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| workflows = await baseQuery | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return NextResponse.json({ data: workflows }, { status: 200 }) | ||||||||||||||||||||||||||||||
| } catch (error: any) { | ||||||||||||||||||||||||||||||
| const elapsed = Date.now() - startTime | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation for negative / zero page numbers
Negative page numbers silently fall through: e.g.
page=-5passes thepage > 1check as false, so the offset clause is never applied — callers get page-1 results regardless. Consider adding an explicit guard:This ensures that any page value below 1 is clamped to 1 rather than silently returning the first page without surfacing an error to the caller.