i've been using sequelize-typescript, tsyringe on a refactor work here and i got a pretty interesting bug here. Well normally all of my repository containers is being registered normally and instanced properly with the follow settings:

  • i import the reflect metadata on the root of my application and the tsyringe container after it

    import 'reflect-metadata';
    import 'dotenv/config';
    import express, { Request, Response, NextFunction } from 'express';
    ...
    import '@shared/infra/sequelize/index'; // default sequelize connection
    import '@shared/container/index';
    
  • Inside of container/index is the following code, im using sequelize-typescript to craft the repositories.

    
    import { container } from 'tsyringe';
    
    import IUsersRepository from '@modules/users/repositories/IUsersRepositories';
    import UsersRepository from '@modules/users/infra/sequelize/repositories/UserRepository';
    ...
    import IModelRepository from '@modules/model/repositories/IModelRepository';
    import ModelRepository from '@modules/model/infra/sequelize/repositories/ModelRepository';
    
    container.registerSingleton<IUsersRepository>(
      'UsersRepository',
      UsersRepository,
    );
    ...
    container.registerSingleton<IModelRepository>(
      'ModelRepository',
      ModelRepository,
    );
    
  • then i do all of the routering with express:

    import { Router } from 'express';
    import bdDecider from '@shared/infra/http/middlewares/bdDecider';
    import ensureAuthenticated from '@modules/users/infra/http/middlewares/EnsureAuthenticated';
    import UserRouter from '@modules/users/infra/http/routes/user.routes';
    ...
    import ModelRouter from '@modules/model/infra/http/routes/model.routes';
    
    const routes = Router();
    
    routes.use('/sessions', SessionRouter);
    routes.use(ensureAuthenticated);
    routes.use(bdDecider); //bdDecider as it says gets the logged on user bdConfig so i can connect to it
    routes.use('/model', ModelRouter);
    
  • so we go to the route that calls container.resolve()

    import { container } from 'tsyringe';
    import { Response, Request } from 'express';
    import ShowModelsService from '@modules/invoices/services/ShowModelsService';
    
    export default class ShowModelsController {
      public async show(req: Request, res: Response): Promise<Response> {
        const { id } = req.params;
    
        const showModelsService = container.resolve( //it calls the model service
          ShowModelsService,
        );
    
        const models = await showModelsService.execute(
          id,
        );
    
        return res.json(models);
      }
    }
    
  • here is the service that he calls

    import IModelRepository from '@modules/model/repositories/IModelRepository';
    import AppError from '@shared/errors/AppError';
    import { inject, injectable } from 'tsyringe';
    import IModelDTO from '../dtos/IModelDTO';
    
    type IResponse = IModelDTO;
    
    @injectable()
    export default class ShowModelService {
      constructor(
        @inject('ModelRepository')
        private modelRepository: IModelRepository,
      ) {}
    
      public async execute(id: string): Promise<IResponse> {
        const model = await this.modelRepository.get_models(
          id,
        );
    
        if (!model) {
          throw new AppError('Model not found!', 404);
        }
    
        return model;
      }
    }
    
  • Till there everything is fine and works properly, but when i try to associate that model with another one using sequelize. Tsyringe stops being able to properly inject the dependencies and gives the title error message. Here it is the models i'm trying to associate.

    import Model from '@modules/model/infra/sequelize/entities/Model';
    import { DataTypes } from 'sequelize';
    import { Sequelize } from 'sequelize-typescript';
    import User from '../entities/User';
    export default (sequelize: Sequelize): void => {
    Model.init(
        {
          primary: {
            allowNull: false,
            autoIncrement: true,
            primaryKey: true,
            type: DataTypes.INTEGER,
          },
          camp1: DataTypes.DECIMAL(20, 2),
          camp2: DataTypes.DATE,
        },
        {
          tableName: 'tbl_model',
          sequelize,
        },
      );
      Model.hasMany(User);
    }
    
  • if i remove that "Model.hasMany(User);" it goes back to normal and the injection happens, i'm very confused to know whats going on...

  • by the way here is my model repository

    import IModelRepository from '@modules/model/repositories/IModelRepository';
    import AppError from '@shared/errors/AppError';
    import { connection } from '@shared/infra/http/middlewares/bdDecider';
    import { Repository } from 'sequelize-typescript';
    import IModelDTO from '@modules/model/dtos/IModelDTO';
    import initModel from '../utils/initInvoice';
    import initUser from '../utils/initItem';
    import Model from '../entities/Model';
    import User from '../entities/User';
    
    export default class ModelRepository implements IModelRepository {
      private ormRepository: Repository<Model>;
    
      constructor() {
        if (!connection) {
          throw new AppError(
            `You don't have a client settled on your user credentials or you don't have a client settled or both`,
          );
        }
        initModel(connection); // it Model.init() the model with the hasmany association
        initUser(connection); // it User.init()
        this.ormRepository = connection.getRepository(Model);
      }
      public async get_models(
        id: string,
      ): Promise<IModelDTO | null> {
        const models = await this.ormRepository.findOne({
          where: { id },
          include: [
            {
              model: User,
            },
          ],
        });
        return models;
      }
    }
    
    
  • I'm sorry if this is too much information, but i tried to give as much as possible so someone could maybe help me.. But honestly i'm kinda skeptical about finding a solution, probably i'll have to detach this method from this model and try to do it separately. As you noticed i changed the names of the models so i might have misspelled something but don't worry with that there's not misspelling on the actual code because this bug only happens when i add "Model.hasMany(User);" to the initModel() function. Hopefully someone will be able to help me, any questions i'll be around don't be afraid to ask. :)

1

There are 1 best solutions below

0
On

Oh well i figured out a solution. Its just better to init the models before calling the container.resolve(). For some reason when you try to init a model inside of it looks like it loses the reference and it fails to inject. But all good now :)

     constructor() {
        if (!connection) {
          throw new AppError(
            `You don't have a client settled on your user credentials or you don't have a client settled or both`,
          );
        }
    initModel(connection); 
    initUser(connection); 
    this.ormRepository = connection.getRepository(Model);
  }

so i just removed the initModel and initUser functions from the repository constructor and putted somewhere else before the container.resolve() being called.