diff --git a/server/prisma/sql/recommend.sql b/server/prisma/sql/recommend.sql index beaf2c52..ad2ad7a4 100644 --- a/server/prisma/sql/recommend.sql +++ b/server/prisma/sql/recommend.sql @@ -1,10 +1,17 @@ -SELECT recv.id, - (SELECT COUNT(*) FROM "Enrollment" recv_enroll - INNER JOIN "Enrollment" req_enroll - ON recv_enroll."courseId" = req_enroll."courseId" - WHERE recv_enroll."userId" = recv.id - AND req_enroll."userId" = $1) -AS overlap FROM "User" recv +-- $1 = senderId +SELECT + *, + -- course overlap + (SELECT COUNT(1) FROM "Course" course + WHERE EXISTS (SELECT 1 FROM "Enrollment" e WHERE e."courseId" = course.id AND e."userId" = recv.id) + AND EXISTS (SELECT 1 FROM "Enrollment" e WHERE e."courseId" = course.id AND e."userId" = $1) + ) + + -- interest overlap + (SELECT COUNT(1) FROM "InterestSubject" subj + WHERE EXISTS (SELECT 1 FROM "Interest" i WHERE i."subjectId" = subj.id AND i."userId" = recv.id) + AND EXISTS (SELECT 1 FROM "Interest" i WHERE i."subjectId" = subj.id AND i."userId" = $1) + ) AS overlap +FROM "User" recv WHERE recv.id <> $1 AND NOT EXISTS ( @@ -21,13 +28,3 @@ AND NOT EXISTS ( ORDER BY overlap DESC LIMIT $2 OFFSET $3; - --- SELECT recv.id AS recv, COUNT(recv_enroll) AS overlap FROM "User" recv --- LEFT JOIN "Relationship" rel ON (rel."sendingUserId" = recv.id AND rel."receivingUserId" = $1) OR (rel."sendingUserId" = $1 AND rel."sendingUserId" = recv.id) --- LEFT JOIN "Enrollment" recv_enroll ON recv_enroll."userId" = recv.id --- INNER JOIN "Course" course ON recv_enroll."courseId" = course.id --- INNER JOIN "Enrollment" req_enroll ON req_enroll."courseId" = course.id --- WHERE req_enroll."userId" = $1 AND recv.id <> $1 --- AND rel.status != 'MATCHED' --- GROUP BY recv.id --- ORDER BY overlap DESC LIMIT $2 OFFSET $3; diff --git a/server/src/functions/engines/recommendation.test.ts b/server/src/functions/engines/recommendation.test.ts index 5a046854..a92f409d 100644 --- a/server/src/functions/engines/recommendation.test.ts +++ b/server/src/functions/engines/recommendation.test.ts @@ -8,14 +8,14 @@ beforeAll(() => { test("recommendation engine", async () => { const usersFor101 = await recommendedTo(101, 5, 0); - if (!usersFor101.ok) throw new Error(); + if (!usersFor101.ok) throw console.error(usersFor101.error); expect(usersFor101.value.map((entry) => entry.u.id)).toEqual([102, 103]); const usersFor102 = await recommendedTo(102, 5, 0); - if (!usersFor102.ok) throw new Error(); + if (!usersFor102.ok) throw console.error(usersFor102.error); expect(usersFor102.value.map((entry) => entry.u.id)).toEqual([103, 101]); const usersFor103 = await recommendedTo(103, 5, 0); - if (!usersFor103.ok) throw new Error(); + if (!usersFor103.ok) throw console.error(usersFor103.error); expect(usersFor103.value.map((entry) => entry.u.id)).toEqual([102, 101]); }); diff --git a/server/src/functions/engines/recommendation.ts b/server/src/functions/engines/recommendation.ts index cac0bcd4..adfa93e3 100644 --- a/server/src/functions/engines/recommendation.ts +++ b/server/src/functions/engines/recommendation.ts @@ -1,8 +1,7 @@ import { recommend as sql } from "@prisma/client/sql"; import { Err, Ok, type Result } from "common/lib/result"; -import type { UserID, UserWithCoursesAndSubjects } from "common/types"; +import type { User, UserID, UserWithCoursesAndSubjects } from "common/types"; import { prisma } from "../../database/client"; -import { getUserByID } from "../../database/users"; export async function recommendedTo( user: UserID, @@ -11,7 +10,7 @@ export async function recommendedTo( ): Promise< Result< Array<{ - u: UserWithCoursesAndSubjects; + u: User; // UserWithCoursesAndSubjects count: number; }> > @@ -20,17 +19,16 @@ export async function recommendedTo( const result = await prisma.$queryRawTyped(sql(user, limit, offset)); return Promise.all( result.map(async (res) => { - const user = await getUserByID(res.id); - if (!user.ok) throw new Error("not found"); // this shouldn't happen - return { - count: Number.parseInt(res.overlap?.toString() ?? "0"), - u: user.value, - }; + const { overlap: count, ...u } = res; + if (count === null) + throw new Error("count is null: something is wrong"); + return { count: Number(count), u }; }), ) .then((val) => Ok(val)) .catch((err) => Err(err)); } catch (err) { - return Err(err); + console.error("caught error: ", err); + return Err(500); } }