Sequelize: multiple entities in the same table breaks test

Viewed 154

I've inherited a project where 2 sequelize entities are stored in the same table. So they both have the same tableName and schema.

@Table({ tableName: 'thesametable', schema: 'schema', timestamps: false })
export default class FooModel extends Model<FooModel> {
  fieldA: string
}

@Table({ tableName: 'thesametable', schema: 'schema', timestamps: false })
export default class BarModel extends Model<BarModel> {
  fieldB: string
}

The code actually runs fine, but when I write tests for this code, I use an in-memory SQL

dbConnection = new Sequelize('sqlite::memory:', {
  models,
  logging: false,
});
await dbConnection.sync({ force: true, logging: true });

jest.spyOn(FooModel, 'schema').mockImplementation(() => FooModel);
jest.spyOn(BarModel, 'schema').mockImplementation(() => BarModel);

So far all good, but when the first record is inserted in the table, errors pop up.

DatabaseError [SequelizeDatabaseError]: SQLITE_ERROR: no such column: fieldB

After checking the log files, I found out that it only creates the table just once, and when it does, it only creates the fields of the first entity. So, naturally fields are missing when data is inserted for the 2nd entity.

Is there a way to tell sequelize/mysql to effectively include the fields of both entities when the table is created.

I tried a lot of different settings.

  • I tried changing the force: true to alter: true.
  • I tried to use define: { freezeTableNames: true }
  • I tried to add dialect: 'mysql'
  • I tried the setting: paranoid: true

Because it only impacts the test, and there is actually a lot of prouction data in the table, changing the table name is something I prefer to keep as a last option.

EDIT:

After some time I realised that even though this worked fine in production. The code ran as 2 microservices, and each microservice used only 1 of the entities. So, while there were 2 entities using the same table, they were not aware of each others existence. My test however tried to use all models.

2 Answers

So you have two tables with the same name? The sync() method is going to just create one of them I believe. Unless you ran your production migrations for test, I don't think sync will allow you to have two tables with the same name.

While there were multiple models refering to the same table, it took me some time to realize that they were used in different microservices. So, in practice they were never used together. That explains why there was no issue in production.

The test which I ran also only needed access to a limited set of models. It's actually possible to state explicitly the ones it needs.

dbConnection = new Sequelize('sqlite::memory:', {
  models: [FooModel],
  logging: false,
});

That solved all of it.

Related