Files
Edu/services/content/src/questions/questions.service.ts
SpecialX 921fe82771 feat(content): 修复服务并添加chapters/knowledge-points/questions模块
- database.ts 导出db常量替代getDb()函数

- env.ts JWT_SECRET/ES_URL/NEO4J_URL改optional加DEV_MODE

- neo4j.ts driver惰性创建+try/catch+connectionTimeout:3000

- health/lifecycle改用Drizzle原生查询

- textbooks.schema修复integer到int+导出NewTextbook类型

- 新建chapters/knowledge-points/questions三模块CRUD

- knowledge-points含Neo4j前置依赖图非阻塞查询

- content-init.sql创建4张表

端到端验证: textbooks/chapters/knowledge-points/questions全CRUD通过
2026-07-09 08:52:15 +08:00

84 lines
2.2 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { Injectable } from "@nestjs/common";
import { questionsRepository } from "./questions.repository.js";
import type { Question } from "./questions.schema.js";
import {
NotFoundError,
ValidationError,
} from "../shared/errors/application-error.js";
export interface CreateQuestionInput {
knowledgePointId: string;
type: string;
content: string;
answer?: string;
explanation?: string;
difficulty?: number;
}
export interface UpdateQuestionInput {
type?: string;
content?: string;
answer?: string;
explanation?: string;
difficulty?: number;
}
const VALID_TYPES = new Set([
"single_choice",
"multiple_choice",
"short_answer",
"essay",
]);
@Injectable()
export class QuestionsService {
async createQuestion(input: CreateQuestionInput): Promise<{ id: string }> {
if (!input.knowledgePointId || !input.type || !input.content) {
throw new ValidationError("knowledgePointId, type, content are required");
}
if (!VALID_TYPES.has(input.type)) {
throw new ValidationError(
`Invalid question type: ${input.type}. Must be one of: ${[...VALID_TYPES].join(", ")}`,
);
}
const id = randomUUID();
await questionsRepository.create({
id,
knowledgePointId: input.knowledgePointId,
type: input.type,
content: input.content,
answer: input.answer,
explanation: input.explanation,
difficulty: input.difficulty,
});
return { id };
}
async getQuestion(id: string): Promise<Question> {
const question = await questionsRepository.findById(id);
if (!question) {
throw new NotFoundError("Question", id);
}
return question;
}
async listByKnowledgePoint(knowledgePointId: string): Promise<Question[]> {
return questionsRepository.findByKnowledgePointId(knowledgePointId);
}
async updateQuestion(id: string, data: UpdateQuestionInput): Promise<void> {
await this.getQuestion(id);
if (data.type && !VALID_TYPES.has(data.type)) {
throw new ValidationError(`Invalid question type: ${data.type}`);
}
await questionsRepository.update(id, data);
}
async deleteQuestion(id: string): Promise<void> {
await this.getQuestion(id);
await questionsRepository.delete(id);
}
}