Merge remote-tracking branch 'origin/feat/question-routes' into feat/question-routes

This commit is contained in:
Gabriellvl 2025-04-07 16:47:18 +02:00
commit 24105004fc
12 changed files with 104 additions and 121 deletions

View file

@ -2,7 +2,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js';
import { Answer } from '../../entities/questions/answer.entity.js'; import { Answer } from '../../entities/questions/answer.entity.js';
import { Question } from '../../entities/questions/question.entity.js'; import { Question } from '../../entities/questions/question.entity.js';
import { Teacher } from '../../entities/users/teacher.entity.js'; import { Teacher } from '../../entities/users/teacher.entity.js';
import {Loaded} from "@mikro-orm/core"; import { Loaded } from '@mikro-orm/core';
export class AnswerRepository extends DwengoEntityRepository<Answer> { export class AnswerRepository extends DwengoEntityRepository<Answer> {
public async createAnswer(answer: { toQuestion: Question; author: Teacher; content: string }): Promise<Answer> { public async createAnswer(answer: { toQuestion: Question; author: Teacher; content: string }): Promise<Answer> {
@ -22,7 +22,8 @@ export class AnswerRepository extends DwengoEntityRepository<Answer> {
} }
public async findAnswer(question: Question, sequenceNumber: number): Promise<Loaded<Answer> | null> { public async findAnswer(question: Question, sequenceNumber: number): Promise<Loaded<Answer> | null> {
return this.findOne({ return this.findOne({
toQuestion: question, sequenceNumber toQuestion: question,
sequenceNumber,
}); });
} }
public async removeAnswerByQuestionAndSequenceNumber(question: Question, sequenceNumber: number): Promise<void> { public async removeAnswerByQuestionAndSequenceNumber(question: Question, sequenceNumber: number): Promise<void> {

View file

@ -3,7 +3,7 @@ import { Question } from '../../entities/questions/question.entity.js';
import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js';
import { Student } from '../../entities/users/student.entity.js'; import { Student } from '../../entities/users/student.entity.js';
import { LearningObject } from '../../entities/content/learning-object.entity.js'; import { LearningObject } from '../../entities/content/learning-object.entity.js';
import {Loaded} from "@mikro-orm/core"; import { Loaded } from '@mikro-orm/core';
export class QuestionRepository extends DwengoEntityRepository<Question> { export class QuestionRepository extends DwengoEntityRepository<Question> {
public async createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> { public async createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> {
@ -68,7 +68,7 @@ export class QuestionRepository extends DwengoEntityRepository<Question> {
learningObjectHruid: loId.hruid, learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language, learningObjectLanguage: loId.language,
learningObjectVersion: loId.version, learningObjectVersion: loId.version,
sequenceNumber sequenceNumber,
}); });
} }

View file

@ -1,19 +1,13 @@
import express from "express"; import express from 'express';
import { import { createAnswerHandler, deleteAnswerHandler, getAnswerHandler, getAllAnswersHandler, updateAnswerHandler } from '../controllers/answers';
createAnswerHandler,
deleteAnswerHandler,
getAnswerHandler,
getAllAnswersHandler,
updateAnswerHandler
} from "../controllers/answers";
const router = express.Router({ mergeParams: true }); const router = express.Router({ mergeParams: true });
router.get('/', getAllAnswersHandler); router.get('/', getAllAnswersHandler);
router.post('/', createAnswerHandler) router.post('/', createAnswerHandler);
router.get('/:seqAnswer', getAnswerHandler) router.get('/:seqAnswer', getAnswerHandler);
router.delete('/:seqAnswer', deleteAnswerHandler); router.delete('/:seqAnswer', deleteAnswerHandler);

View file

@ -1,11 +1,11 @@
import {getAnswerRepository} from "../data/repositories"; import { getAnswerRepository } from '../data/repositories';
import {Answer} from "../entities/questions/answer.entity"; import { Answer } from '../entities/questions/answer.entity';
import {mapToAnswerDTO, mapToAnswerDTOId} from "../interfaces/answer"; import { mapToAnswerDTO, mapToAnswerDTOId } from '../interfaces/answer';
import {fetchTeacher} from "./teachers"; import { fetchTeacher } from './teachers';
import {fetchQuestion} from "./questions"; import { fetchQuestion } from './questions';
import {QuestionId} from "@dwengo-1/common/interfaces/question"; import { QuestionId } from '@dwengo-1/common/interfaces/question';
import {AnswerData, AnswerDTO, AnswerId} from "@dwengo-1/common/interfaces/answer"; import { AnswerData, AnswerDTO, AnswerId } from '@dwengo-1/common/interfaces/answer';
import {NotFoundException} from "../exceptions/not-found-exception"; import { NotFoundException } from '../exceptions/not-found-exception';
export async function getAnswersByQuestion(questionId: QuestionId, full: boolean): Promise<AnswerDTO[] | AnswerId[]> { export async function getAnswersByQuestion(questionId: QuestionId, full: boolean): Promise<AnswerDTO[] | AnswerId[]> {
const answerRepository = getAnswerRepository(); const answerRepository = getAnswerRepository();
@ -27,7 +27,9 @@ export async function createAnswer(questionId: QuestionId, answerData: AnswerDat
const content = answerData.content; const content = answerData.content;
const answer = await answerRepository.createAnswer({ const answer = await answerRepository.createAnswer({
toQuestion, author, content toQuestion,
author,
content,
}); });
return mapToAnswerDTO(answer); return mapToAnswerDTO(answer);
} }
@ -37,7 +39,7 @@ async function fetchAnswer(questionId: QuestionId, sequenceNumber: number): Prom
const question = await fetchQuestion(questionId); const question = await fetchQuestion(questionId);
const answer = await answerRepository.findAnswer(question, sequenceNumber); const answer = await answerRepository.findAnswer(question, sequenceNumber);
if (!answer){ if (!answer) {
throw new NotFoundException('Answer with questionID and sequence number not found'); throw new NotFoundException('Answer with questionID and sequence number not found');
} }

View file

@ -56,11 +56,11 @@ export async function deleteQuestion(questionId: QuestionId): Promise<QuestionDT
const questionRepository = getQuestionRepository(); const questionRepository = getQuestionRepository();
const question = await fetchQuestion(questionId); // Throws error if not found const question = await fetchQuestion(questionId); // Throws error if not found
const loId : LearningObjectIdentifier = { const loId: LearningObjectIdentifier = {
hruid: questionId.learningObjectIdentifier.hruid, hruid: questionId.learningObjectIdentifier.hruid,
language: questionId.learningObjectIdentifier.language, language: questionId.learningObjectIdentifier.language,
version: questionId.learningObjectIdentifier.version || FALLBACK_VERSION_NUM version: questionId.learningObjectIdentifier.version || FALLBACK_VERSION_NUM,
} };
await questionRepository.removeQuestionByLearningObjectAndSequenceNumber(loId, questionId.sequenceNumber); await questionRepository.removeQuestionByLearningObjectAndSequenceNumber(loId, questionId.sequenceNumber);
return mapToQuestionDTO(question); return mapToQuestionDTO(question);

View file

@ -1,10 +1,10 @@
import {Request, Response} from "express"; import { Request, Response } from 'express';
import {beforeAll, beforeEach, describe, expect, it, Mock, vi} from "vitest"; import { beforeAll, beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import {setupTestApp} from "../setup-tests"; import { setupTestApp } from '../setup-tests';
import {Language} from "@dwengo-1/common/util/language"; import { Language } from '@dwengo-1/common/util/language';
import {getAllAnswersHandler, getAnswerHandler, updateAnswerHandler} from "../../src/controllers/answers"; import { getAllAnswersHandler, getAnswerHandler, updateAnswerHandler } from '../../src/controllers/answers';
import {BadRequestException} from "../../src/exceptions/bad-request-exception"; import { BadRequestException } from '../../src/exceptions/bad-request-exception';
import {NotFoundException} from "../../src/exceptions/not-found-exception"; import { NotFoundException } from '../../src/exceptions/not-found-exception';
describe('Questions controllers', () => { describe('Questions controllers', () => {
let req: Partial<Request>; let req: Partial<Request>;
@ -25,12 +25,12 @@ describe('Questions controllers', () => {
it('Get answers list', async () => { it('Get answers list', async () => {
req = { req = {
params: {hruid: 'id05', version: '1', seq: '2'}, params: { hruid: 'id05', version: '1', seq: '2' },
query: {lang: Language.English, full: 'true'}, query: { lang: Language.English, full: 'true' },
}; };
await getAllAnswersHandler(req as Request, res as Response); await getAllAnswersHandler(req as Request, res as Response);
expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({answers: expect.anything()})); expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ answers: expect.anything() }));
const result = jsonMock.mock.lastCall?.[0]; const result = jsonMock.mock.lastCall?.[0];
// Console.log(result.answers); // Console.log(result.answers);
@ -39,12 +39,12 @@ describe('Questions controllers', () => {
it('Get answer', async () => { it('Get answer', async () => {
req = { req = {
params: {hruid: 'id05', version: '1', seq: '2', seqAnswer: '2'}, params: { hruid: 'id05', version: '1', seq: '2', seqAnswer: '2' },
query: {lang: Language.English, full: 'true'}, query: { lang: Language.English, full: 'true' },
}; };
await getAnswerHandler(req as Request, res as Response); await getAnswerHandler(req as Request, res as Response);
expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({answer: expect.anything()})); expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ answer: expect.anything() }));
// Const result = jsonMock.mock.lastCall?.[0]; // Const result = jsonMock.mock.lastCall?.[0];
// Console.log(result.answer); // Console.log(result.answer);
@ -52,13 +52,12 @@ describe('Questions controllers', () => {
it('Get answer hruid does not exist', async () => { it('Get answer hruid does not exist', async () => {
req = { req = {
params: { hruid: 'id_not_exist'}, params: { hruid: 'id_not_exist' },
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
await expect( async () => getAnswerHandler(req as Request, res as Response)) await expect(async () => getAnswerHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException);
.rejects.toThrow(NotFoundException); });
})
it('Get answer no hruid given', async () => { it('Get answer no hruid given', async () => {
req = { req = {
@ -66,16 +65,15 @@ describe('Questions controllers', () => {
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
await expect( async () => getAnswerHandler(req as Request, res as Response)) await expect(async () => getAnswerHandler(req as Request, res as Response)).rejects.toThrow(BadRequestException);
.rejects.toThrow(BadRequestException); });
})
it('Update question', async() => { it('Update question', async () => {
const newContent = "updated question"; const newContent = 'updated question';
req = { req = {
params: { hruid: 'id05', version: '1', seq: '2', seqAnswer: '2'}, params: { hruid: 'id05', version: '1', seq: '2', seqAnswer: '2' },
query: { lang: Language.English }, query: { lang: Language.English },
body: { content: newContent } body: { content: newContent },
}; };
await updateAnswerHandler(req as Request, res as Response); await updateAnswerHandler(req as Request, res as Response);
@ -86,5 +84,4 @@ describe('Questions controllers', () => {
// Console.log(result.question); // Console.log(result.question);
expect(result.answer.content).to.eq(newContent); expect(result.answer.content).to.eq(newContent);
}); });
}); });

View file

@ -1,14 +1,10 @@
import {beforeAll, beforeEach, describe, expect, it, Mock, vi} from "vitest"; import { beforeAll, beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import {Request, Response} from "express"; import { Request, Response } from 'express';
import {setupTestApp} from "../setup-tests"; import { setupTestApp } from '../setup-tests';
import { import { getAllQuestionsHandler, getQuestionHandler, updateQuestionHandler } from '../../src/controllers/questions';
getAllQuestionsHandler, import { Language } from '@dwengo-1/common/util/language';
getQuestionHandler, updateQuestionHandler import { NotFoundException } from '../../src/exceptions/not-found-exception';
} from "../../src/controllers/questions"; import { BadRequestException } from '../../src/exceptions/bad-request-exception';
import {Language} from "@dwengo-1/common/util/language";
import {NotFoundException} from "../../src/exceptions/not-found-exception";
import {BadRequestException} from "../../src/exceptions/bad-request-exception";
describe('Questions controllers', () => { describe('Questions controllers', () => {
let req: Partial<Request>; let req: Partial<Request>;
@ -43,7 +39,7 @@ describe('Questions controllers', () => {
it('Get question', async () => { it('Get question', async () => {
req = { req = {
params: { hruid: 'id05', version: '1', seq: '1'}, params: { hruid: 'id05', version: '1', seq: '1' },
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
@ -52,11 +48,11 @@ describe('Questions controllers', () => {
// Const result = jsonMock.mock.lastCall?.[0]; // Const result = jsonMock.mock.lastCall?.[0];
// Console.log(result.question); // Console.log(result.question);
}) });
it('Get question with fallback sequence number and version', async () => { it('Get question with fallback sequence number and version', async () => {
req = { req = {
params: { hruid: 'id05'}, params: { hruid: 'id05' },
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
@ -65,17 +61,16 @@ describe('Questions controllers', () => {
// Const result = jsonMock.mock.lastCall?.[0]; // Const result = jsonMock.mock.lastCall?.[0];
// Console.log(result.question); // Console.log(result.question);
}) });
it('Get question hruid does not exist', async () => { it('Get question hruid does not exist', async () => {
req = { req = {
params: { hruid: 'id_not_exist'}, params: { hruid: 'id_not_exist' },
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
await expect( async () => getQuestionHandler(req as Request, res as Response)) await expect(async () => getQuestionHandler(req as Request, res as Response)).rejects.toThrow(NotFoundException);
.rejects.toThrow(NotFoundException); });
})
it('Get question no hruid given', async () => { it('Get question no hruid given', async () => {
req = { req = {
@ -83,9 +78,8 @@ describe('Questions controllers', () => {
query: { lang: Language.English, full: 'true' }, query: { lang: Language.English, full: 'true' },
}; };
await expect( async () => getQuestionHandler(req as Request, res as Response)) await expect(async () => getQuestionHandler(req as Request, res as Response)).rejects.toThrow(BadRequestException);
.rejects.toThrow(BadRequestException); });
})
/* /*
It('Create and delete question', async() => { It('Create and delete question', async() => {
@ -104,12 +98,12 @@ describe('Questions controllers', () => {
*/ */
it('Update question', async() => { it('Update question', async () => {
const newContent = "updated question"; const newContent = 'updated question';
req = { req = {
params: { hruid: 'id05', version: '1', seq: '1'}, params: { hruid: 'id05', version: '1', seq: '1' },
query: { lang: Language.English }, query: { lang: Language.English },
body: { content: newContent } body: { content: newContent },
}; };
await updateQuestionHandler(req as Request, res as Response); await updateQuestionHandler(req as Request, res as Response);

View file

@ -1,40 +1,39 @@
import type {AnswerData, AnswerDTO, AnswerId} from "@dwengo-1/common/interfaces/answer"; import type { AnswerData, AnswerDTO, AnswerId } from "@dwengo-1/common/interfaces/answer";
import {BaseController} from "@/controllers/base-controller.ts"; import { BaseController } from "@/controllers/base-controller.ts";
import type {QuestionId} from "@dwengo-1/common/interfaces/question"; import type { QuestionId } from "@dwengo-1/common/interfaces/question";
export interface AnswersResponse { export interface AnswersResponse {
answers: AnswerDTO[] | AnswerId[] answers: AnswerDTO[] | AnswerId[];
} }
export interface AnswerResponse { export interface AnswerResponse {
answer: AnswerDTO answer: AnswerDTO;
} }
export class AnswerController extends BaseController { export class AnswerController extends BaseController {
constructor(questionId: QuestionId) { constructor(questionId: QuestionId) {
this.loId = questionId.learningObjectIdentifier; this.loId = questionId.learningObjectIdentifier;
this.sequenceNumber = questionId.sequenceNumber; this.sequenceNumber = questionId.sequenceNumber;
super(`learningObject/${loId.hruid}/:${loId.version}/questions/${this.sequenceNumber}/answers`) super(`learningObject/${loId.hruid}/:${loId.version}/questions/${this.sequenceNumber}/answers`);
} }
async getAll(full = true): Promise<AnswersResponse> { async getAll(full = true): Promise<AnswersResponse> {
return this.get<AnswersResponse>("/", {lang: this.loId.lang, full}); return this.get<AnswersResponse>("/", { lang: this.loId.lang, full });
} }
async getBy(seq: number): Promise<AnswerResponse> { async getBy(seq: number): Promise<AnswerResponse> {
return this.get<AnswerResponse>(`/${seq}`, {lang: this.loId.lang}); return this.get<AnswerResponse>(`/${seq}`, { lang: this.loId.lang });
} }
async create(answerData: AnswerData): Promise<AnswerResponse> { async create(answerData: AnswerData): Promise<AnswerResponse> {
return this.post<AnswerResponse>("/", answerData, {lang: this.loId.lang}); return this.post<AnswerResponse>("/", answerData, { lang: this.loId.lang });
} }
async remove(seq: number): Promise<AnswerResponse> { async remove(seq: number): Promise<AnswerResponse> {
return this.delete<AnswerResponse>(`/${seq}`, {lang: this.loId.lang}); return this.delete<AnswerResponse>(`/${seq}`, { lang: this.loId.lang });
} }
async update(seq: number, answerData: AnswerData): Promise<AnswerResponse> { async update(seq: number, answerData: AnswerData): Promise<AnswerResponse> {
return this.put<AnswerResponse>(`/${seq}`, answerData,{lang: this.loId.lang}); return this.put<AnswerResponse>(`/${seq}`, answerData, { lang: this.loId.lang });
} }
} }

View file

@ -28,13 +28,13 @@ export abstract class BaseController {
} }
protected async delete<T>(path: string, queryParams?: QueryParams): Promise<T> { protected async delete<T>(path: string, queryParams?: QueryParams): Promise<T> {
const response = await apiClient.delete<T>(this.absolutePathFor(path), { params: queryParams} ); const response = await apiClient.delete<T>(this.absolutePathFor(path), { params: queryParams });
BaseController.assertSuccessResponse(response); BaseController.assertSuccessResponse(response);
return response.data; return response.data;
} }
protected async put<T>(path: string, body: unknown, queryParams?: QueryParams): Promise<T> { protected async put<T>(path: string, body: unknown, queryParams?: QueryParams): Promise<T> {
const response = await apiClient.put<T>(this.absolutePathFor(path), body, { params: queryParams}); const response = await apiClient.put<T>(this.absolutePathFor(path), body, { params: queryParams });
BaseController.assertSuccessResponse(response); BaseController.assertSuccessResponse(response);
return response.data; return response.data;
} }

View file

@ -1,6 +1,6 @@
import type {QuestionData, QuestionDTO, QuestionId} from "@dwengo-1/common/interfaces/question"; import type { QuestionData, QuestionDTO, QuestionId } from "@dwengo-1/common/interfaces/question";
import {BaseController} from "@/controllers/base-controller.ts"; import { BaseController } from "@/controllers/base-controller.ts";
import type {LearningObjectIdentifierDTO} from "@dwengo-1/common/interfaces/learning-content"; import type { LearningObjectIdentifierDTO } from "@dwengo-1/common/interfaces/learning-content";
export interface QuestionsResponse { export interface QuestionsResponse {
questions: QuestionDTO[] | QuestionId[]; questions: QuestionDTO[] | QuestionId[];
@ -17,22 +17,22 @@ export class QuestionController extends BaseController {
} }
async getAll(full = true): Promise<QuestionsResponse> { async getAll(full = true): Promise<QuestionsResponse> {
return this.get<QuestionsResponse>("/", {lang: this.loId.lang, full}); return this.get<QuestionsResponse>("/", { lang: this.loId.lang, full });
} }
async getBy(sequenceNumber: number): Promise<QuestionResponse> { async getBy(sequenceNumber: number): Promise<QuestionResponse> {
return this.get<QuestionResponse>(`/${sequenceNumber}`, {lang: this.loId.lang}); return this.get<QuestionResponse>(`/${sequenceNumber}`, { lang: this.loId.lang });
} }
async create(questionData: QuestionData): Promise<QuestionResponse> { async create(questionData: QuestionData): Promise<QuestionResponse> {
return this.post<QuestionResponse>("/", questionData, {lang: this.loId.lang}) return this.post<QuestionResponse>("/", questionData, { lang: this.loId.lang });
} }
async remove(sequenceNumber: number): Promise<QuestionResponse> { async remove(sequenceNumber: number): Promise<QuestionResponse> {
return this.delete<QuestionResponse>(`/${sequenceNumber}`, {lang: this.loId.lang}); return this.delete<QuestionResponse>(`/${sequenceNumber}`, { lang: this.loId.lang });
} }
async update(sequenceNumber: number, questionData: QuestionData): Promise<QuestionResponse> { async update(sequenceNumber: number, questionData: QuestionData): Promise<QuestionResponse> {
return this.put<QuestionResponse>(`/${sequenceNumber}`, questionData, {lang: this.loId.lang}); return this.put<QuestionResponse>(`/${sequenceNumber}`, questionData, { lang: this.loId.lang });
} }
} }

View file

@ -1,13 +1,8 @@
import type { QuestionId} from "@dwengo-1/common/dist/interfaces/question.ts"; import type { QuestionId } from "@dwengo-1/common/dist/interfaces/question.ts";
import { type MaybeRefOrGetter, toValue} from "vue"; import { type MaybeRefOrGetter, toValue } from "vue";
import { import { useMutation, type UseMutationReturnType, useQuery, type UseQueryReturnType } from "@tanstack/vue-query";
useMutation, import { AnswerController, type AnswerResponse, type AnswersResponse } from "@/controllers/answers.ts";
type UseMutationReturnType, import type { AnswerData } from "@dwengo-1/common/dist/interfaces/answer.ts";
useQuery,
type UseQueryReturnType
} from "@tanstack/vue-query";
import {AnswerController, type AnswerResponse, type AnswersResponse} from "@/controllers/answers.ts";
import type {AnswerData} from "@dwengo-1/common/dist/interfaces/answer.ts";
// TODO caching // TODO caching
@ -23,7 +18,7 @@ export function useAnswersQuery(
export function useAnswerQuery( export function useAnswerQuery(
questionId: MaybeRefOrGetter<QuestionId>, questionId: MaybeRefOrGetter<QuestionId>,
sequenceNumber: MaybeRefOrGetter<number> sequenceNumber: MaybeRefOrGetter<number>,
): UseQueryReturnType<AnswerResponse, Error> { ): UseQueryReturnType<AnswerResponse, Error> {
return useQuery({ return useQuery({
queryFn: async () => new AnswerController(toValue(questionId)).getBy(toValue(sequenceNumber)), queryFn: async () => new AnswerController(toValue(questionId)).getBy(toValue(sequenceNumber)),
@ -49,9 +44,8 @@ export function useDeleteAnswerMutation(
export function useUpdateAnswerMutation( export function useUpdateAnswerMutation(
questionId: MaybeRefOrGetter<QuestionId>, questionId: MaybeRefOrGetter<QuestionId>,
): UseMutationReturnType<AnswerResponse, Error, { answerData: AnswerData, seq: number }, unknown> { ): UseMutationReturnType<AnswerResponse, Error, { answerData: AnswerData; seq: number }, unknown> {
return useMutation({ return useMutation({
mutationFn: async (data, seq) => new AnswerController(toValue(questionId)).update(seq, data), mutationFn: async (data, seq) => new AnswerController(toValue(questionId)).update(seq, data),
}); });
} }

View file

@ -1,17 +1,19 @@
import {QuestionController, type QuestionResponse, type QuestionsResponse} from "@/controllers/questions.ts"; import { QuestionController, type QuestionResponse, type QuestionsResponse } from "@/controllers/questions.ts";
import type {QuestionData, QuestionId} from "@dwengo-1/common/interfaces/question"; import type { QuestionData, QuestionId } from "@dwengo-1/common/interfaces/question";
import type {LearningObjectIdentifierDTO} from "@dwengo-1/common/interfaces/learning-content"; import type { LearningObjectIdentifierDTO } from "@dwengo-1/common/interfaces/learning-content";
import {computed, type MaybeRefOrGetter, toValue} from "vue"; import { computed, type MaybeRefOrGetter, toValue } from "vue";
import { import {
useMutation, useMutation,
type UseMutationReturnType, type UseMutationReturnType,
useQuery, useQuery,
useQueryClient, useQueryClient,
type UseQueryReturnType type UseQueryReturnType,
} from "@tanstack/vue-query"; } from "@tanstack/vue-query";
export function questionsQueryKey(
export function questionsQueryKey(loId: LearningObjectIdentifierDTO, full: boolean): [string, string, number, string, boolean] { loId: LearningObjectIdentifierDTO,
full: boolean,
): [string, string, number, string, boolean] {
return ["questions", loId.hruid, loId.version, loId.language, full]; return ["questions", loId.hruid, loId.version, loId.language, full];
} }
@ -65,7 +67,7 @@ export function useUpdateQuestionMutation(
const sequenceNumber = toValue(questionId).sequenceNumber; const sequenceNumber = toValue(questionId).sequenceNumber;
return useMutation({ return useMutation({
mutationFn: async ( data ) => new QuestionController(loId).update(sequenceNumber, data), mutationFn: async (data) => new QuestionController(loId).update(sequenceNumber, data),
onSuccess: async () => { onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) }); await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) });
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) }); await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) });