-
Notifications
You must be signed in to change notification settings - Fork 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
Pagination & Filters #154
Pagination & Filters #154
Changes from all commits
656e0b6
c70bee1
bc7efec
6726bce
e681ee7
f69cf1e
337dd9d
dd1dc4a
06f344d
0cd5393
d21f343
ee6b36d
300c80b
b1f8c25
6e9112c
177ff75
39bff9b
9475148
6bba980
b233372
0b1a977
90ff6d2
140374c
05ebd11
0ee9488
066d721
c8642bf
0fef38b
10fcad0
e510812
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function roundToInt(value: number) { | ||
return Math.ceil(value); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,12 +2,16 @@ import { Router, Request, Response } from "express"; | |
import { Session } from "neo4j-driver"; | ||
import driver from "../driver/driver"; | ||
import User from "../models/User"; | ||
import removeKeys from "../misc/removeKeys"; | ||
import roundToInt from "../misc/roundToInt"; | ||
import { | ||
OkErrorResponse, | ||
FriendsErrorResponse, | ||
UsersErrorResponse, | ||
} from "../types/userResponse"; | ||
|
||
const filterUser = (user: User) => removeKeys({ ...user }, ["name_embedding"]); | ||
|
||
const friendshipRouter = Router(); | ||
|
||
async function userExists( | ||
|
@@ -31,27 +35,72 @@ async function userExists( | |
|
||
friendshipRouter.get( | ||
"/:userId/friends", | ||
async (req: Request, res: FriendsErrorResponse) => { | ||
async (req: Request, res: Response) => { | ||
try { | ||
const session = driver.session(); | ||
const userId = req.params.userId; | ||
const page: number = parseInt((req.query.page as string) || ""); | ||
const maxUsersOnPage: number = parseInt( | ||
(req.query.maxUsers as string) || "", | ||
); | ||
|
||
const user = await userExists(session, res, userId); | ||
if ("json" in user) { | ||
await session.close(); | ||
return res; | ||
} | ||
|
||
const friendQuery = await session.run( | ||
const searchRequest = await session.run( | ||
`MATCH (u:User {id: $userId})-[:IS_FRIENDS_WITH]->(f:User)-[:IS_FRIENDS_WITH]->(u) | ||
WITH f ORDER BY f.last_name, f.first_name | ||
RETURN DISTINCT f`, | ||
{ userId }, | ||
); | ||
await session.close(); | ||
|
||
const friends = friendQuery.records.map((f) => f.get("f").properties); | ||
return res.json({ status: "ok", friends }); | ||
const allFriends = searchRequest.records.map((f) => { | ||
return filterUser(f.get("f").properties); | ||
}); | ||
|
||
if (!page && !maxUsersOnPage) { | ||
if (allFriends.length === 0) { | ||
return res.status(404).json({ | ||
status: "error", | ||
errors: { users: "No friends found" }, | ||
}); | ||
} | ||
const totalPage: number = roundToInt(allFriends.length / 5); | ||
return res.status(200).json({ | ||
status: "ok", | ||
allUsersSize: allFriends.length, | ||
totalPage: totalPage, | ||
users: allFriends, | ||
}); | ||
} else if (!page || !maxUsersOnPage) { | ||
return res.status(400).json({ | ||
status: "error", | ||
errors: { params: "Missing or incorrect query params" }, | ||
}); | ||
} | ||
|
||
const friends = allFriends.slice( | ||
(page - 1) * maxUsersOnPage, | ||
page * maxUsersOnPage, | ||
); | ||
|
||
if (friends.length === 0) { | ||
return res.status(404).json({ | ||
status: "error", | ||
errors: { users: "No friends found with given queries" }, | ||
}); | ||
} | ||
const totalPage: number = roundToInt(allFriends.length / maxUsersOnPage); | ||
return res.status(200).json({ | ||
status: "ok", | ||
allUsersSize: allFriends.length, | ||
totalPage: totalPage, | ||
users: friends, | ||
}); | ||
} catch (err) { | ||
console.log("Error:", err); | ||
return res.status(404).json({ status: "error", errors: err as object }); | ||
|
@@ -91,11 +140,14 @@ friendshipRouter.get( | |
|
||
friendshipRouter.get( | ||
"/:userId/friend-suggestions", | ||
async (req: Request, res: UsersErrorResponse) => { | ||
async (req: Request, res: Response) => { | ||
try { | ||
const session: Session = driver.session(); | ||
const userId: string = req.params.userId; | ||
|
||
const page: number = parseInt((req.query.page as string) || ""); | ||
const maxUsersOnPage: number = parseInt( | ||
(req.query.maxUsers as string) || "", | ||
); | ||
const user = await userExists(session, res, userId); | ||
if ("json" in user) { | ||
await session.close(); | ||
|
@@ -108,15 +160,58 @@ friendshipRouter.get( | |
RETURN DISTINCT suggested`, | ||
{ userId }, | ||
); | ||
|
||
const allUsers: User[] = friendSuggestionsQuery.records.map((r) => { | ||
return filterUser(r.get("suggested").properties); | ||
}); | ||
|
||
await session.close(); | ||
|
||
const users: User[] = friendSuggestionsQuery.records | ||
.map((record) => record.get("suggested").properties) | ||
.slice(0, 15); | ||
return res.json({ status: "ok", users }); | ||
if (!page && !maxUsersOnPage) { | ||
if (allUsers.length === 0) { | ||
return res.status(404).json({ | ||
status: "not found", | ||
message: "No users found", | ||
}); | ||
} | ||
const totalPage: number = roundToInt(allUsers.length / 5); | ||
return res.status(200).json({ | ||
status: "ok", | ||
allUsersSize: allUsers.length, | ||
totalPage: totalPage, | ||
users: allUsers, | ||
}); | ||
} else if (!page || !maxUsersOnPage) { | ||
return res.status(400).json({ | ||
status: "bad request", | ||
message: "Missing or incorrect query params", | ||
}); | ||
} | ||
|
||
const users = allUsers.slice( | ||
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. This code would still be slow if a million users registered. It's still taking all the users from the database. 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. Hmm I never thought of this solution, thanks! I will try to fix this now :) |
||
(page - 1) * maxUsersOnPage, | ||
page * maxUsersOnPage, | ||
); | ||
|
||
if (users.length === 0) { | ||
return res.status(404).json({ | ||
status: "not found", | ||
message: "No users found with given queries", | ||
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. All other responses have a different format: 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. Yes, you're right 😅 |
||
}); | ||
} | ||
|
||
const totalPage: number = roundToInt(allUsers.length / maxUsersOnPage); | ||
return res.status(200).json({ | ||
status: "ok", | ||
allUsersSize: allUsers.length, | ||
totalPage: totalPage, | ||
users: users, | ||
}); | ||
} catch (err) { | ||
console.log("Error:", err); | ||
return res.status(404).json({ status: "error", errors: err as object }); | ||
console.error("Error:", err); | ||
return res | ||
.status(500) | ||
.json({ status: "error", message: "Internal server error" }); | ||
} | ||
}, | ||
); | ||
|
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.
Response isn't typed so type checking doesn't work
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.
I don't remember if it was already in code or I added, but changing the Response to custom would cause to change it everywhere where friends are mentioned, like friend-suggestions or friends endpoints, each to corresponing endpoint. I didn't come to any other conslusion, so if you have any, let me know! 😊