Publicada:

Node.js + MSSQL - Conéctese a SQL Server con Sequelize y Tedious

Tutorial creado con Node.js, Sequelize y MS SQL Server

Otras versiones disponibles:

Esta es una publicación rápida para mostrar cómo conectarse desde Node.js a MS SQL Server usando Sequelize & Tedious, y crea/actualiza automáticamente la base de datos de SQL Server desde el código.

Los fragmentos de código a continuación son de un tutorial de Node.js + SQL Server CRUD API que publiqué recientemente, para ver el proyecto completo y las instrucciones sobre cómo ejecutarlo localmente, consulte Node.js + MS SQL Server - Ejemplo y tutorial de API CRUD.

 

Contenedor de base de datos del servidor MSSQL

Ruta: /_helpers/db.js

El envoltorio de la base de datos MSSQL se conecta a MSSQL mediante Sequelize & la biblioteca tedious. Exporta un objeto que expone todos los modelos de base de datos para la aplicación (actualmente solo User) y proporciona una manera fácil de acceder a cualquier parte de la base de datos desde un solo punto.

Tedious es la biblioteca de conectores MSSQL utilizada por Sequelize para conectarse a SQL Server. El contenedor DB usa tedious directamente para conectarse a SQL Server y crear la base de datos si no existe. Para obtener más información sobre tedious, consulte https://tediousjs.github.io/tedious/.

La función initialize() se ejecuta una vez en el inicio de la API y realiza las siguientes acciones:

  • Se conecta a MS SQL Server utilizando el cliente db tedious y ejecuta una consulta para crear la base de datos API si aún no existe.
  • Se conecta a la base de datos API con Sequelize ORM.
  • Inicializa el modelo User y lo adjunta al objeto db exportado.
  • Crea/actualiza automáticamente tablas en la base de datos de SQL Server para que coincidan con el modelo de Sequelize (si es necesario) llamando a await sequelize.sync({ alter: true }). Para obtener más información sobre las opciones de sincronización de modelos de Sequelize, consulte https://sequelize.org/master/manual/model-basics.html#model-synchronization.
const tedious = require('tedious');
const { Sequelize } = require('sequelize');

const { dbName, dbConfig } = require('config.json');

module.exports = db = {};

initialize();

async function initialize() {
    const dialect = 'mssql';
    const host = dbConfig.server;
    const { userName, password } = dbConfig.authentication.options;

    // create db if it doesn't already exist
    await ensureDbExists(dbName);

    // connect to db
    const sequelize = new Sequelize(dbName, userName, password, { host, dialect });

    // init models and add them to the exported db object
    db.User = require('../users/user.model')(sequelize);

    // sync all models with database
    await sequelize.sync({ alter: true });
}

async function ensureDbExists(dbName) {
    return new Promise((resolve, reject) => {
        const connection = new tedious.Connection(dbConfig);
        connection.connect((err) => {
            if (err) {
                console.error(err);
                reject(`Connection Failed: ${err.message}`);
            }

            const createDbQuery = `IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '${dbName}') CREATE DATABASE [${dbName}];`;
            const request = new tedious.Request(createDbQuery, (err) => {
                if (err) {
                    console.error(err);
                    reject(`Create DB Query Failed: ${err.message}`);
                }

                // query executed successfully
                resolve();
            });

            connection.execSql(request);
        });
    });
}
 

Modelo de usuario Sequelize

Ruta: /users/user.model.js

El modelo de usuario utiliza Sequelize para definir el esquema de la tabla users en la base de datos de SQL Server. El objeto del modelo Sequelize exportado brinda acceso completo para realizar operaciones CRUD (create, read, update, delete) en usuarios en MSSQL; consulte el servicio de usuario a continuación para ver ejemplos de su uso (a través del ayudante db).

El defaultScope configura el modelo para excluir el hash de la contraseña de los resultados de la consulta de forma predeterminada. El ámbito withHash se puede utilizar para consultar a los usuarios e incluir el hash de la contraseña en los resultados. Para obtener más información sobre los ámbitos de Sequelize, consulte https://sequelize.org/master/manual/scopes.html.

const { DataTypes } = require('sequelize');

module.exports = model;

function model(sequelize) {
    const attributes = {
        email: { type: DataTypes.STRING, allowNull: false },
        passwordHash: { type: DataTypes.STRING, allowNull: false },
        title: { type: DataTypes.STRING, allowNull: false },
        firstName: { type: DataTypes.STRING, allowNull: false },
        lastName: { type: DataTypes.STRING, allowNull: false },
        role: { type: DataTypes.STRING, allowNull: false }
    };

    const options = {
        defaultScope: {
            // exclude password hash by default
            attributes: { exclude: ['passwordHash'] }
        },
        scopes: {
            // include hash with this scope
            withHash: { attributes: {}, }
        }
    };

    return sequelize.define('User', attributes, options);
}
 

Servicio de usuario

Ruta: /users/user.service.js

El servicio de usuario es responsable de toda la interacción de la base de datos y la lógica comercial central relacionada con las operaciones CRUD del usuario, encapsula toda la interacción con el modelo de usuario Sequelize y expone un conjunto simple de métodos para acceder y administrar los datos en SQL Server.

La parte superior del archivo contiene el objeto de servicio exportado con solo los nombres de los métodos para que sea fácil ver todos los métodos de un vistazo, el resto del archivo contiene las funciones de implementación para cada método de servicio, seguidas de las funciones auxiliares locales.

const bcrypt = require('bcryptjs');

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

module.exports = {
    getAll,
    getById,
    create,
    update,
    delete: _delete
};

async function getAll() {
    return await db.User.findAll();
}

async function getById(id) {
    return await getUser(id);
}

async function create(params) {
    // validate
    if (await db.User.findOne({ where: { email: params.email } })) {
        throw 'Email "' + params.email + '" is already registered';
    }

    const user = new db.User(params);
    
    // hash password
    user.passwordHash = await bcrypt.hash(params.password, 10);

    // save user
    await user.save();
}

async function update(id, params) {
    const user = await getUser(id);

    // validate
    const usernameChanged = params.username && user.username !== params.username;
    if (usernameChanged && await db.User.findOne({ where: { username: params.username } })) {
        throw 'Username "' + params.username + '" is already taken';
    }

    // hash password if it was entered
    if (params.password) {
        params.passwordHash = await bcrypt.hash(params.password, 10);
    }

    // copy params to user and save
    Object.assign(user, params);
    await user.save();
}

async function _delete(id) {
    const user = await getUser(id);
    await user.destroy();
}

// helper functions

async function getUser(id) {
    const user = await db.User.findByPk(id);
    if (!user) throw 'User not found';
    return user;
}
 


Suscríbete o Sígueme para actualizaciones

Suscríbete a mi canal de YouTube o sígueme en Twitter, Facebook o GitHub para recibir notificaciones cuando publique contenido nuevo.

Aparte de la codificación...

Actualmente estoy intentando viajar por Australia en motocicleta con mi esposa Tina en un par de Royal Enfield Himalayan. Puedes seguir nuestras aventuras en YouTube, Instagram y Facebook.


¿Necesita Ayuda NodeJS?

Buscar fiverr para encontrar ayuda rápidamente de desarrolladores NodeJS experimentados.