nestjstypeormrepository-patternnestjs-typeorm

NestJS Repository gives error 'No metadata for "TaskRepository" was found.'


GitHub link to project: nestjs-task-management

Error Log:

[Nest] 15824  - 23/08/2023, 11:22:29     LOG [NestFactory] Starting Nest application...
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [InstanceLoader] AppModule dependencies initialized +115ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [InstanceLoader] TypeOrmModule dependencies initialized +1ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [InstanceLoader] TypeOrmCoreModule dependencies initialized +182ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [InstanceLoader] TypeOrmModule dependencies initialized +1ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [InstanceLoader] TasksModule dependencies initialized +2ms  
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [RoutesResolver] TasksController {/tasks}: +28ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [RouterExplorer] Mapped {/tasks/:id, GET} route +5ms
[Nest] 15824  - 23/08/2023, 11:22:29     LOG [NestApplication] Nest application successfully started +4ms
[Nest] 15824  - 23/08/2023, 12:03:53   ERROR [ExceptionsHandler] No metadata for "TaskRepository" was found.
EntityMetadataNotFoundError: No metadata for "TaskRepository" was found.
    at DataSource.getMetadata (D:\SaifAli\NestJS Demo Projects\nestjs-task-management\src\data-source\DataSource.ts:444:30)
    at Repository.get metadata [as metadata] (D:\SaifAli\NestJS Demo Projects\nestjs-task-management\src\repository\Repository.ts:53:40)
    at Repository.findOne (D:\SaifAli\NestJS Demo Projects\nestjs-task-management\src\repository\Repository.ts:577:42)
    at TasksService.getTaskById (D:\SaifAli\NestJS Demo Projects\nestjs-task-management\src\tasks\tasks.service.ts:37:50)
    at TasksController.getTaskById (D:\SaifAli\NestJS Demo Projects\nestjs-task-management\src\tasks\tasks.controller.ts:24:30)
    at D:\SaifAli\NestJS Demo Projects\nestjs-task-management\node_modules\@nestjs\core\router\router-execution-context.js:38:29
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at D:\SaifAli\NestJS Demo Projects\nestjs-task-management\node_modules\@nestjs\core\router\router-execution-context.js:46:28
    at D:\SaifAli\NestJS Demo Projects\nestjs-task-management\node_modules\@nestjs\core\router\router-proxy.js:9:17

Modules:

    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/typeorm": "^10.0.0",
    "typeorm": "^0.3.17"

typeorm.config.ts:

import { TypeOrmModuleOptions } from "@nestjs/typeorm";

export const typeOrmConfig: TypeOrmModuleOptions = {
    type: 'postgres',
    host: 'localhost',
    port: 5432,
    username: 'postgres',
    password: 'root',
    database: 'taskmanagement',
    entities: [__dirname + '/../**/*.entity.{js,ts}'],
    synchronize: true,
};

tasks.module.ts:

import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';
import { TasksController } from './tasks.controller';
import { TasksService } from './tasks.service';
import { TaskRepository } from './task.repository';

@Module({
  imports: [TypeOrmModule.forFeature([TaskRepository])],
  controllers: [TasksController],
  providers: [TasksService],
})
export class TasksModule {}

task.entity.ts:

import { TaskStatus } from "./task-status.enum";
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class Task {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;

    @Column()
    status: TaskStatus;
}

task.repository.ts:

import { Repository } from 'typeorm';
import { Task } from './task.entity';

export class TaskRepository extends Repository<Task> {
  // Your custom repository methods can go here
}

tasks.service.ts:

import { TaskRepository } from './task.repository';
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Task } from './task.entity';

@Injectable()
export class TasksService {
    constructor(
        @InjectRepository(TaskRepository)
        private taskRepository: TaskRepository,
    ) {};
    async getTaskById(id: number): Promise<Task> {
        const record = await this.taskRepository.findOne({ where: { id } });
        if (!record) {
            throw new NotFoundException();
        }
        return record;
    }
}

I tried using an older version of TypeORM but that was introducing new errors and I want to learn doing this using the up-to-date methods.

I only get this error when I hit the endpoint using Postman and I have been trying to fix this since yesterday and was unable to find any similar issues. One was to use entities: [__dirname + '/../**/*.entity.{js,ts}'], in the typeorm config file where I was using autoLoadEntities: true instead so I tried that too but didn't change anything.

I don't understand where and how I have to provide metadata to the repository.

I thank you guys in advance for any help here.


Solution

  • The below code is incorrect. Instead of TaskRepository, it needs to be Task (from task.entity.ts)

    @Module({
      imports: [TypeOrmModule.forFeature([TaskRepository])],
      controllers: [TasksController],
      providers: [TasksService],
    })
    export class TasksModule {}
    

    So to fix this, you need to change this to:

    import { Task } from './task.entity';
    
    @Module({
      imports: [TypeOrmModule.forFeature([Task])],
      controllers: [TasksController],
      providers: [TasksService],
    })
    export class TasksModule {}
    

    Your second issue is how you instantiated the repository with TaskService.

    @Injectable()
    export class TasksService {
        constructor(
            @InjectRepository(TaskRepository)
            private taskRepository: TaskRepository,
        ) {};
    }
    

    You need to use Task here as well, instead of TaskRepository.

    import { MongoRepository } from 'typeorm'
    
    import { Task } from './task.entity'
    
    @Injectable()
    export class TasksService {
        constructor(
            @InjectRepository(Task)
            private taskRepository: MongoRepository<Task>,
        ) {};
    }
    

    Now, you don't even need a class called TaskRepository.