mirror of
https://litchi.icu/ngc2207/judge4c-db.git
synced 2025-05-18 13:07:05 +00:00
feat: add Prisma integration and initial data seeding
This commit is contained in:
parent
2fc607accd
commit
3e68af8f7a
5
.gitignore
vendored
5
.gitignore
vendored
@ -41,4 +41,7 @@ next-env.d.ts
|
|||||||
cache
|
cache
|
||||||
|
|
||||||
# bun
|
# bun
|
||||||
bun.lockb
|
bun.lockb
|
||||||
|
|
||||||
|
# prisma
|
||||||
|
/prisma/migrations
|
11
package.json
11
package.json
@ -9,6 +9,7 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@prisma/client": "^5.22.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.456.0",
|
"lucide-react": "^0.456.0",
|
||||||
@ -19,13 +20,15 @@
|
|||||||
"tailwindcss-animate": "^1.0.7"
|
"tailwindcss-animate": "^1.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
"@faker-js/faker": "^9.2.0",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"postcss": "^8",
|
|
||||||
"tailwindcss": "^3.4.1",
|
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "15.0.3"
|
"eslint-config-next": "15.0.3",
|
||||||
|
"postcss": "^8",
|
||||||
|
"prisma": "^5.22.0",
|
||||||
|
"tailwindcss": "^3.4.1",
|
||||||
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
165
prisma/schema.prisma
Normal file
165
prisma/schema.prisma
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum UserRole {
|
||||||
|
ADMIN
|
||||||
|
TEACHER
|
||||||
|
STUDENT
|
||||||
|
GUEST
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
email String @unique @db.VarChar(255)
|
||||||
|
displayName String? @db.VarChar(255)
|
||||||
|
hashedPassword String @default("")
|
||||||
|
passwordSalt String @default("")
|
||||||
|
role UserRole @default(GUEST)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
organizedEvents Event[] @relation("OrganizedEvents")
|
||||||
|
participatedEvents Event[] @relation("ParticipatedEvents")
|
||||||
|
createdQuestions Question[] @relation("CreatedQuestions")
|
||||||
|
submissions Submission[]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EventType {
|
||||||
|
COMPETITION
|
||||||
|
EXAM
|
||||||
|
HOMEWORK
|
||||||
|
}
|
||||||
|
|
||||||
|
model Event {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
startTime DateTime @db.Timestamptz
|
||||||
|
endTime DateTime @db.Timestamptz
|
||||||
|
isVisible Boolean @default(true)
|
||||||
|
type EventType @default(COMPETITION)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
organizer User[] @relation("OrganizedEvents")
|
||||||
|
participants User[] @relation("ParticipatedEvents")
|
||||||
|
eventQuestions EventQuestion[]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum QuestionDifficulty {
|
||||||
|
EASY
|
||||||
|
MEDIUM
|
||||||
|
HARD
|
||||||
|
}
|
||||||
|
|
||||||
|
model Question {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
statement String @db.Text
|
||||||
|
difficulty QuestionDifficulty @default(EASY)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
creators User[] @relation("CreatedQuestions")
|
||||||
|
codeTemplates CodeTemplate[]
|
||||||
|
eventQuestions EventQuestion[]
|
||||||
|
tags QuestionTag[] @relation("QuestionTags")
|
||||||
|
}
|
||||||
|
|
||||||
|
model QuestionTag {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
questions Question[] @relation("QuestionTags")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodeLanguage {
|
||||||
|
C
|
||||||
|
CPP
|
||||||
|
JAVA
|
||||||
|
}
|
||||||
|
|
||||||
|
model CodeTemplate {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
language CodeLanguage
|
||||||
|
starterCode String @db.Text
|
||||||
|
correctSolution String @default("") @db.Text
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
question Question @relation(fields: [questionId], references: [id])
|
||||||
|
questionId String
|
||||||
|
}
|
||||||
|
|
||||||
|
model EventQuestion {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
event Event @relation(fields: [eventId], references: [id])
|
||||||
|
eventId String
|
||||||
|
question Question @relation(fields: [questionId], references: [id])
|
||||||
|
questionId String
|
||||||
|
displayOrder Int @default(0)
|
||||||
|
hidden Boolean @default(false)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
submissions Submission[]
|
||||||
|
|
||||||
|
@@unique([eventId, questionId])
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SubmissionStatus {
|
||||||
|
PENDING
|
||||||
|
ACCEPTED
|
||||||
|
REJECTED
|
||||||
|
COMPILATION_ERROR
|
||||||
|
RUNTIME_ERROR
|
||||||
|
INTERNAL_ERROR
|
||||||
|
PARTIAL_ACCEPTED
|
||||||
|
SKIPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
model Submission {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
submitter User @relation(fields: [submitterId], references: [id])
|
||||||
|
submitterId String @db.VarChar(255)
|
||||||
|
eventQuestion EventQuestion @relation(fields: [eventQuestionId], references: [id])
|
||||||
|
eventQuestionId String @db.VarChar(255)
|
||||||
|
language CodeLanguage
|
||||||
|
code String @db.Text
|
||||||
|
status SubmissionStatus
|
||||||
|
statusMessage String?
|
||||||
|
memoryUsage Int?
|
||||||
|
executionTime Int?
|
||||||
|
score Int? @default(0)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
testResults TestResult[]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestResultStatus {
|
||||||
|
ACCEPTED
|
||||||
|
REJECTED
|
||||||
|
TIMEOUT
|
||||||
|
MEMORY_LIMIT_EXCEEDED
|
||||||
|
COMPILATION_ERROR
|
||||||
|
RUNTIME_ERROR
|
||||||
|
INTERNAL_ERROR
|
||||||
|
OUTPUT_MISMATCH
|
||||||
|
SKIPPED
|
||||||
|
}
|
||||||
|
|
||||||
|
model TestResult {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
submission Submission @relation(fields: [submissionId], references: [id])
|
||||||
|
submissionId String
|
||||||
|
input String @db.Text
|
||||||
|
output String @db.Text
|
||||||
|
status TestResultStatus
|
||||||
|
statusMessage String?
|
||||||
|
memoryUsage Int?
|
||||||
|
executionTime Int?
|
||||||
|
score Int? @default(0)
|
||||||
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
}
|
574
prisma/seed.ts
Normal file
574
prisma/seed.ts
Normal file
@ -0,0 +1,574 @@
|
|||||||
|
import {
|
||||||
|
UserRole,
|
||||||
|
User,
|
||||||
|
EventType,
|
||||||
|
Event,
|
||||||
|
QuestionDifficulty,
|
||||||
|
Question,
|
||||||
|
QuestionTag,
|
||||||
|
CodeLanguage,
|
||||||
|
CodeTemplate,
|
||||||
|
EventQuestion,
|
||||||
|
} from "@prisma/client";
|
||||||
|
import prisma from "@/lib/prisma";
|
||||||
|
import { faker } from "@faker-js/faker";
|
||||||
|
|
||||||
|
async function createUser(role: UserRole): Promise<User> {
|
||||||
|
return prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email: faker.internet.email(),
|
||||||
|
displayName: faker.person.fullName(),
|
||||||
|
hashedPassword: faker.internet.password(),
|
||||||
|
passwordSalt: faker.string.alphanumeric(16),
|
||||||
|
role,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createUsers(
|
||||||
|
rolesWithCount: { role: UserRole; count: number }[]
|
||||||
|
): Promise<User[]> {
|
||||||
|
const users = await Promise.all(
|
||||||
|
rolesWithCount.flatMap(({ role, count }) =>
|
||||||
|
Array.from({ length: count }, () => createUser(role))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createQuestionTags(): Promise<QuestionTag[]> {
|
||||||
|
const questionTags = [
|
||||||
|
"Array",
|
||||||
|
"String",
|
||||||
|
"Hash Table",
|
||||||
|
"Dynamic Programming",
|
||||||
|
"Math",
|
||||||
|
"Sorting",
|
||||||
|
"Greedy",
|
||||||
|
"Depth-First Search",
|
||||||
|
"Database",
|
||||||
|
"Binary Search",
|
||||||
|
"Matrix",
|
||||||
|
"Tree",
|
||||||
|
"Breadth-First Search",
|
||||||
|
];
|
||||||
|
|
||||||
|
await prisma.questionTag.createMany({
|
||||||
|
data: questionTags.map((name) => ({ name })),
|
||||||
|
});
|
||||||
|
|
||||||
|
return prisma.questionTag.findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createQuestions(): Promise<Question[]> {
|
||||||
|
const questions = [
|
||||||
|
{
|
||||||
|
name: "Two Sum",
|
||||||
|
statement: `Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.`,
|
||||||
|
difficulty: QuestionDifficulty.EASY,
|
||||||
|
tags: ["Array", "Hash Table"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add Two Numbers",
|
||||||
|
statement: `You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.`,
|
||||||
|
difficulty: QuestionDifficulty.MEDIUM,
|
||||||
|
tags: ["Linked List", "Math"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Longest Substring Without Repeating Characters",
|
||||||
|
statement: `Given a string s, find the length of the longest substring without repeating characters.`,
|
||||||
|
difficulty: QuestionDifficulty.MEDIUM,
|
||||||
|
tags: ["Hash Table", "String", "Sliding Window"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const creators = await prisma.user.findMany({
|
||||||
|
where: { role: UserRole.TEACHER },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (creators.length === 0) {
|
||||||
|
throw new Error("No creators found for questions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = await prisma.questionTag.findMany();
|
||||||
|
const tagMap = new Map(tags.map((tag) => [tag.name, tag]));
|
||||||
|
|
||||||
|
const missingTags = questions.flatMap((question) =>
|
||||||
|
question.tags.filter((tag) => !tagMap.has(tag))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (missingTags.length > 0) {
|
||||||
|
await prisma.questionTag.createMany({
|
||||||
|
data: missingTags.map((name) => ({ name })),
|
||||||
|
});
|
||||||
|
|
||||||
|
const createdTags = await prisma.questionTag.findMany({
|
||||||
|
where: { name: { in: missingTags } },
|
||||||
|
});
|
||||||
|
|
||||||
|
createdTags.forEach((tag) => tagMap.set(tag.name, tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
questions.map(({ name, statement, difficulty, tags: questionTags }) =>
|
||||||
|
prisma.question.create({
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
statement,
|
||||||
|
difficulty,
|
||||||
|
tags: {
|
||||||
|
connect: questionTags.map((tag) => ({ id: tagMap.get(tag)!.id })),
|
||||||
|
},
|
||||||
|
creators: {
|
||||||
|
connect: creators
|
||||||
|
.sort(() => Math.random() - 0.5)
|
||||||
|
.slice(
|
||||||
|
0,
|
||||||
|
Math.max(1, Math.floor(Math.random() * creators.length))
|
||||||
|
)
|
||||||
|
.map((creator) => ({ id: creator.id })),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkAndSeed<T>(
|
||||||
|
check: () => Promise<T[]>,
|
||||||
|
create: () => Promise<T[]>,
|
||||||
|
entityName: string
|
||||||
|
): Promise<void> {
|
||||||
|
const existingEntities = await check();
|
||||||
|
if (existingEntities.length > 0) {
|
||||||
|
console.log(`${entityName} already exist, skipping seeding ${entityName}.`);
|
||||||
|
} else {
|
||||||
|
console.log(`Seeding ${entityName} ...`);
|
||||||
|
const entities = await create();
|
||||||
|
console.log(`Created ${entityName}:`);
|
||||||
|
console.log(entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createCodeTemplates(): Promise<CodeTemplate[]> {
|
||||||
|
const codeTemplates = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
language: CodeLanguage.C,
|
||||||
|
starterCode: `/**
|
||||||
|
* Note: The returned array must be malloced, assume caller calls free().
|
||||||
|
*/
|
||||||
|
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
|
||||||
|
|
||||||
|
}`,
|
||||||
|
correctSolution: `int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
|
||||||
|
struct hashTable {
|
||||||
|
int key;
|
||||||
|
int value;
|
||||||
|
UT_hash_handle hh;
|
||||||
|
} *hashTable = NULL, *item, *tmpItem;
|
||||||
|
|
||||||
|
for (int i = 0; i < numsSize; i++) {
|
||||||
|
HASH_FIND_INT(hashTable, &nums[i], item);
|
||||||
|
if (item) {
|
||||||
|
int* result = malloc(sizeof(int) * 2);
|
||||||
|
result[0] = item->value;
|
||||||
|
result[1] = i;
|
||||||
|
*returnSize = 2;
|
||||||
|
HASH_ITER(hh, hashTable, item, tmpItem) {
|
||||||
|
HASH_DEL(hashTable, item);
|
||||||
|
free(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
item = malloc(sizeof(struct hashTable));
|
||||||
|
item->key = target - nums[i];
|
||||||
|
item->value = i;
|
||||||
|
HASH_ADD_INT(hashTable, key, item);
|
||||||
|
}
|
||||||
|
HASH_ITER(hh, hashTable, item, tmpItem) {
|
||||||
|
HASH_DEL(hashTable, item);
|
||||||
|
free(item);
|
||||||
|
}
|
||||||
|
*returnSize = 0;
|
||||||
|
// If no valid pair is found, return an empty array
|
||||||
|
return malloc(sizeof(int) * 0);
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.CPP,
|
||||||
|
starterCode: `class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> twoSum(vector<int>& nums, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> twoSum(vector<int> &nums, int target) {
|
||||||
|
unordered_map<int, int> hash;
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
hash[nums[i]] = i;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
int complement = target - nums[i];
|
||||||
|
if (hash.find(complement) != hash.end() && hash[complement] != i) {
|
||||||
|
return {i, hash[complement]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no valid pair is found, return an empty vector
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.JAVA,
|
||||||
|
starterCode: `class Solution {
|
||||||
|
public int[] twoSum(int[] nums, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
public int[] twoSum(int[] nums, int target) {
|
||||||
|
Map<Integer, Integer> map = new HashMap<>();
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
map.put(nums[i], i);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
int complement = target - nums[i];
|
||||||
|
if (map.containsKey(complement) && map.get(complement) != i) {
|
||||||
|
return new int[] { i, map.get(complement) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In case there is no solution, return an empty array
|
||||||
|
return new int[] {};
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
language: CodeLanguage.C,
|
||||||
|
starterCode: `/**
|
||||||
|
* Definition for singly-linked list.
|
||||||
|
* struct ListNode {
|
||||||
|
* int val;
|
||||||
|
* struct ListNode *next;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
|
||||||
|
|
||||||
|
}`,
|
||||||
|
correctSolution: `struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
|
||||||
|
struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
|
||||||
|
dummyHead->val = 0;
|
||||||
|
dummyHead->next = NULL;
|
||||||
|
struct ListNode* curr = dummyHead;
|
||||||
|
int carry = 0;
|
||||||
|
while (l1 != NULL || l2 != NULL || carry != 0) {
|
||||||
|
int x = (l1 != NULL) ? l1->val : 0;
|
||||||
|
int y = (l2 != NULL) ? l2->val : 0;
|
||||||
|
int sum = carry + x + y;
|
||||||
|
carry = sum / 10;
|
||||||
|
curr->next = malloc(sizeof(struct ListNode));
|
||||||
|
curr->next->val = sum % 10;
|
||||||
|
curr->next->next = NULL;
|
||||||
|
curr = curr->next;
|
||||||
|
if (l1 != NULL) l1 = l1->next;
|
||||||
|
if (l2 != NULL) l2 = l2->next;
|
||||||
|
}
|
||||||
|
struct ListNode* result = dummyHead->next;
|
||||||
|
free(dummyHead); // Free the memory allocated for dummyHead
|
||||||
|
return result;
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.CPP,
|
||||||
|
starterCode: `/**
|
||||||
|
* Definition for singly-linked list.
|
||||||
|
* struct ListNode {
|
||||||
|
* int val;
|
||||||
|
* ListNode *next;
|
||||||
|
* ListNode() : val(0), next(nullptr) {}
|
||||||
|
* ListNode(int x) : val(x), next(nullptr) {}
|
||||||
|
* ListNode(int x, ListNode *next) : val(x), next(next) {}
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
public:
|
||||||
|
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
|
||||||
|
ListNode* dummyHead = new ListNode(0);
|
||||||
|
ListNode* curr = dummyHead;
|
||||||
|
int carry = 0;
|
||||||
|
while (l1 != NULL || l2 != NULL || carry != 0) {
|
||||||
|
int x = l1 ? l1->val : 0;
|
||||||
|
int y = l2 ? l2->val : 0;
|
||||||
|
int sum = carry + x + y;
|
||||||
|
carry = sum / 10;
|
||||||
|
curr->next = new ListNode(sum % 10);
|
||||||
|
curr = curr->next;
|
||||||
|
l1 = l1 ? l1->next : nullptr;
|
||||||
|
l2 = l2 ? l2->next : nullptr;
|
||||||
|
}
|
||||||
|
ListNode* result = dummyHead->next;
|
||||||
|
delete dummyHead; // Freeing the memory allocated for dummyHead
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.JAVA,
|
||||||
|
starterCode: `/**
|
||||||
|
* Definition for singly-linked list.
|
||||||
|
* public class ListNode {
|
||||||
|
* int val;
|
||||||
|
* ListNode next;
|
||||||
|
* ListNode() {}
|
||||||
|
* ListNode(int val) { this.val = val; }
|
||||||
|
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
class Solution {
|
||||||
|
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
// Add Two Numbers (Java improved)
|
||||||
|
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
|
||||||
|
ListNode dummyHead = new ListNode(0);
|
||||||
|
ListNode curr = dummyHead;
|
||||||
|
int carry = 0;
|
||||||
|
while (l1 != null || l2 != null || carry != 0) {
|
||||||
|
int x = (l1 != null) ? l1.val : 0;
|
||||||
|
int y = (l2 != null) ? l2.val : 0;
|
||||||
|
int sum = carry + x + y;
|
||||||
|
carry = sum / 10;
|
||||||
|
curr.next = new ListNode(sum % 10);
|
||||||
|
curr = curr.next;
|
||||||
|
if (l1 != null) l1 = l1.next;
|
||||||
|
if (l2 != null) l2 = l2.next;
|
||||||
|
}
|
||||||
|
return dummyHead.next;
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
language: CodeLanguage.C,
|
||||||
|
starterCode: `int lengthOfLongestSubstring(char* s) {
|
||||||
|
|
||||||
|
}`,
|
||||||
|
correctSolution: `int lengthOfLongestSubstring(char * s){
|
||||||
|
|
||||||
|
int arr[256] = {0};
|
||||||
|
int start = 0;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
for (int i = 0; s[i]; i++)
|
||||||
|
{
|
||||||
|
char c = s[i];
|
||||||
|
arr[c] != 0 ? (arr[c] > start ? start = arr[c] : start) : arr[c];
|
||||||
|
(i - start + 1) > len ? len = (i - start + 1) : len;
|
||||||
|
arr[c] = i + 1;
|
||||||
|
}
|
||||||
|
return (len);
|
||||||
|
return(len);
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.CPP,
|
||||||
|
starterCode: `class Solution {
|
||||||
|
public:
|
||||||
|
int lengthOfLongestSubstring(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
public:
|
||||||
|
int lengthOfLongestSubstring(std::string_view sv)
|
||||||
|
{
|
||||||
|
std::vector<char> vec;
|
||||||
|
std::size_t size = 0;
|
||||||
|
|
||||||
|
for (auto c : sv) {
|
||||||
|
if (const auto& it = std::find(std::cbegin(vec), std::cend(vec), c); it != std::cend(vec)) {
|
||||||
|
size = std::max(size, vec.size());
|
||||||
|
vec.erase(std::cbegin(vec), std::next(it));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec.emplace_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::max(size, vec.size());
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: CodeLanguage.JAVA,
|
||||||
|
starterCode: `class Solution {
|
||||||
|
public int lengthOfLongestSubstring(String s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
correctSolution: `class Solution {
|
||||||
|
public int lengthOfLongestSubstring(String s) {
|
||||||
|
Queue<Character> queue = new LinkedList<>();
|
||||||
|
int res = 0;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
while (queue.contains(c)) {
|
||||||
|
queue.poll();
|
||||||
|
}
|
||||||
|
queue.offer(c);
|
||||||
|
res = Math.max(res, queue.size());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const questions = await prisma.question.findMany();
|
||||||
|
const newCodeTemplates = questions.flatMap((question, index) =>
|
||||||
|
codeTemplates[index].map((template) => ({
|
||||||
|
...template,
|
||||||
|
questionId: question.id,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
await prisma.codeTemplate.createMany({
|
||||||
|
data: newCodeTemplates,
|
||||||
|
});
|
||||||
|
|
||||||
|
return prisma.codeTemplate.findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEvents(): Promise<Event[]> {
|
||||||
|
const users = await prisma.user.findMany();
|
||||||
|
if (users.length === 0) {
|
||||||
|
throw new Error("No users found fororganizers and participants.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventTypes = Object.values(EventType);
|
||||||
|
|
||||||
|
const events = await Promise.all(
|
||||||
|
Array.from({ length: 5 }, () => {
|
||||||
|
const startTime = faker.date.future();
|
||||||
|
const endTime = faker.date.future({ refDate: startTime });
|
||||||
|
const type = faker.helpers.arrayElement(eventTypes);
|
||||||
|
const isVisible = faker.datatype.boolean();
|
||||||
|
|
||||||
|
return prisma.event.create({
|
||||||
|
data: {
|
||||||
|
name: faker.lorem.words(3),
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
type,
|
||||||
|
isVisible,
|
||||||
|
organizer: {
|
||||||
|
connect: {
|
||||||
|
id: faker.helpers.arrayElement(users).id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
participants: {
|
||||||
|
connect: faker.helpers
|
||||||
|
.arrayElements(users, { min: 1, max: 5 })
|
||||||
|
.map((user) => ({ id: user.id })),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEventQuestions(
|
||||||
|
event: Event,
|
||||||
|
questions: Question[]
|
||||||
|
): Promise<EventQuestion[]> {
|
||||||
|
const selectedQuestions = faker.helpers.arrayElements(
|
||||||
|
questions,
|
||||||
|
faker.number.int({ min: 1, max: questions.length })
|
||||||
|
);
|
||||||
|
|
||||||
|
const shuffledQuestions = faker.helpers.shuffle(selectedQuestions);
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
shuffledQuestions.map((question, index) =>
|
||||||
|
prisma.eventQuestion.create({
|
||||||
|
data: {
|
||||||
|
event: {
|
||||||
|
connect: {
|
||||||
|
id: event.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
question: {
|
||||||
|
connect: {
|
||||||
|
id: question.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
displayOrder: index,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const rolesWithCount = [
|
||||||
|
{ role: UserRole.ADMIN, count: 2 },
|
||||||
|
{ role: UserRole.TEACHER, count: 3 },
|
||||||
|
{ role: UserRole.STUDENT, count: 5 },
|
||||||
|
{ role: UserRole.GUEST, count: 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await checkAndSeed(
|
||||||
|
() => prisma.user.findMany(),
|
||||||
|
() => createUsers(rolesWithCount),
|
||||||
|
"users"
|
||||||
|
);
|
||||||
|
|
||||||
|
await checkAndSeed(
|
||||||
|
() => prisma.questionTag.findMany(),
|
||||||
|
createQuestionTags,
|
||||||
|
"question tags"
|
||||||
|
);
|
||||||
|
|
||||||
|
await checkAndSeed(
|
||||||
|
() => prisma.question.findMany(),
|
||||||
|
createQuestions,
|
||||||
|
"questions"
|
||||||
|
);
|
||||||
|
|
||||||
|
await checkAndSeed(
|
||||||
|
() => prisma.codeTemplate.findMany(),
|
||||||
|
createCodeTemplates,
|
||||||
|
"code templates"
|
||||||
|
);
|
||||||
|
|
||||||
|
await checkAndSeed(() => prisma.event.findMany(), createEvents, "events");
|
||||||
|
|
||||||
|
const questions = await prisma.question.findMany();
|
||||||
|
const events = await prisma.event.findMany();
|
||||||
|
await Promise.all(
|
||||||
|
events.map((event) => createEventQuestions(event, questions))
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
5
src/lib/prisma.ts
Normal file
5
src/lib/prisma.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
|
const prisma: PrismaClient = new PrismaClient();
|
||||||
|
|
||||||
|
export default prisma;
|
Loading…
Reference in New Issue
Block a user