How to solve circular dependency issue with NestJs and Mongodb?

457 Views Asked by At

I am try trying to implement unit test code for my nestjs application but I keep getting this error.

A circular dependency has been detected inside RootTestModule. Please, make sure that each side of a bidirectional relationships are decorated with "forwardRef()".

I checked my service and controller file but could not find any issue with it.

Service file

import { Injectable, NotFoundException } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { Grocery, GroceryDocument } from './schemas/grocery-list.schema';


@Injectable()
export class GroceryService {
  constructor(
    @InjectModel('GroceryService')
    private readonly groceryModel: Model<GroceryDocument>,
  ) {}

  // Create new Grocery Record
  async create(
    item: string,
    category: string,
    quantity: number,
  ): Promise<Grocery> {
    const newGrocery = new this.groceryModel({
      // userId: uuidv4(),
      item,
      category,
      quantity,
    });
    const result = await newGrocery.save();
    return new Grocery(result.item, result.category, result.quantity);
    // return await this.groceryModel.create({
    //   userId: uuidv4(),
    //   item,
    //   category,
    //   quantity,
    // });
    // return newGrocery.save();
  }

  // Read all Grocery Records
  async readAll(): Promise<Grocery[]> {
    const groceryList: Grocery[] = await this.groceryModel.find().exec();
    if (!groceryList) {
      throw new NotFoundException('No records found!');
    }
    return groceryList;
  }

  async readById(id): Promise<Grocery> {
    try {
      const specifiedGrocery = await this.groceryModel.findById(id).exec();
      return specifiedGrocery;
    } catch (err) {
      throw new NotFoundException('Invalid ID provided');
    }
  }

  async update(id, grocery: Grocery): Promise<Grocery> {
    try {
      const specifiedGrocery = await this.groceryModel.findByIdAndUpdate(
        id,
        grocery,
        {
          new: true,
        },
      );
      return specifiedGrocery;
    } catch (err) {
      throw new NotFoundException('Invalid ID provided');
    }
  }

  async delete(id): Promise<any> {
    try {
      const specifiedGrocery = await this.groceryModel.findByIdAndRemove(id);
      if (!specifiedGrocery) {
        throw new NotFoundException('Grocery with given ID does not exist');
      }
      // return specifiedGrocery;
    } catch (err) {
      throw new NotFoundException('Invalid ID provided');
    }
  }
}

Controller file

import {
  Body,
  Controller,
  Delete,
  Get,
  HttpStatus,
  NotFoundException,
  Param,
  Post,
  Put,
  Res,
} from '@nestjs/common';
import {
  ApiBadRequestResponse,
  ApiBody,
  ApiCreatedResponse,
  ApiOkResponse,
  ApiOperation,
  ApiParam,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { GroceryService } from './grocery-list.service';
// import { Grocery } from './schemas/grocery-list.schema';

import { UpdateGroceryDto } from './dto/update-grocery.dto';
import { CreateGroceryDto } from './dto/create-grocery.dto';

@ApiTags('grocery-list')
@Controller('grocery-list')
export class GroceryListController {
  constructor(private readonly groceryService: GroceryService) {}

  // GET all groceries
  @Get()
  @ApiOperation({ summary: 'Get all the data from this api' })
  @ApiOkResponse({
    status: 200,
    description: `List of Groceries`,
    type: [CreateGroceryDto],
  })
  @ApiResponse({
    status: 500,
    description: `Internal Server Error`,
  })
  @ApiBadRequestResponse()
  async fetchAll(@Res() response) {
    const groceries = await this.groceryService.readAll();
    return response.status(HttpStatus.OK).json({
      groceries,
    });
  }

  // GET a specific grocery
  @Get('/:id')
  @ApiOperation({
    summary: 'Get a particular data with given ID from this api',
  })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'enter unique id',
    required: true,
  })
  @ApiOkResponse({
    status: 200,
    description: `Get a unique ID from the groceries list`,
    type: CreateGroceryDto,
  })
  @ApiResponse({
    status: 500,
    description: `Internal Server Error`,
  })
  @ApiBadRequestResponse()
  async findById(@Res() response, @Param('id') id) {
    const grocery = await this.groceryService.readById(id);
    return response.status(HttpStatus.OK).json({
      grocery,
    });
  }

  // POST operation
  @Post()
  @ApiOperation({ summary: `create new record` })
  @ApiCreatedResponse({
    status: 201,
    description: `Added new grocery record`,
    type: CreateGroceryDto,
  })
  @ApiResponse({
    status: 500,
    description: `Internal Server Error`,
  })
  @ApiBadRequestResponse()
  async createGrocery(@Res() response, @Body() grocery: CreateGroceryDto) {
    const newGrocery = await this.groceryService.create(
      grocery.item,
      grocery.category,
      grocery.quantity,
    );
    console.log(newGrocery);
    return response.status(HttpStatus.CREATED).json({
      newGrocery,
    });
  }

  // PUT operation
  @Put('/:id')
  @ApiOperation({ summary: 'Update a single Id from this api' })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'enter unique id',
    required: true,
  })
  @ApiCreatedResponse({
    status: 201,
    description: `Updated existing grocery record`,
    type: CreateGroceryDto,
  })
  @ApiResponse({
    status: 403,
    description: `Forbidden`,
  })
  @ApiResponse({
    status: 500,
    description: `Internal Server Error`,
  })
  @ApiBadRequestResponse()
  async update(
    @Res() response,
    @Param('id') id,
    @Body() grocery: CreateGroceryDto,
  ) {
    const updatedGrocery = await this.groceryService.update(id, grocery);
    if (!updatedGrocery) {
      throw new NotFoundException('id not found');
    }
    return response.status(HttpStatus.OK).json({
      updatedGrocery,
    });
  }

  // DELETE operation
  @Delete('/:id')
  @ApiOperation({ summary: 'Delete a single Id from this api' })
  @ApiParam({
    name: 'id',
    type: 'string',
    description: 'enter unique id',
    required: true,
  })
  @ApiOkResponse({
    status: 200,
    description: `Delete a grocery record with provided ID`,
    type: UpdateGroceryDto,
  })
  @ApiResponse({
    status: 403,
    description: `Forbidden`,
  })
  @ApiResponse({
    status: 500,
    description: `Internal Server Error`,
  })
  @ApiBadRequestResponse()
  async delete(@Res() response, @Param('id') id) {
    const deletedGrocery = await this.groceryService.delete(id);
    return response.status(HttpStatus.OK).json({
      deletedGrocery,
    });
  }
}

Module file

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { GroceryListController } from './grocery-list.controller';
import { GroceryModel } from './schemas/grocery-list.schema';
import { GroceryService } from './grocery-list.service';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: 'GroceryService', schema: GroceryModel }]),
  ],
  controllers: [GroceryListController],
  providers: [GroceryService],
})
export class GroceryListModule {}
0

There are 0 best solutions below