Skip to content

Commit a3a8e5c

Browse files
authored
興味のある分野 (server のみ) (#488)
<!--変更したい場合は、`/.github/pull_request_template.md` を修正して下さい。--> # PRの概要 <!-- 変更の目的 もしくは 関連する Issue 番号 --> <!-- 以下のように書くと Issue にリンクでき、マージ時に自動で Issue を閉じられる--> <!-- closes #1 --> ## 具体的な変更内容 <!-- ビューの変更がある場合はスクショによる比較などがあるとわかりやすい --> ## 影響範囲 <!-- この関数を変更したのでこの機能にも影響がある、など --> ## 動作要件 <!-- 動作に必要な 環境変数 / 依存関係 / DBの更新 など --> ## 補足 <!-- レビューをする際に見てほしい点、ローカル環境で試す際の注意点、など --> ## レビューリクエストを出す前にチェック! - [x] 改めてセルフレビューしたか - [x] 手動での動作検証を行ったか - [x] server の機能追加ならば、テストを書いたか - 理由: 書いた | server の機能追加ではない - [x] 間違った使い方が存在するならば、それのドキュメントをコメントで書いたか - 理由: 書いた | 間違った使い方は存在しない - [x] わかりやすいPRになっているか <!-- レビューリクエスト後は、Slackでもメンションしてお願いすることを推奨します。 -->
1 parent d21df4d commit a3a8e5c

File tree

12 files changed

+380
-245
lines changed

12 files changed

+380
-245
lines changed

common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type {
66
IDToken,
77
Gender,
88
RelationshipStatus,
9+
InterestSubject,
910
User,
1011
InitUser,
1112
UpdateUser,

common/zod/schemas.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export const IntroLongSchema = z
3232
// .min(2, { message: "自己紹介文は2文字以上です" })
3333
.max(225, { message: "自己紹介文は225文字以下です" });
3434

35+
export const InterestSubjectSchema = z.object({
36+
id: z.number(),
37+
name: z.string(),
38+
group: z.string(),
39+
});
40+
3541
export const UserSchema = z.object({
3642
id: UserIDSchema,
3743
guid: GUIDSchema,

common/zod/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
InitRoomSchema,
1515
InitSharedRoomSchema,
1616
InitUserSchema,
17+
InterestSubjectSchema,
1718
IntroLongSchema,
1819
IntroShortSchema,
1920
MessageIDSchema,
@@ -45,6 +46,7 @@ export type Name = z.infer<typeof NameSchema>;
4546
export type PictureUrl = z.infer<typeof PictureUrlSchema>;
4647
export type Gender = z.infer<typeof GenderSchema>;
4748
export type RelationshipStatus = z.infer<typeof RelationshipStatusSchema>;
49+
export type InterestSubject = z.infer<typeof InterestSubjectSchema>;
4850
export type User = z.infer<typeof UserSchema>;
4951
export type InitUser = z.infer<typeof InitUserSchema>;
5052
export type UpdateUser = z.infer<typeof UpdateUserSchema>;

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"prisma-generate-sql": "bunx dotenv -e .env.dev -- prisma generate --sql"
1212
},
1313
"prisma": {
14-
"seed": "bun src/seeds/seed.ts"
14+
"seed": "bun src/seeds/seed-test.ts"
1515
},
1616
"keywords": [],
1717
"author": "",

server/prisma/schema.prisma

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//schema.prisma
22
generator client {
3-
provider = "prisma-client-js"
4-
binaryTargets = ["native", "debian-openssl-3.0.x"]
3+
provider = "prisma-client-js"
4+
binaryTargets = ["native", "debian-openssl-3.0.x"]
55
previewFeatures = ["typedSql"]
66
}
77

@@ -39,6 +39,7 @@ model User {
3939
enrollments Enrollment[]
4040
sendingUsers Relationship[] @relation("sending") // 自分がマッチリクエストを送ったユーザー
4141
receivingUsers Relationship[] @relation("receiving") // 自分にマッチリクエストを送ったユーザー
42+
interests Interest[]
4243
}
4344

4445
// プロフィールの画像。
@@ -47,6 +48,25 @@ model Avatar {
4748
data Bytes
4849
}
4950

51+
model InterestSubject {
52+
id Int @id @default(autoincrement())
53+
name String
54+
group String // such as Computer Science | name = ML
55+
56+
@@unique([name, group])
57+
Interest Interest[] // ignore this
58+
}
59+
60+
// User->Interest->InterestSubject
61+
model Interest {
62+
userId Int
63+
user User @relation(fields: [userId], references: [id])
64+
subjectId Int
65+
subject InterestSubject @relation(fields: [subjectId], references: [id])
66+
67+
@@unique([userId, subjectId])
68+
}
69+
5070
// enum Gender {
5171
// MALE
5272
// FEMALE
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { beforeAll, expect, test } from "bun:test";
2+
import { assertLocalDB } from "../load-env";
3+
import * as interest from "./interest";
4+
5+
beforeAll(assertLocalDB);
6+
7+
test("list", async () => {
8+
const got = (await interest.all()).sort((a, b) => a.id - b.id);
9+
expect(got).toEqual([
10+
{ id: 1, group: "Computer Science", name: "型システム" },
11+
{ id: 2, group: "Computer Science", name: "機械学習" },
12+
{ id: 3, group: "Computer Science", name: "CPU アーキテクチャ" },
13+
{ id: 4, group: "Computer Science", name: "分散処理" },
14+
{ id: 5, group: "Math", name: "Lean4" },
15+
]);
16+
});
17+
18+
test("get by user id", async () => {
19+
const got = (await interest.of(101)).sort((a, b) => a.id - b.id);
20+
expect(got).toEqual([
21+
{ id: 1, group: "Computer Science", name: "型システム" },
22+
{ id: 2, group: "Computer Science", name: "機械学習" },
23+
{ id: 3, group: "Computer Science", name: "CPU アーキテクチャ" },
24+
]);
25+
});

server/src/database/interest.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { InterestSubject, UserID } from "../common/types";
2+
import { prisma } from "./client";
3+
4+
export async function all(): Promise<InterestSubject[]> {
5+
return await prisma.interestSubject.findMany();
6+
}
7+
8+
export async function get(id: number): Promise<InterestSubject | null> {
9+
return await prisma.interestSubject.findUnique({ where: { id } });
10+
}
11+
12+
export async function of(userId: UserID): Promise<InterestSubject[]> {
13+
return await prisma.interest
14+
.findMany({
15+
where: {
16+
userId,
17+
},
18+
select: {
19+
subject: true,
20+
},
21+
})
22+
.then((res) => res.map((interest) => interest.subject));
23+
}
24+
25+
export async function add(userId: UserID, subjectId: number) {
26+
return await prisma.interest.create({
27+
data: {
28+
userId,
29+
subjectId,
30+
},
31+
});
32+
}
33+
export async function remove(userId: UserID, subjectId: number) {
34+
return await prisma.interest.delete({
35+
where: {
36+
userId_subjectId: { userId, subjectId },
37+
},
38+
});
39+
}

server/src/functions/user.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ test("get all users", async () => {
1616
expect(result.code).toBe(200);
1717
expect(result.body).toSatisfy((s) => s.length === 3);
1818
expect(result.body).toSatisfy(
19-
(s) => typeof s !== "string" && s[0].name === "田中太郎",
19+
(s) =>
20+
typeof s !== "string" && s.some((person) => person.name === "田中太郎"),
2021
);
2122
});
2223

server/src/seeds/data/subjects.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const subjects = [
2+
{
3+
group: "Computer Science",
4+
subjects: ["機械学習", "CPU アーキテクチャ", "型システム", "分散処理"],
5+
},
6+
{
7+
group: "Math",
8+
subjects: ["Lean4"],
9+
},
10+
];

server/src/seeds/seed-test.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { prisma } from "../database/client";
2+
import {
3+
courses,
4+
enrollments,
5+
interest,
6+
slots,
7+
subjects,
8+
users,
9+
} from "./test-data/data";
10+
11+
async function main() {
12+
await Promise.all(
13+
subjects.map(async ({ group, subjects }) => {
14+
for (const [id, name] of subjects) {
15+
await prisma.interestSubject.upsert({
16+
where: { id },
17+
update: { name, group },
18+
create: { id, name, group },
19+
});
20+
}
21+
}),
22+
);
23+
24+
await Promise.all(
25+
users.map(async (user) => {
26+
await prisma.user.upsert({
27+
where: { id: user.id },
28+
update: {},
29+
create: user,
30+
});
31+
}),
32+
);
33+
34+
await Promise.all(
35+
interest.map(async (interest) => {
36+
await prisma.interest.upsert({
37+
where: {
38+
userId_subjectId: interest,
39+
},
40+
update: interest,
41+
create: interest,
42+
});
43+
}),
44+
);
45+
46+
await Promise.all(
47+
courses.map(async (course) => {
48+
await prisma.course.upsert({
49+
where: { id: course.id },
50+
update: course,
51+
create: course,
52+
});
53+
}),
54+
);
55+
56+
await Promise.all(
57+
slots.map(async (slot) => {
58+
await prisma.slot.upsert({
59+
where: {
60+
courseId_period_day: {
61+
courseId: slot.courseId,
62+
period: slot.period,
63+
day: slot.day,
64+
},
65+
},
66+
update: slot,
67+
create: slot,
68+
});
69+
}),
70+
);
71+
72+
const promises = enrollments.map(async ([user, course]) => {
73+
await prisma.enrollment.upsert({
74+
where: {
75+
userId_courseId: { userId: user, courseId: course },
76+
},
77+
update: {},
78+
create: {
79+
userId: user,
80+
courseId: course,
81+
},
82+
});
83+
});
84+
await Promise.all(promises);
85+
}
86+
87+
await main()
88+
.then(async () => {
89+
await prisma.$disconnect();
90+
})
91+
.catch(async (e) => {
92+
console.error(e);
93+
await prisma.$disconnect();
94+
process.exit(1);
95+
});

0 commit comments

Comments
 (0)