Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
"simple-import-sort"
],
"rules": {
"@typescript-eslint/array-type": [
"error",
{
"default": "generic",
"readonly": "generic"
}
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/explicit-function-return-type": 0,
Expand Down
2 changes: 1 addition & 1 deletion backend/matching/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { logger } from '@/lib/utils';
import server, { io } from '@/server';
import { initWorker } from '@/workers';

const workers: ChildProcess[] = [];
const workers: Array<ChildProcess> = [];

const port = Number.parseInt(EXPRESS_PORT || '8001');

Expand Down
25 changes: 6 additions & 19 deletions backend/matching/src/services/get-match-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { IMatchItemsResponse, IMatchType } from '@/types';

import { createRoom } from './collab';
import { getRandomQuestion } from './question';
import { fetchAttemptedQuestions } from './user';

export async function getMatchItems(
searchIdentifier: IMatchType,
Expand All @@ -17,26 +16,13 @@ export async function getMatchItems(
throw new Error('Both user IDs are required');
}

let allAttemptedQuestions: number[] = [];

try {
const [attemptedQuestions1, attemptedQuestions2] = await Promise.all([
fetchAttemptedQuestions(userId1),
fetchAttemptedQuestions(userId2),
]);
allAttemptedQuestions = [...new Set([...attemptedQuestions1, ...attemptedQuestions2])];
} catch (error) {
logger.error('Error in getMatchItems: Failed to fetch attempted questions', error);
}

const topics = topic?.split('|') ?? [];
const payload = {
attemptedQuestions: allAttemptedQuestions,
userId1,
userId2,
...(searchIdentifier === 'difficulty' && difficulty ? { difficulty } : {}),
...(searchIdentifier === 'topic' && topic ? { topic: topics } : {}),
...(searchIdentifier === 'exact match' && topic && difficulty
? { topic: topics, difficulty }
: {}),
...(searchIdentifier === 'topic' && topic ? { topics } : {}),
...(searchIdentifier === 'exact match' && topic && difficulty ? { topics, difficulty } : {}),
};

// Get a random question
Expand All @@ -55,7 +41,8 @@ export async function getMatchItems(
questionId: question.id,
};
} catch (error) {
logger.error('Error in getMatchItems:', error);
const { name, message, stack, cause } = error as Error;
logger.error(`Error in getMatchItems: ${JSON.stringify({ name, message, stack, cause })}`);
return undefined;
}
}
10 changes: 5 additions & 5 deletions backend/matching/src/services/question.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import type { IGetRandomQuestionPayload, IQuestion, IServiceResponse } from '@/types';
import type { IGetRandomQuestionPayload, IQuestion } from '@/types';

import { questionServiceClient, routes } from './_hosts';

export async function getRandomQuestion(payload: IGetRandomQuestionPayload): Promise<IQuestion> {
const response = await questionServiceClient.post<IServiceResponse<{ question: IQuestion }>>(
const response = await questionServiceClient.post<IQuestion>(
routes.QUESTION_SERVICE.GET_RANDOM_QN.path,
payload
);

if (response.status !== 200 || !response.data.data) {
throw new Error(response.data.error?.message || 'Failed to get a random question');
if (response.status !== 200 || !response.data) {
throw new Error(response.statusText || 'Failed to get a random question');
}

return response?.data?.data?.question ?? undefined;
return response?.data ?? undefined;
}
4 changes: 2 additions & 2 deletions backend/matching/src/services/user.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { routes, userServiceClient } from './_hosts';

export async function fetchAttemptedQuestions(userId: string): Promise<number[]> {
const response = await userServiceClient.post<number[]>(
export async function fetchAttemptedQuestions(userId: string): Promise<Array<number>> {
const response = await userServiceClient.post<Array<number>>(
routes.USER_SERVICE.ATTEMPTED_QNS.GET.path,
{
userId,
Expand Down
7 changes: 4 additions & 3 deletions backend/matching/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type IRequestMatchRESTPayload = {
};

export type IRequestMatchWSPayload = {
topic: string | string[];
topic: string | Array<string>;
difficulty: string;
};

Expand Down Expand Up @@ -61,9 +61,10 @@ export interface IQuestion {
}

export interface IGetRandomQuestionPayload {
attemptedQuestions: number[];
userId1: string;
userId2: string;
difficulty?: string;
topic?: Array<string>;
topics?: Array<string>;
}

export interface IMatchItemsResponse {
Expand Down
2 changes: 1 addition & 1 deletion backend/matching/src/workers/matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async function processMatch(
]);

// Notify both sockets
const { ...matchItems } = await getMatchItems(
const matchItems = await getMatchItems(
searchIdentifier,
topic,
difficulty,
Expand Down
11 changes: 11 additions & 0 deletions backend/question/drizzle/0001_attempt_history.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS "question_attempts" (
"attempt_id" serial PRIMARY KEY NOT NULL,
"question_id" integer NOT NULL,
"user_id_1" uuid NOT NULL,
"user_id_2" uuid,
"code" text NOT NULL,
"timestamp" timestamp (6) with time zone DEFAULT now(),
"language" varchar(50) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX IF NOT EXISTS "unique_users_attempt" ON "question_attempts" USING btree ("question_id","user_id_1","user_id_2");
190 changes: 190 additions & 0 deletions backend/question/drizzle/meta/0001_snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
{
"id": "afa9ccaa-137c-47d3-acb0-ab1e2208038e",
"prevId": "84b2ca8d-3021-496f-8769-bbc4dada6468",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.admin": {
"name": "admin",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"action": {
"name": "action",
"type": "action",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.question_attempts": {
"name": "question_attempts",
"schema": "",
"columns": {
"attempt_id": {
"name": "attempt_id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"question_id": {
"name": "question_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"user_id_1": {
"name": "user_id_1",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"user_id_2": {
"name": "user_id_2",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"code": {
"name": "code",
"type": "text",
"primaryKey": false,
"notNull": true
},
"timestamp": {
"name": "timestamp",
"type": "timestamp (6) with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"language": {
"name": "language",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"unique_users_attempt": {
"name": "unique_users_attempt",
"columns": [
{
"expression": "question_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "user_id_1",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "user_id_2",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.questions": {
"name": "questions",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"title": {
"name": "title",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"difficulty": {
"name": "difficulty",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true
},
"topic": {
"name": "topic",
"type": "varchar(255)[]",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp (6) with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp (6) with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"public.action": {
"name": "action",
"schema": "public",
"values": [
"SEED"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
7 changes: 7 additions & 0 deletions backend/question/drizzle/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
"when": 1728143550719,
"tag": "0000_initial_schema",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1730553826248,
"tag": "0001_attempt_history",
"breakpoints": true
}
]
}
3 changes: 2 additions & 1 deletion backend/question/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"http-status-codes": "^2.3.0",
"pino": "^9.4.0",
"pino-http": "^10.3.0",
"postgres": "^3.4.4"
"postgres": "^3.4.4",
"uuid": "^11.0.2"
},
"devDependencies": {
"@swc/core": "^1.7.26",
Expand Down
Loading