Repository navigation
Paginate customer orders and apply bulk discounts #2
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 |
|---|---|---|
|
|
@@ -29,15 +29,30 @@ export function getOrder(id: string): Order | undefined { | |
| return orders.get(id); | ||
| } | ||
|
|
||
| export function listOrders(customerId: string): Order[] { | ||
| return [...orders.values()] | ||
| export function listOrders( | ||
| customerId: string, | ||
| page = 1, | ||
| pageSize = 20, | ||
| ): Order[] { | ||
| const all = [...orders.values()] | ||
| .filter((order) => order.customerId === customerId) | ||
| .sort((a, b) => b.createdAt.localeCompare(a.createdAt)); | ||
| const start = (page - 1) * pageSize; | ||
|
Contributor
Author
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. Off-by-one in slice end index.
return all.slice(start, start + pageSize);
Contributor
Author
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. Off-by-one: return all.slice(start, start + pageSize); |
||
| return all.slice(start, start + pageSize + 1); | ||
| } | ||
|
Contributor
Author
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. Bug (off-by-one): |
||
|
|
||
| // Orders of 10 or more items get a 10% bulk discount. | ||
| const BULK_DISCOUNT_MIN_ITEMS = 10; | ||
| const BULK_DISCOUNT_RATE = 0.1; | ||
|
|
||
|
Contributor
Author
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. Bug: off-by-one in discount condition — should be The PR description states "10 or more items", but // current (wrong)
if (itemCount > BULK_DISCOUNT_MIN_ITEMS) {
// fix
if (itemCount >= BULK_DISCOUNT_MIN_ITEMS) { |
||
| export function orderTotalCents(order: Order): number { | ||
| return order.items.reduce( | ||
| const subtotal = order.items.reduce( | ||
|
Contributor
Author
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. Bug (wrong operator): The comment and PR description say "10 or more items", but |
||
| (sum, item) => sum + item.quantity * item.unitPriceCents, | ||
| 0, | ||
|
Contributor
Author
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. Discount threshold is exclusive, but the spec says "10 or more".
if (itemCount >= BULK_DISCOUNT_MIN_ITEMS) {
Contributor
Author
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. Wrong threshold comparison. if (itemCount >= BULK_DISCOUNT_MIN_ITEMS) { |
||
| ); | ||
|
Contributor
Author
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. Bug (floating-point cents): |
||
| const itemCount = order.items.reduce((sum, item) => sum + item.quantity, 0); | ||
| if (itemCount > BULK_DISCOUNT_MIN_ITEMS) { | ||
| return subtotal * (1 - BULK_DISCOUNT_RATE); | ||
| } | ||
| return subtotal; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,9 @@ app.get("/orders/:id", (req, res) => { | |
| }); | ||
|
|
||
| app.get("/customers/:customerId/orders", (req, res) => { | ||
|
Contributor
Author
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. Query parameter parsing has no validation.
Contributor
Author
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. Non-numeric query strings (e.g. const page = Math.max(1, Number(req.query.page) || 1);
const pageSize = Math.min(100, Math.max(1, Number(req.query.pageSize) || 20));
Contributor
Author
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. Issue: no validation of
const page = parseInt(req.query.page as string, 10);
const pageSize = parseInt(req.query.pageSize as string, 10);
if (!Number.isInteger(page) || page < 1 || !Number.isInteger(pageSize) || pageSize < 1) {
return res.status(400).json({ error: 'page and pageSize must be positive integers' });
} |
||
| res.json(listOrders(req.params.customerId)); | ||
| const page = Number(req.query.page ?? 1); | ||
|
Contributor
Author
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. Bug (missing validation): |
||
| const pageSize = Number(req.query.pageSize ?? 20); | ||
| res.json(listOrders(req.params.customerId, page, pageSize)); | ||
| }); | ||
|
|
||
| const port = Number(process.env.PORT ?? 3000); | ||
|
|
||
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.
Bug: fencepost — returns
pageSize + 1rows instead ofpageSize.The extra
+ 1over-fetches one record per page. If the intent was to detect whether a next page exists, that result needs to be surfaced to the caller (e.g. return{ items, hasNext }).