Search code examples
typescriptnestdependency-management

Nest can't resolve model dependency


I ran into a error where nest can't resolve dependencies. I am getting the following error from logger:

[Nest] 39472  - 17.08.2023, 05:45:34   ERROR [ExceptionHandler] Nest can't resolve dependencies of the UserTransactionRepository (?). Please make sure that the argument UserTransactionRepository at index [0] is available in the WalletModule context.

Potential solutions:
- Is WalletModule a valid NestJS module?
- If UserTransactionRepository is a provider, is it part of the current WalletModule?     
- If UserTransactionRepository is exported from a separate @Module, is that module imported within WalletModule?
  @Module({
    imports: [ /* the Module containing UserTransactionRepository */ ]
  })

Error: Nest can't resolve dependencies of the UserTransactionRepository (?). Please make sure that the argument UserTransactionRepository at index [0] is available in the WalletModule context.

Potential solutions:
- Is WalletModule a valid NestJS module?
- If UserTransactionRepository is a provider, is it part of the current WalletModule?     
- If UserTransactionRepository is exported from a separate @Module, is that module imported within WalletModule?
  @Module({
    imports: [ /* the Module containing UserTransactionRepository */ ]
  })

    at Injector.lookupComponentInParentModules (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:254:19)  
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at Injector.resolveComponentInstance (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:207:33)        
    at resolveParam (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:128:38)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:143:27)        
    at Injector.loadInstance (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:70:13)
    at Injector.loadProvider (C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\injector.js:97:9)
    at C:\Users\v.aleshchenko\Documents\GMDEV System\external\mock-operator-wallet\node_modules\@nestjs\core\injector\instance-loader.js:56:13
    at async Promise.all (index 5)

I have the following folder structure, respectively, there are two modules that are imported into the app.module.

enter image description here

rom the error, I see that Nest cannot resolve the dependency in the UserTransactionRepository class. If you remove the dependency from the constructor and make the functionality without it, then everything works. Here is the transaction repository file:

import { Injectable } from '@nestjs/common';
import { UserTransaction } from '../models/transaction.model';
import { DOMAIN_MODEL_ERROR_CODE } from 'src/common/enums/domain-model-error.enum';
import { DomainModelError } from 'src/common/exceptions/domain-model.exception';
import { TRANSACTION_OPERATION } from '../enums/transaction-operation.enum';
import { TRANSACTION_STATUS } from '../enums/transaction-status.enum';
import { InjectModel } from '@nestjs/sequelize';

interface ITransactionResponce {
  userId: string;
  transactionId: string;
  amount: string;
  operation: string;
  status: string;
  finished: string;
}

@Injectable()
export class UserTransactionRepository {
  constructor(
    @InjectModel(UserTransaction)
    private readonly transactionModel: typeof UserTransaction,
  ) {}

  async saveTransaction(
    userId: string,
    transactionId: string,
    amount: string,
    // ): Promise<ITransactionResponce> {
  ): Promise<any> {
    try {
      const query = {
        userId,
        transactionId,
        amount,
        operation: TRANSACTION_OPERATION.DEPOSIT,
        status: TRANSACTION_STATUS.SUCCESS,
        finished: true,
      };
      const res = this.transactionModel.create<UserTransaction>(query);
      console.log(res);
      return res;
    } catch (error) {
      if (error.code === DOMAIN_MODEL_ERROR_CODE.NOT_FOUND) {
        throw new DomainModelError({
          message: error.message,
          code: DOMAIN_MODEL_ERROR_CODE.TRANSACTION_NOT_FOUND,
        });
      }

      throw error;
    }
  }
}

Modules look like this:

import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { User } from './models/user.model';
import { UserSessionRepository } from './repositories/user-session.repository';
import { UserSession } from './models/user-session.model';

