import { config } from "@/config"; import rTracer from "cls-rtracer"; import { DataTypes, Sequelize } from "sequelize"; import { initLogger } from "@/infrastructure/logger"; import * as glob from "glob"; import * as path from "path"; import { IAdapter } from "../../domain"; import { InfrastructureError } from "../InfrastructureError"; import { SequelizeBusinessTransaction, SequelizeBusinessTransactionType, } from "./SequelizeBusinessTransaction"; import { ISequelizeModels } from "./SequelizeModel.interface"; import { ISequelizeQueryBuilder } from "./queryBuilder/SequelizeQueryBuilder"; //import * as dotenv from "dotenv"; //dotenv.config(); export interface ISequelizeAdapter extends IAdapter { queryBuilder: ISequelizeQueryBuilder; startTransaction: () => SequelizeBusinessTransactionType; getModel: (modelName: string) => any; hasModel: (modelName: string) => boolean; } export class SequelizeAdapter implements ISequelizeAdapter { // eslint-disable-next-line no-use-before-define private static instance: SequelizeAdapter; public static getInstance(params: { queryBuilder: ISequelizeQueryBuilder; }): SequelizeAdapter { if (!SequelizeAdapter.instance) { SequelizeAdapter.instance = SequelizeAdapter.create(params); } return SequelizeAdapter.instance; } private static create(params: { queryBuilder: ISequelizeQueryBuilder }) { const { queryBuilder } = params; const connection = initConnection(); const models = registerModels(connection); return new SequelizeAdapter(connection, models, queryBuilder); } private _connection: Sequelize; private _models: ISequelizeModels; private _queryBuilder: ISequelizeQueryBuilder; protected constructor( connection: Sequelize, models: ISequelizeModels, queryBuilder: ISequelizeQueryBuilder, ) { this._connection = connection; this._models = models; this._queryBuilder = queryBuilder; } get queryBuilder(): ISequelizeQueryBuilder { return this._queryBuilder; } public startTransaction(): SequelizeBusinessTransactionType { return new SequelizeBusinessTransaction(this._connection); } public sync(params) { return this._connection.sync(params); } public getModel(modelName: string) { if (this.hasModel(modelName)) { return this._models[modelName]; } throw InfrastructureError.create( InfrastructureError.RESOURCE_NOT_FOUND_ERROR, `[SequelizeAdapter] ${modelName} sequelize model not exists!`, ); } public hasModel(modelName: string): boolean { return !!this._models[modelName]; } } function initConnection(): Sequelize { const { username, password, database, host, dialect, port } = config.database; const logger = initLogger(rTracer); logger.debug("=========================> CONECTO A SEQUELIZE"); return new Sequelize(database, username, password, { host, dialect, port, dialectOptions: { multipleStatements: true, dateStrings: true, typeCast: true, //timezone: "Z", }, pool: { max: 5, min: 0, acquire: 60000, idle: 10000, }, logQueryParameters: true, logging: (sql, timing) => console.debug(sql), //logger.debug(sql, timing), define: { charset: "utf8mb4", collate: "utf8mb4_unicode_ci", //freezeTableName: true, underscored: true, timestamps: true, }, }); } function registerModels(connection: Sequelize): ISequelizeModels { const cwd = path.resolve(`${__dirname}/../../../`); const models: ISequelizeModels = {}; // Get all models const globOptions = { cwd, nocase: true, nodir: true, absolute: true, }; glob.sync("**/*.model.{js,ts}", globOptions).forEach(function (file) { console.log(`>> ${file}`); // eslint-disable-next-line @typescript-eslint/no-var-requires const modelDef = require(path.join(file)).default; const model = typeof modelDef === "function" ? modelDef(connection, DataTypes) : false; if (model) models[model.name] = model; }); for (const modelName in models) { const model = models[modelName]; if (model.associate) { model.associate(connection, models); } if (model.hooks) { model.hooks(connection); } } return models; }