diff --git a/bun.lock b/bun.lock
index 1cc4a83f..1998c206 100644
--- a/bun.lock
+++ b/bun.lock
@@ -430,7 +430,7 @@
"@types/body-parser": ["@types/body-parser@1.19.5", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg=="],
- "@types/bun": ["@types/bun@1.2.4", "", { "dependencies": { "bun-types": "1.2.4" } }, "sha512-QtuV5OMR8/rdKJs213iwXDpfVvnskPXY/S0ZiFbsTjQZycuqPbMW8Gf/XhLfwE5njW8sxI2WjISURXPlHypMFA=="],
+ "@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="],
"@types/caseless": ["@types/caseless@0.12.5", "", {}, "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg=="],
@@ -536,7 +536,7 @@
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
- "bun-types": ["bun-types@1.2.4", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-nDPymR207ZZEoWD4AavvEaa/KZe/qlrbMSchqpQwovPZCKc7pwMoENjEtHgMKaAjJhy+x6vfqSBA1QU3bJgs0Q=="],
+ "bun-types": ["bun-types@1.2.9", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-dk/kOEfQbajENN/D6FyiSgOKEuUi9PWfqKQJEgwKrCMWbjS/S6tEXp178mWvWAcUSYm9ArDlWHZKO3T/4cLXiw=="],
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
diff --git a/common/lib/panic.ts b/common/lib/panic.ts
index 0a7ae204..63afe954 100644
--- a/common/lib/panic.ts
+++ b/common/lib/panic.ts
@@ -1,6 +1,8 @@
// unexpected error
export function panic(reason: string): never {
- throw new Error(reason, {
- cause: "panic",
- });
+ throw new Error(reason);
+ // TODO: 型エラーとなるため一時的にコメントアウト
+ // throw new Error(reason, {
+ // cause: "panic",
+ // });
}
diff --git a/server/prisma/sql/recommend.sql b/server/prisma/sql/recommend.sql
index ad2ad7a4..1720f38b 100644
--- a/server/prisma/sql/recommend.sql
+++ b/server/prisma/sql/recommend.sql
@@ -1,6 +1,33 @@
-- $1 = senderId
SELECT
- *,
+ recv.id,
+ recv.name,
+ recv.gender,
+ recv.grade,
+ recv.faculty,
+ recv.department,
+ recv.intro,
+ recv."guid",
+ recv."pictureUrl",
+ json_agg(DISTINCT jsonb_build_object(
+ 'id', c.id,
+ 'name', c.name,
+ 'teacher', c.teacher,
+ 'slots', (
+ SELECT json_agg(
+ jsonb_build_object(
+ 'courseId', "Slot"."courseId",
+ 'day', "Slot"."day",
+ 'period', "Slot"."period"
+ )
+ ) FROM "Slot" WHERE "Slot"."courseId" = c.id)
+ )
+ ) AS "courses",
+ json_agg(DISTINCT jsonb_build_object(
+ 'id', s.id,
+ 'name', s.name,
+ 'group', s.group
+ )) AS "interestSubjects",
-- 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)
@@ -12,6 +39,13 @@ SELECT
AND EXISTS (SELECT 1 FROM "Interest" i WHERE i."subjectId" = subj.id AND i."userId" = $1)
) AS overlap
FROM "User" recv
+
+INNER JOIN "Enrollment" ON "Enrollment"."userId" = recv.id
+INNER JOIN "Course" c on c.id = "Enrollment"."courseId"
+INNER JOIN "Slot" ON "Slot"."courseId" = c.id
+INNER JOIN "Interest" ON "Interest"."userId" = recv.id
+INNER JOIN "InterestSubject" s ON s.id = "Interest"."subjectId"
+
WHERE recv.id <> $1
AND NOT EXISTS (
@@ -26,5 +60,20 @@ AND NOT EXISTS (
AND status = 'PENDING'
)
+-- 授業の登録も興味分野の登録も 0 件のユーザは除外
+AND (
+ EXISTS (
+ SELECT 1 FROM "Enrollment" e
+ WHERE e."userId" = recv.id
+ )
+ OR
+ EXISTS (
+ SELECT 1 FROM "Interest" i
+ WHERE i."userId" = recv.id
+ )
+)
+
+GROUP BY recv.id
+
ORDER BY overlap DESC
LIMIT $2 OFFSET $3;
diff --git a/server/src/functions/engines/recommendation.ts b/server/src/functions/engines/recommendation.ts
index 64222a0a..bf1f78f6 100644
--- a/server/src/functions/engines/recommendation.ts
+++ b/server/src/functions/engines/recommendation.ts
@@ -1,9 +1,11 @@
import { recommend } from "@prisma/client/sql";
-import type { UserID, UserWithCoursesAndSubjects } from "common/types";
+import type {
+ Course,
+ InterestSubject,
+ UserID,
+ UserWithCoursesAndSubjects,
+} from "common/types";
import { prisma } from "../../database/client";
-import { getCoursesByUserId } from "../../database/courses";
-import * as interest from "../../database/interest";
-import { getUserByID } from "../../database/users";
export async function recommendedTo(
user: UserID,
@@ -15,23 +17,16 @@ export async function recommendedTo(
count: number;
}>
> {
- const result = await prisma.$queryRawTyped(recommend(user, limit, offset));
- return Promise.all(
- result.map(async (res) => {
- const { overlap: count, ...u } = res;
- if (count === null) throw new Error("count is null: something is wrong");
- // TODO: user の情報はここで再度 DB に問い合わせるのではなく、 recommend の sql で取得
- const user = await getUserByID(u.id);
- const courses = getCoursesByUserId(u.id);
- const subjects = interest.of(u.id);
- return {
- count: Number(count),
- u: {
- ...user,
- courses: await courses,
- interestSubjects: await subjects,
- },
- };
- }),
- );
+ const users = await prisma.$queryRawTyped(recommend(user, limit, offset));
+ return users.map((user) => {
+ const { overlap: count, ...u } = user;
+ return {
+ count: Number(count),
+ u: {
+ ...u,
+ interestSubjects: u.interestSubjects as InterestSubject[], // TODO: type
+ courses: u.courses as Course[], // TODO: type
+ },
+ };
+ });
}
diff --git a/web/app/chat/layout.tsx b/web/app/chat/layout.tsx
index fabe653b..31bd4e2b 100644
--- a/web/app/chat/layout.tsx
+++ b/web/app/chat/layout.tsx
@@ -9,7 +9,9 @@ export default function Layout({ children }: { children: React.ReactNode }) {
CourseMate は現在ベータ版です。
+