Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js Database Module with Sequelize

To make my code more readable, I'm trying to move all database related code into a single file. and use Sequelize as ORM. I would like that this file, when included provide a ready to use Database. Tables schemas are also managed by Sequelize which is why I use the sync() method to create the tables on the first run. Unfortunately, when I run the application for the first time, I get an error that the table doesn't exist when using this code:

File: test.js

const database = require('./dbInit');

(async () => {

    await database.testTable.max('id').then((maxId) => {
        console.log(maxId);
    });

})();

File: dbInit.js

const Sequelize = require('sequelize');

const sequelize = new Sequelize('mysql://root:root@localhost:3306/test');

const testTable = sequelize.import('testTable');

const database = {
    sequelize: sequelize,
    testTable: testTable,
};

sequelize
    .authenticate()
    .then(() => {
        console.log('Connection to the database has been established successfully.');
    })
    .catch(error => {
        console.error(error);
    });

sequelize.sync();

module.exports = database;

File: testTable.js

const Sequelize = require('sequelize');

module.exports = (sequelize, DataTypes) => {
    return sequelize.define('testTable',
        {
            id: {
                type: Sequelize.BIGINT(19).UNSIGNED,
                primaryKey: true,
                autoIncrement: false,
            }
        }
    );
};

When I run the code as is, without tables created, I can see from the logs that the query is run before the connection to the database is available:

> node .\test.js
Executing (default): SELECT 1+1 AS result
Executing (default): SELECT max(`id`) AS `max` FROM `testTables` AS `testTable`;
Connection to the database has been established successfully.
(node:1572) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Table 'test.testtables' doesn't exist

I have found a way to make it work by adding this like, just before the call to the DB (in test.js before the max('id') call):

await database.sequelize.sync();

Is there any other way to have the dbInit module completely independent and not having to add this sync() call inside all other files which will require database connectivity?

I've looked for sync module loading but it doesn't seem an option yet.

like image 559
Nicolas Bouvrette Avatar asked Nov 07 '22 01:11

Nicolas Bouvrette


1 Answers

Because of async behavior all of ops that You want to do:

  1. Connect
  2. Sync
  3. Do DB operations

You've to make it following way:

put model files to: db folder as: db/schemas/User.js

and make module file for db: db/index.js

const Sequelize = require('sequelize');

const sequelize = new Sequelize('mysql://root:root@localhost:3306/test');

const connect = async () => {
  try {
    await sequelize.authenticate();
    await sequelize.sync();

    console.log('Connection to the database has been established successfully.');
  }
  catch (error) {
    console.error(error.message);
    process.exit(-1);
  }
});

const model = name => database.models[name];

const User = sequelize.import('./schemas/User');

const database = {
    sequelize: sequelize,
    models: {User},
    connect,
    model
};

module.exports = database;

and in test.js:

const db = require('./db');

(async () => {
    await db.connect();

    const User = db.model('User');

    const id = await User.max('id');

    console.log(id);
})();

P.S. forget about examples that used in web apps when developer does not care when db will connect and when express app will listen on port. Your question is different - You want to do db query immediately, so You've to make sure connection and sync established successfully.

like image 123
num8er Avatar answered Nov 14 '22 22:11

num8er