I am trying to record a question on a prisma model. The model is defined as following:
model QuestionRecord {
id String @id
institution String
title String
imagepath String
alternatives String
subject String
topic String
year Int
StudentQuestionRecord StudentQuestionRecord[]
}
To make any record on that model, I use the following class and its typing:
import { randomUUID } from "crypto";
export interface QuestionEntity {
id: string,
year: number,
title: string,
topic: string,
subject: string,
imagepath: string,
institution: string,
alternatives: string,
};
export class Question {
public _id: string;
public props: Omit<QuestionEntity, 'id'>;
constructor(props: Omit<QuestionEntity, 'id'>, id?: string) {
this._id = id ?? randomUUID();
this.props = props;
}
public get id() {
return this._id;
}
public get title() {
return this.props.title;
}
public set title(newQuestionTitle) {
this.props.title = newQuestionTitle;
}
public get topic() {
return this.props.topic;
}
public set topic(newQuestionTopic) {
this.props.topic = newQuestionTopic;
}
public get subject() {
return this.props.subject;
}
public set subject(newQuestionSubject) {
this.props.subject = newQuestionSubject;
}
public get year() {
return this.props.year;
}
public set year(newYear) {
this.props.year = newYear
}
public get institution() {
return this.props.institution;
}
public set institution(newInstitution) {
this.props.institution = newInstitution;
}
public get alternatives() {
return this.props.alternatives;
}
public set alternatives(newAlternatives) {
this.props.alternatives = newAlternatives;
}
public get imagepath() {
return this.props.imagepath;
}
public set imagepath(newImage) {
this.props.imagepath = newImage;
}
}
Finally, I have this route that allows one to request the creation of a question:
@Post('create/question')
async createQuestionView(@Body() body: CreateQuestionBody) {
const {id, year, title, topic, subject, imagepath, institution, alternatives } = body;
const { question } = await this.createQuestion.execute({
id,
year,
title,
topic,
subject,
imagepath,
institution,
alternatives
});
return {question: QuestionViewModel.toHTTP(question)};
}
By the way, here's other snippets that may be helpful in the troubleshooting, as suggested by Shea. Here is how execute method was written:
interface CreateQuestionResponse {
question: Question;
}
@Injectable()
export class CreateQuestion {
constructor(private questionRepository: QuestionRepository) {}
async execute(request: QuestionEntity): Promise<CreateQuestionResponse> {
const {
institution, subject, topic, title,
year, alternatives, imagepath
} = request;
const question = new Question({
alternatives,
institution,
imagepath,
subject,
topic,
title,
year,
});
await this.questionRepository.create(question)
return { question };
}
}
Here is how PrismaQuestionRepository
was written:
export class PrismaQuestionRepository implements QuestionRepository {
constructor(private prisma: PrismaService) {}
async create(question: QuestionEntity): Promise<void> {
const raw = PrismaQuestionMappper.toPrisma(question);
await this.prisma.questionRecord.create({
data: raw,
})
}
async findQuestionById(questionId: string): Promise<QuestionEntity | null> {
const question = await this.prisma.questionRecord.findUnique({
where: {
id: questionId,
}
});
if (!question) return null;
return PrismaQuestionMappper.toDomain(question);
}
async findQuestionsByYear(year: number): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
year: year,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
async findQuestionsByTitle(title: string): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
title: title,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
async findQuestionsByTopic(topic: string): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
topic: topic,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
async findQuestionsBySubject(subject: string): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
subject: subject,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
async findQuestionsByInstitution(institution: string): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
institution: institution,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
async findQuestionsBySubjectAndTopic(subject: string, topic: string): Promise<QuestionEntity[] | null> {
const questions = await this.prisma.questionRecord.findMany({
where: {
subject: subject,
topic: topic,
}
});
if (!questions) return null;
return questions.map(PrismaQuestionMappper.toDomain);
}
}
Here is how mapper was written:
export class PrismaQuestionMappper {
static toPrisma(question: QuestionEntity) {
return {
id: question.id,
year: question.year,
title: question.title,
topic: question.topic,
subject: question.subject,
imagepath: question.imagepath,
institution: question.institution,
alternatives: question.alternatives,
};
};
static toDomain(raw: QuestionEntity) {
return new Question({
year: raw.year,
title: raw.title,
topic: raw.topic,
subject: raw.subject,
imagepath: raw.imagepath,
institution: raw.institution,
alternatives: raw.alternatives,
});
};
};
My application runs quite well, until I try to record a question. Whenever I try to, passing in all necessary fields, I got this error:
[Nest] 13784 - 03/01/2023, 09:00:47 ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'questionRecord')
TypeError: Cannot read properties of undefined (reading 'questionRecord')
at PrismaQuestionRepository.create (/home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/src/infra/database/prisma/repositories/prisma.question.repository.ts:12:27)
at CreateQuestion.execute (/home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/src/app/use-cases/question/create.question.ts:29:39)
at AppController.createQuestionView (/home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/src/infra/http/controllers/app.controller.ts:52:52)
at /home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/node_modules/@nestjs/core/router/router-execution-context.js:38:29
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at /home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/node_modules/@nestjs/core/router/router-execution-context.js:46:28
at /home/famialiaaes/Documents/Estudos/NestJs/student-microservice/student/node_modules/@nestjs/core/router/router-proxy.js:9:17
I know that this error occurs when a supposed property of an undefined thing is called. So I re-read all my code and refactor it in some snippets, as well I pocked around with it in order to see what can have been evaluated as undefined but could not dilute the problem yet. I hope someone can help me out with, pointing out some nuance that failed to see. Thanks in advance!
Issue solved: as PrismaQuestionRepository
is a class that is part of the nestjs module, on top of it I should have put an @Injectable decorator, what I haven't since now. After doing this, the problem disappeared.
CodePudding user response:
It looks like this.prisma
is undefined when you attempt to run this.prisma.questionRecord.create
. When you instantiate PrismaQuestionRepository
, you have to pass in prisma
(looking at its constructor.) Make sure you are properly instantiating PrismaQuestionRepository
, which seems to be the root of your error.