@Module({
  imports: [SequelizeModule.forFeature([User, UserSession])],
  providers: [UserSessionRepository],
  exports: [UserSessionRepository],
})
export class UserModule {}
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { Wallet } from './models/wallet.model';
import { WalletRepository } from './repositories/wallet.repository';
import { WalletController } from './wallet.controller';
import { GetUserBalanceUseCase } from './usecases/get-user-balance.usecase';
import { UserModule } from '../user/user.module';
import { UseCaseRunnerService } from '../common/services/usecase-runner.service';
import { DepositUseCase } from './usecases/deposit.usecase';
import { UserTransactionRepository } from './repositories/transaction.repository';

@Module({
  imports: [SequelizeModule.forFeature([Wallet]), UserModule],
  providers: [
    UseCaseRunnerService,
    WalletRepository,
    UserTransactionRepository,
    GetUserBalanceUseCase,
    DepositUseCase,
  ],
  controllers: [WalletController],
})
export class WalletModule {}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from './database/database.module';
import { WalletModule } from './wallet/wallet.module';
import { UserModule } from './user/user.module';
import config from './config/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [config],
    }),
    DatabaseModule,
    WalletModule,
    UserModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

How can I get rid of this error?

As I found out the problem is in the transaction repository file. But I don’t understand what’s wrong with it, since there is only one dependency per model with which you need to work in the repository.

Transaction model

import {
  AllowNull,
  BelongsTo,
  Column,
  CreatedAt,
  DataType,
  Default,
  ForeignKey,
  PrimaryKey,
  Table,
  UpdatedAt,
} from 'sequelize-typescript';

import { BaseModel } from '../../common/models/base-model';

import { User } from '../../user/models/user.model';
import { TRANSACTION_STATUS } from 'src/wallet/enums/transaction-status.enum';
import { TRANSACTION_OPERATION } from 'src/wallet/enums/transaction-operation.enum';
import { Wallet } from './wallet.model';

export interface ITransaction {
  id: string;
  userId: string;
  walletId: string;
  amount: string;
  operation: TRANSACTION_OPERATION;
  status: TRANSACTION_STATUS;
  createdAt?: Date;
  updatedAt?: Date;
}

@Table({
  tableName: 'transactions',
  timestamps: false,
})
export class UserTransaction extends BaseModel<ITransaction> {
  @PrimaryKey
  @AllowNull(false)
  @Default(DataType.UUIDV4)
  @Column(DataType.UUID)
  id: string;

  @ForeignKey(() => User)
  @AllowNull(false)
  @Column({ type: DataType.UUID, field: 'user_id' })
  userId: string;

  @BelongsTo(() => User)
  user: User;

  @ForeignKey(() => Wallet)
  @AllowNull(false)
  @Column({ type: DataType.UUID, field: 'wallet_id' })
  walletId: string;

  @BelongsTo(() => Wallet)
  wallet: Wallet;

  @AllowNull(false)
  @Default('0')
  @Column(DataType.STRING)
  amount: string;

  @AllowNull(false)
  @Column(DataType.STRING)
  operation: TRANSACTION_OPERATION;

  @AllowNull(false)
  @Column(DataType.STRING)
  status: TRANSACTION_STATUS;

  @CreatedAt
  @AllowNull(false)
  @Default(DataType.NOW())
  @Column({ type: DataType.DATE, field: 'created_at' })
  createdAt: Date;

  @UpdatedAt
  @AllowNull(false)
  @Default(DataType.NOW())
  @Column({ type: DataType.DATE, field: 'updated_at' })
  updatedAt: Date;
}

Solution

  • So, I resolved my problem. The error was that I didn't add the model to the sequelize module:

    @Module({
      imports: [SequelizeModule.forFeature([Wallet, UserTransaction]), UserModule],
      providers: [
        UseCaseRunnerService,
        UserTransactionRepository,
        WalletRepository,
        GetUserBalanceUseCase,
        DepositUseCase,
      ],
      controllers: [WalletController],
    })