alterações de melhorias
This commit is contained in:
+12
-476
@@ -1,488 +1,24 @@
|
||||
/**
|
||||
* ARQUIVO DE MIGRAÇÕES DO BANCO DE DADOS
|
||||
* ========================================
|
||||
*
|
||||
* Este script contém TODAS as alterações estruturais feitas no banco de dados
|
||||
* desde a criação inicial do projeto.
|
||||
*
|
||||
* USO:
|
||||
* node scripts/migracoes.js [alias]
|
||||
*
|
||||
* Exemplo:
|
||||
* node scripts/migracoes.js lajedo
|
||||
* node scripts/migracoes.js novo
|
||||
*
|
||||
* IMPORTANTE:
|
||||
* - Cada migração tem um ID único e só executa uma vez
|
||||
* - O controle é feito via tabela CHATC2_CONTROLE_MIGRACOES
|
||||
* - Para adicionar NOVA migração, adicione um novo objeto no array MIGRACOES
|
||||
* - Nunca remova ou altere migrações já existentes (apenas adicione novas)
|
||||
* Script CLI de migrações.
|
||||
*
|
||||
* Uso: node scripts/migracoes.js [alias]
|
||||
*
|
||||
* As migrações também rodam automaticamente no boot do servidor.
|
||||
* Este script existe para execução manual/diagnóstico.
|
||||
*/
|
||||
|
||||
const db = require('../src/database');
|
||||
const migrationRunner = require('./migrationRunner');
|
||||
|
||||
// Este script aplica DDL no dialeto Firebird (BLOB SUB_TYPE, etc.).
|
||||
// Alias padrão: novo_local.
|
||||
const alias = process.argv[2] || 'novo_local';
|
||||
|
||||
// ============================================================
|
||||
// CONTROLE DE MIGRAÇÕES
|
||||
// ============================================================
|
||||
async function garantirControle() {
|
||||
try {
|
||||
await db.execute(alias, `
|
||||
CREATE TABLE CHATC2_CONTROLE_MIGRACOES (
|
||||
MIG_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
MIG_DESCRICAO VARCHAR(200),
|
||||
MIG_DATA_EXECUCAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
MIG_STATUS CHAR(1) DEFAULT 'A'
|
||||
)
|
||||
`);
|
||||
console.log('✅ Tabela CHATC2_CONTROLE_MIGRACOES criada');
|
||||
} catch(e) {
|
||||
if (!e.message.includes('already exists')) {
|
||||
console.log('⚠️ CHATC2_CONTROLE_MIGRACOES:', e.message.substring(0, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function migracaoJaExecutada(id) {
|
||||
try {
|
||||
var r = await db.query(alias,
|
||||
'SELECT COUNT(*) AS CT FROM CHATC2_CONTROLE_MIGRACOES WHERE MIG_ID = ?', [id]);
|
||||
return r[0]?.CT > 0;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function registrarMigracao(id, descricao) {
|
||||
try {
|
||||
await db.execute(alias,
|
||||
'INSERT INTO CHATC2_CONTROLE_MIGRACOES (MIG_ID, MIG_DESCRICAO) VALUES (?, ?)',
|
||||
[id, descricao]);
|
||||
} catch(e) {
|
||||
console.log('⚠️ Erro ao registrar migração:', e.message.substring(0, 80));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// LISTA DE MIGRAÇÕES
|
||||
// ============================================================
|
||||
// SEMPRE adicione NOVAS migrações no FINAL do array, com ID sequencial.
|
||||
// NUNCA remova ou modifique migrações já existentes.
|
||||
|
||||
const MIGRACOES = [
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 1: Campo USU_TIPO_CHAT em USUARIOS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 1,
|
||||
descricao: 'Adicionar USU_TIPO_CHAT em USUARIOS (A=Atendente, G=Gerente)',
|
||||
sql: [
|
||||
`ALTER TABLE USUARIOS ADD USU_TIPO_CHAT CHAR(1) DEFAULT 'A'`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 2: Tabela CHATC2_INSTANCIAS (Evolution API)
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 2,
|
||||
descricao: 'Criar tabela CHATC2_INSTANCIAS para conexões WhatsApp',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_INSTANCIAS (
|
||||
INS_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
INS_EMPRESA_ID INTEGER NOT NULL,
|
||||
INS_NOME VARCHAR(100),
|
||||
INS_URL VARCHAR(500),
|
||||
INS_API_KEY VARCHAR(500),
|
||||
INS_INSTANCE_NAME VARCHAR(100),
|
||||
INS_STATUS CHAR(1) DEFAULT 'D',
|
||||
INS_QR_CODE BLOB SUB_TYPE 0,
|
||||
INS_DT_CONEXAO TIMESTAMP,
|
||||
INS_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INS_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_INSTANCIAS`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 3: Tabela CHATC2_EQUIPES
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 3,
|
||||
descricao: 'Criar tabela CHATC2_EQUIPES',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_EQUIPES (
|
||||
EQU_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
EQU_EMPRESA_ID INTEGER NOT NULL,
|
||||
EQU_NOME VARCHAR(100),
|
||||
EQU_ORDEM INTEGER DEFAULT 0,
|
||||
EQU_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_EQUIPES`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 4: Tabela CHATC2_USU_EQUIPES
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 4,
|
||||
descricao: 'Criar tabela CHATC2_USU_EQUIPES (relação N:N)',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_USU_EQUIPES (
|
||||
EQU_EQUIPE_ID INTEGER NOT NULL,
|
||||
EQU_USUARIO_ID INTEGER NOT NULL,
|
||||
PRIMARY KEY (EQU_EQUIPE_ID, EQU_USUARIO_ID)
|
||||
)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 5: Tabela CHATC2_ETIQUETAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 5,
|
||||
descricao: 'Criar tabela CHATC2_ETIQUETAS',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_ETIQUETAS (
|
||||
ETI_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
ETI_EMPRESA_ID INTEGER NOT NULL,
|
||||
ETI_NOME VARCHAR(50),
|
||||
ETI_COR VARCHAR(7) DEFAULT '#667eea',
|
||||
ETI_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_ETIQUETAS`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 6: Tabela CHATC2_CONVERSAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 6,
|
||||
descricao: 'Criar tabela CHATC2_CONVERSAS',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_CONVERSAS (
|
||||
CON_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
CON_EMPRESA_ID INTEGER NOT NULL,
|
||||
CON_INSTANCIA_ID INTEGER,
|
||||
CON_CLIENTE_ID INTEGER,
|
||||
CON_NUMERO VARCHAR(20),
|
||||
CON_NOME_CONTATO VARCHAR(100),
|
||||
CON_STATUS CHAR(1) DEFAULT 'E',
|
||||
CON_USUARIO_ID INTEGER,
|
||||
CON_EQUIPE_ID INTEGER,
|
||||
CON_DT_INICIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CON_DT_FINAL TIMESTAMP,
|
||||
CON_DT_ULTIMA_MSG TIMESTAMP,
|
||||
CON_SAUDACAO_ENVIADA CHAR(1) DEFAULT 'N',
|
||||
CON_CSAT_ENVIADO CHAR(1) DEFAULT 'N',
|
||||
CON_PRIMEIRA_MSG TIMESTAMP,
|
||||
CON_ORIGEM VARCHAR(20) DEFAULT 'whatsapp',
|
||||
CON_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_CONVERSAS`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 7: Tabela CHATC2_CONVERSAS_MENSAGENS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 7,
|
||||
descricao: 'Criar tabela CHATC2_CONVERSAS_MENSAGENS',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_CONVERSAS_MENSAGENS (
|
||||
CME_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
CME_CONVERSA_ID INTEGER NOT NULL,
|
||||
CME_REMETENTE CHAR(1) DEFAULT 'C',
|
||||
CME_USUARIO_ID INTEGER,
|
||||
CME_MENSAGEM BLOB SUB_TYPE 1,
|
||||
CME_TEXTO VARCHAR(4000),
|
||||
CME_TIPO VARCHAR(20) DEFAULT 'text',
|
||||
CME_DT_ENVIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CME_PRIVADA CHAR(1) DEFAULT 'N',
|
||||
CME_LIDA CHAR(1) DEFAULT 'N',
|
||||
CME_MIDIA_ID INTEGER,
|
||||
CME_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_CONVERSAS_MENSAGENS`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 8: Tabela CHATC2_MENSAGENS_ATENDIMENTOS (blob mídias)
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 8,
|
||||
descricao: 'Criar tabela CHATC2_MENSAGENS_ATENDIMENTOS para mídias',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_MENSAGENS_ATENDIMENTOS (
|
||||
MAT_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
MAT_CONVERSA_ID INTEGER,
|
||||
MAT_MENSAGEM_ID INTEGER,
|
||||
MAT_NOME_ARQUIVO VARCHAR(255),
|
||||
MAT_TIPO_ARQUIVO VARCHAR(50),
|
||||
MAT_ARQUIVO BLOB SUB_TYPE 0,
|
||||
MAT_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
MAT_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_MENSAGENS_ATENDIMENTO`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 9: Tabela CHATC2_CONVERSAS_ETIQUETAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 9,
|
||||
descricao: 'Criar tabela CHATC2_CONVERSAS_ETIQUETAS',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_CONVERSAS_ETIQUETAS (
|
||||
CET_CONVERSA_ID INTEGER NOT NULL,
|
||||
CET_ETIQUETA_ID INTEGER NOT NULL,
|
||||
PRIMARY KEY (CET_CONVERSA_ID, CET_ETIQUETA_ID)
|
||||
)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 10: Tabela CHATC2_CSAT_AVALIACOES
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 10,
|
||||
descricao: 'Criar tabela CHATC2_CSAT_AVALIACOES',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_CSAT_AVALIACOES (
|
||||
CSA_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
CSA_CONVERSA_ID INTEGER,
|
||||
CSA_EMPRESA_ID INTEGER,
|
||||
CSA_CLIENTE_ID INTEGER,
|
||||
CSA_NOTA INTEGER,
|
||||
CSA_COMENTARIO VARCHAR(500),
|
||||
CSA_DT_AVALIACAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
`CREATE SEQUENCE GEN_CSAT_AVALIACOES`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 11: Tabela CHATC2_CONFIGURACOES_EMPRESA (base)
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 11,
|
||||
descricao: 'Criar tabela CHATC2_CONFIGURACOES_EMPRESA (base)',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_CONFIGURACOES_EMPRESA (
|
||||
CFE_EMPRESA_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
CFE_INSTANCIA_PADRAO_ID INTEGER,
|
||||
CFE_FOTO_CELULAR CHAR(1) DEFAULT 'N',
|
||||
CFE_SAUDACAO_ATIVA CHAR(1) DEFAULT 'S',
|
||||
CFE_SAUDACAO_MENSAGEM VARCHAR(500),
|
||||
CFE_CSAT_ATIVO CHAR(1) DEFAULT 'N',
|
||||
CFE_CSAT_MENSAGEM VARCHAR(500) DEFAULT 'Avalie seu atendimento de 1 a 5 estrelas'
|
||||
)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 12: EQU_ORDEM em CHATC2_EQUIPES
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 12,
|
||||
descricao: 'Adicionar EQU_ORDEM em CHATC2_EQUIPES (ordenação)',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_EQUIPES ADD EQU_ORDEM INTEGER DEFAULT 0`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 13: Campos de triagem em CHATC2_CONFIGURACOES_EMPRESA
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 13,
|
||||
descricao: 'Adicionar campos de triagem em CHATC2_CONFIGURACOES_EMPRESA',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_ENVIAR_NOME_USUARIO CHAR(1) DEFAULT 'N'`,
|
||||
`ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_ATIVA CHAR(1) DEFAULT 'N'`,
|
||||
`ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_WELCOME VARCHAR(500)`,
|
||||
`ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_AFTER VARCHAR(500)`,
|
||||
`ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_BOLETO_NUMERO VARCHAR(10) DEFAULT '0'`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 14: CON_MENU_ESTADO em CHATC2_CONVERSAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 14,
|
||||
descricao: 'Adicionar CON_MENU_ESTADO em CHATC2_CONVERSAS (navegação triagem)',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_CONVERSAS ADD CON_MENU_ESTADO VARCHAR(100)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 15: CON_ETIQUETAS_DESC em CHATC2_CONVERSAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 15,
|
||||
descricao: 'Adicionar CON_ETIQUETAS_DESC em CHATC2_CONVERSAS (estado legado)',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_CONVERSAS ADD CON_ETIQUETAS_DESC VARCHAR(500)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 16: Tabela CHATC2_MENUS_EMPRESA (fluxo personalizado)
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 16,
|
||||
descricao: 'Criar tabela CHATC2_MENUS_EMPRESA para fluxo de atendimento personalizado',
|
||||
sql: [
|
||||
`CREATE TABLE CHATC2_MENUS_EMPRESA (
|
||||
MNE_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
MNE_EMPRESA_ID INTEGER,
|
||||
MNE_EQUIPE_ID INTEGER,
|
||||
MNE_MENU_PAI_ID INTEGER,
|
||||
MNE_ORDEM INTEGER DEFAULT 0,
|
||||
MNE_TITULO VARCHAR(100),
|
||||
MNE_TIPO CHAR(1) DEFAULT 'M',
|
||||
MNE_TEXTO BLOB SUB_TYPE TEXT,
|
||||
MNE_ACAO_ROTA VARCHAR(100),
|
||||
MNE_ACAO_METODO VARCHAR(10),
|
||||
MNE_ACAO_PROMPT VARCHAR(300),
|
||||
MNE_SITUACAO CHAR(1) DEFAULT 'A'
|
||||
)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 17: CON_USUARIO_NOME, CON_EQUIPE_NOME, CON_ETIQUETAS_DESC em CHATC2_CONVERSAS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 17,
|
||||
descricao: 'Adicionar CON_USUARIO_NOME, CON_EQUIPE_NOME, CON_ETIQUETAS_DESC em CHATC2_CONVERSAS',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_CONVERSAS ADD CON_USUARIO_NOME VARCHAR(100)`,
|
||||
`ALTER TABLE CHATC2_CONVERSAS ADD CON_EQUIPE_NOME VARCHAR(100)`,
|
||||
`ALTER TABLE CHATC2_CONVERSAS ADD CON_ETIQUETAS_DESC VARCHAR(500)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 18: Etiquetas nos menus de fluxo
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 18,
|
||||
descricao: 'Adicionar MNE_ETIQUETA_IDS em CHATC2_MENUS_EMPRESA (etiquetas por etapa do fluxo)',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_MENUS_EMPRESA ADD MNE_ETIQUETA_IDS VARCHAR(200)`,
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 19: Transcrição de áudio em CHATC2_MENSAGENS_ATENDIMENTOS
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 19,
|
||||
descricao: 'Adicionar MAT_TRANSCRICAO em CHATC2_MENSAGENS_ATENDIMENTOS (transcricao de audio)',
|
||||
sql: [
|
||||
`ALTER TABLE CHATC2_MENSAGENS_ATENDIMENTOS ADD MAT_TRANSCRICAO BLOB SUB_TYPE TEXT`,
|
||||
],
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// >>> ADICIONE NOVAS MIGRAÇÕES AQUI <<<
|
||||
// ============================================================
|
||||
//
|
||||
// Exemplo:
|
||||
// {
|
||||
// id: 19,
|
||||
// descricao: 'Descrição clara do que esta migração faz',
|
||||
// sql: [
|
||||
// `ALTER TABLE EXEMPLO ADD NOVO_CAMPO VARCHAR(100)`,
|
||||
// `CREATE TABLE NOVA_TABELA ( ... )`,
|
||||
// ],
|
||||
// },
|
||||
//
|
||||
];
|
||||
|
||||
// ============================================================
|
||||
// EXECUTOR DE MIGRAÇÕES
|
||||
// ============================================================
|
||||
async function main() {
|
||||
(async () => {
|
||||
console.log(`\n=== MIGRAÇÕES DE BANCO DE DADOS ===`);
|
||||
console.log(`Alias: ${alias}\n`);
|
||||
|
||||
// Blindagem: a DDL aqui é Firebird. Se o alias for Postgres (banco externo,
|
||||
// gerenciado fora), não há o que aplicar — sai sem erro.
|
||||
let driver;
|
||||
try { driver = db.driverOf(alias); }
|
||||
catch (e) { console.error('❌', e.message); process.exit(1); }
|
||||
if (driver !== 'firebird') {
|
||||
console.log(`⚠️ O alias "${alias}" usa o driver "${driver}". Este script aplica DDL Firebird.`);
|
||||
console.log(' Para migrar um banco Firebird: node scripts/migracoes.js novo_local\n');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
await garantirControle();
|
||||
|
||||
var executadas = 0;
|
||||
var pendentes = 0;
|
||||
|
||||
for (var mig of MIGRACOES) {
|
||||
var jaExecutou = await migracaoJaExecutada(mig.id);
|
||||
|
||||
if (jaExecutou) {
|
||||
console.log(`⏭️ [${mig.id}] ${mig.descricao} — já executada`);
|
||||
continue;
|
||||
}
|
||||
|
||||
pendentes++;
|
||||
console.log(`▶️ [${mig.id}] ${mig.descricao}...`);
|
||||
|
||||
var erros = 0;
|
||||
for (var cmd of mig.sql) {
|
||||
try {
|
||||
await db.execute(alias, cmd);
|
||||
console.log(` ✅ ${cmd.substring(0, 80)}...`);
|
||||
} catch(e) {
|
||||
var msg = e.message;
|
||||
// Firebird pode reportar "already exists" de várias formas
|
||||
if (msg.includes('already exists') || msg.includes('Violation') || msg.includes('duplicate') || msg.includes('Unknow')) {
|
||||
console.log(` ℹ️ Já existe: ${cmd.substring(0, 60)}...`);
|
||||
} else {
|
||||
console.log(` ❌ ${msg.substring(0, 120)}`);
|
||||
erros++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (erros === 0) {
|
||||
await registrarMigracao(mig.id, mig.descricao);
|
||||
executadas++;
|
||||
console.log(` ✅ Migração ${mig.id} concluída\n`);
|
||||
} else {
|
||||
console.log(` ⚠️ Migração ${mig.id} concluída com ${erros} erro(s)\n`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`=== RESUMO ===`);
|
||||
console.log(`Total de migrações: ${MIGRACOES.length}`);
|
||||
console.log(`Executadas agora: ${executadas}`);
|
||||
console.log(`Já executadas antes: ${MIGRACOES.length - pendentes}`);
|
||||
console.log(`Pendentes (com erro): ${pendentes - executadas}`);
|
||||
console.log(`\n✅ Finalizado!`);
|
||||
const count = await migrationRunner.executarMigracoes(alias);
|
||||
console.log(`\n✅ ${count} migração(ões) executada(s). Total: ${migrationRunner.MIGRACOES.length}.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main().catch(function(err) {
|
||||
console.error('❌ Erro fatal:', err.message);
|
||||
})().catch((err) => {
|
||||
console.error('❌ Erro:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
+96
-2
@@ -364,6 +364,98 @@ END;
|
||||
COMMIT;
|
||||
^
|
||||
|
||||
-- ============================================================
|
||||
-- MIGRAÇÃO 20: Generators thread-safe para todas as tabelas Chatc2
|
||||
-- Cria sequences faltantes e inicializa todas com MAX atual + 1
|
||||
-- ============================================================
|
||||
EXECUTE BLOCK AS
|
||||
DECLARE max_val INTEGER;
|
||||
BEGIN
|
||||
-- Tabelas que já tinham sequence (criadas nas migrações 2-8, 10).
|
||||
-- Nomes podem variar - este bloco garante que existam com o nome
|
||||
-- usado pelo código (nextId). Se a sequence com outro nome já
|
||||
-- existir, mantém ambas (a antiga fica dormente).
|
||||
|
||||
-- CHATC2_CONVERSAS: já tinha GEN_CONVERSAS (migração 6)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_CONVERSAS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_CONVERSAS';
|
||||
SELECT COALESCE(MAX(CON_CODIGO_ID), 0) + 1 FROM CHATC2_CONVERSAS INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_CONVERSAS TO ' || :max_val;
|
||||
|
||||
-- CHATC2_CONVERSAS_MENSAGENS: já tinha GEN_CONVERSAS_MENSAGENS (migração 7)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CONVERSAS_MENSAGENS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CONVERSAS_MENSAGENS';
|
||||
SELECT COALESCE(MAX(CME_CODIGO_ID), 0) + 1 FROM CHATC2_CONVERSAS_MENSAGENS INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CONVERSAS_MENSAGENS TO ' || :max_val;
|
||||
|
||||
-- CHATC2_MENSAGENS_ATENDIMENTOS: já tinha GEN_MENSAGENS_ATENDIMENTO (migração 8)
|
||||
-- Criamos com nome corrigido (plural ATENDIMENTOS)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_MENSAGENS_ATENDIMENTOS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_MENSAGENS_ATENDIMENTOS';
|
||||
SELECT COALESCE(MAX(MAT_CODIGO_ID), 0) + 1 FROM CHATC2_MENSAGENS_ATENDIMENTOS INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_MENSAGENS_ATENDIMENTOS TO ' || :max_val;
|
||||
|
||||
-- CHATC2_EQUIPES: já tinha GEN_EQUIPES (migração 3)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_EQUIPES')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_EQUIPES';
|
||||
SELECT COALESCE(MAX(EQU_CODIGO_ID), 0) + 1 FROM CHATC2_EQUIPES INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_EQUIPES TO ' || :max_val;
|
||||
|
||||
-- CHATC2_ETIQUETAS: já tinha GEN_ETIQUETAS (migração 5)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_ETIQUETAS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_ETIQUETAS';
|
||||
SELECT COALESCE(MAX(ETI_CODIGO_ID), 0) + 1 FROM CHATC2_ETIQUETAS INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_ETIQUETAS TO ' || :max_val;
|
||||
|
||||
-- CHATC2_INSTANCIAS: já tinha GEN_INSTANCIAS (migração 2)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_INSTANCIAS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_INSTANCIAS';
|
||||
SELECT COALESCE(MAX(INS_CODIGO_ID), 0) + 1 FROM CHATC2_INSTANCIAS INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_INSTANCIAS TO ' || :max_val;
|
||||
|
||||
-- CHATC2_CSAT_AVALIACOES: já tinha GEN_CSAT_AVALIACOES (migração 10)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_CSAT_AVALIACOES')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_CSAT_AVALIACOES';
|
||||
SELECT COALESCE(MAX(CSA_CODIGO_ID), 0) + 1 FROM CHATC2_CSAT_AVALIACOES INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_CSAT_AVALIACOES TO ' || :max_val;
|
||||
|
||||
-- CHATC2_MENUS_EMPRESA: NÃO tinha sequence (criada na migração 16)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_MENUS_EMPRESA')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_MENUS_EMPRESA';
|
||||
SELECT COALESCE(MAX(MNE_CODIGO_ID), 0) + 1 FROM CHATC2_MENUS_EMPRESA INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_MENUS_EMPRESA TO ' || :max_val;
|
||||
|
||||
-- CHATC2_MOTIVOS_ATENDIMENTO: tabela criada por resolucaoSetup.js (sem sequence)
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'GEN_CHATC2_MOTIVOS_ATENDIMENTO')) THEN
|
||||
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CHATC2_MOTIVOS_ATENDIMENTO';
|
||||
SELECT COALESCE(MAX(MOT_CODIGO_ID), 0) + 1 FROM "CHATC2_MOTIVOS_ATENDIMENTO" INTO :max_val;
|
||||
EXECUTE STATEMENT 'SET GENERATOR GEN_CHATC2_MOTIVOS_ATENDIMENTO TO ' || :max_val;
|
||||
END;
|
||||
^
|
||||
COMMIT;
|
||||
^
|
||||
|
||||
-- ============================================================
|
||||
-- MIGRAÇÃO 21: Índices para busca de telefone
|
||||
-- ============================================================
|
||||
EXECUTE BLOCK AS BEGIN
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CLIENTES_CELULAR')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CLIENTES_CELULAR ON CLIENTES (CLI_CELULAR)';
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CLIENTES_FONE1')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CLIENTES_FONE1 ON CLIENTES (CLI_FONE1)';
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CLIENTES_FONE2')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CLIENTES_FONE2 ON CLIENTES (CLI_FONE2)';
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CLIENTES_EMPRESA')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CLIENTES_EMPRESA ON CLIENTES (CLI_EMPRESA_ID)';
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CONV_NUMERO_EMPRESA')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CONV_NUMERO_EMPRESA ON CHATC2_CONVERSAS (CON_NUMERO, CON_EMPRESA_ID)';
|
||||
IF (NOT EXISTS(SELECT 1 FROM RDB$INDICES WHERE RDB$INDEX_NAME = 'IDX_CONV_STATUS')) THEN
|
||||
EXECUTE STATEMENT 'CREATE INDEX IDX_CONV_STATUS ON CHATC2_CONVERSAS (CON_STATUS)';
|
||||
END;
|
||||
^
|
||||
COMMIT;
|
||||
^
|
||||
|
||||
-- ============================================================
|
||||
-- REGISTRO DAS MIGRAÇÕES (marca como executadas)
|
||||
-- ============================================================
|
||||
@@ -391,7 +483,9 @@ BEGIN
|
||||
SELECT 16, 'Tabela CHATC2_MENUS_EMPRESA' FROM RDB$DATABASE UNION ALL
|
||||
SELECT 17, 'CON_USUARIO_NOME e CON_EQUIPE_NOME' FROM RDB$DATABASE UNION ALL
|
||||
SELECT 18, 'MNE_ETIQUETA_IDS nos menus' FROM RDB$DATABASE UNION ALL
|
||||
SELECT 19, 'MAT_TRANSCRICAO nas mídias' FROM RDB$DATABASE
|
||||
SELECT 19, 'MAT_TRANSCRICAO nas mídias' FROM RDB$DATABASE UNION ALL
|
||||
SELECT 20, 'Generators thread-safe para todas as tabelas' FROM RDB$DATABASE UNION ALL
|
||||
SELECT 21, 'Índices para busca de telefone' FROM RDB$DATABASE
|
||||
) AS migracoes
|
||||
INTO :mig_id, :mig_desc
|
||||
DO BEGIN
|
||||
@@ -408,4 +502,4 @@ COMMIT;
|
||||
-- ============================================================
|
||||
-- Após executar, verifique com:
|
||||
-- SELECT * FROM CHATC2_CONTROLE_MIGRACOES ORDER BY MIG_ID;
|
||||
-- Deve mostrar 19 migrações registradas.
|
||||
-- Deve mostrar 21 migrações registradas.
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Runner de migrações — executável via CLI ou automaticamente no boot.
|
||||
*
|
||||
* Exporta uma função `executarMigracoes(alias)` que aplica todas as migrações
|
||||
* pendentes de forma idempotente. Usado por server.js no boot e por
|
||||
* scripts/migracoes.js para execução manual.
|
||||
*/
|
||||
|
||||
const db = require('../src/database');
|
||||
|
||||
// ============================================================
|
||||
// LISTA DE MIGRAÇÕES
|
||||
// ============================================================
|
||||
// SEMPRE adicione NOVAS migrações no FINAL do array, com ID sequencial.
|
||||
// NUNCA remova ou modifique migrações já existentes.
|
||||
|
||||
const MIGRACOES = [
|
||||
{ id: 1, descricao: 'Adicionar USU_TIPO_CHAT em USUARIOS (A=Atendente, G=Gerente)', sql: ['ALTER TABLE USUARIOS ADD USU_TIPO_CHAT CHAR(1) DEFAULT \'A\''] },
|
||||
{ id: 2, descricao: 'Criar tabela CHATC2_INSTANCIAS para conexões WhatsApp', sql: [`CREATE TABLE CHATC2_INSTANCIAS (INS_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, INS_EMPRESA_ID INTEGER NOT NULL, INS_NOME VARCHAR(100), INS_URL VARCHAR(500), INS_API_KEY VARCHAR(500), INS_INSTANCE_NAME VARCHAR(100), INS_STATUS CHAR(1) DEFAULT 'D', INS_QR_CODE BLOB SUB_TYPE 0, INS_DT_CONEXAO TIMESTAMP, INS_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INS_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 3, descricao: 'Criar tabela CHATC2_EQUIPES', sql: [`CREATE TABLE CHATC2_EQUIPES (EQU_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, EQU_EMPRESA_ID INTEGER NOT NULL, EQU_NOME VARCHAR(100), EQU_ORDEM INTEGER DEFAULT 0, EQU_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 4, descricao: 'Criar tabela CHATC2_USU_EQUIPES (relação N:N)', sql: ['CREATE TABLE CHATC2_USU_EQUIPES (EQU_EQUIPE_ID INTEGER NOT NULL, EQU_USUARIO_ID INTEGER NOT NULL, PRIMARY KEY (EQU_EQUIPE_ID, EQU_USUARIO_ID))'] },
|
||||
{ id: 5, descricao: 'Criar tabela CHATC2_ETIQUETAS', sql: [`CREATE TABLE CHATC2_ETIQUETAS (ETI_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, ETI_EMPRESA_ID INTEGER NOT NULL, ETI_NOME VARCHAR(50), ETI_COR VARCHAR(7) DEFAULT '#667eea', ETI_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 6, descricao: 'Criar tabela CHATC2_CONVERSAS', sql: [`CREATE TABLE CHATC2_CONVERSAS (CON_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, CON_EMPRESA_ID INTEGER NOT NULL, CON_INSTANCIA_ID INTEGER, CON_CLIENTE_ID INTEGER, CON_NUMERO VARCHAR(20), CON_NOME_CONTATO VARCHAR(100), CON_STATUS CHAR(1) DEFAULT 'E', CON_USUARIO_ID INTEGER, CON_EQUIPE_ID INTEGER, CON_DT_INICIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CON_DT_FINAL TIMESTAMP, CON_DT_ULTIMA_MSG TIMESTAMP, CON_SAUDACAO_ENVIADA CHAR(1) DEFAULT 'N', CON_CSAT_ENVIADO CHAR(1) DEFAULT 'N', CON_PRIMEIRA_MSG TIMESTAMP, CON_ORIGEM VARCHAR(20) DEFAULT 'whatsapp', CON_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 7, descricao: 'Criar tabela CHATC2_CONVERSAS_MENSAGENS', sql: [`CREATE TABLE CHATC2_CONVERSAS_MENSAGENS (CME_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, CME_CONVERSA_ID INTEGER NOT NULL, CME_REMETENTE CHAR(1) DEFAULT 'C', CME_USUARIO_ID INTEGER, CME_MENSAGEM BLOB SUB_TYPE 1, CME_TEXTO VARCHAR(4000), CME_TIPO VARCHAR(20) DEFAULT 'text', CME_DT_ENVIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CME_PRIVADA CHAR(1) DEFAULT 'N', CME_LIDA CHAR(1) DEFAULT 'N', CME_MIDIA_ID INTEGER, CME_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 8, descricao: 'Criar tabela CHATC2_MENSAGENS_ATENDIMENTOS para mídias', sql: [`CREATE TABLE CHATC2_MENSAGENS_ATENDIMENTOS (MAT_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, MAT_CONVERSA_ID INTEGER, MAT_MENSAGEM_ID INTEGER, MAT_NOME_ARQUIVO VARCHAR(255), MAT_TIPO_ARQUIVO VARCHAR(50), MAT_ARQUIVO BLOB SUB_TYPE 0, MAT_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP, MAT_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 9, descricao: 'Criar tabela CHATC2_CONVERSAS_ETIQUETAS', sql: ['CREATE TABLE CHATC2_CONVERSAS_ETIQUETAS (CET_CONVERSA_ID INTEGER NOT NULL, CET_ETIQUETA_ID INTEGER NOT NULL, PRIMARY KEY (CET_CONVERSA_ID, CET_ETIQUETA_ID))'] },
|
||||
{ id: 10, descricao: 'Criar tabela CHATC2_CSAT_AVALIACOES', sql: [`CREATE TABLE CHATC2_CSAT_AVALIACOES (CSA_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, CSA_CONVERSA_ID INTEGER, CSA_EMPRESA_ID INTEGER, CSA_CLIENTE_ID INTEGER, CSA_NOTA INTEGER, CSA_COMENTARIO VARCHAR(500), CSA_DT_AVALIACAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`] },
|
||||
{ id: 11, descricao: 'Criar tabela CHATC2_CONFIGURACOES_EMPRESA (base)', sql: [`CREATE TABLE CHATC2_CONFIGURACOES_EMPRESA (CFE_EMPRESA_ID INTEGER NOT NULL PRIMARY KEY, CFE_INSTANCIA_PADRAO_ID INTEGER, CFE_FOTO_CELULAR CHAR(1) DEFAULT 'N', CFE_SAUDACAO_ATIVA CHAR(1) DEFAULT 'S', CFE_SAUDACAO_MENSAGEM VARCHAR(500), CFE_CSAT_ATIVO CHAR(1) DEFAULT 'N', CFE_CSAT_MENSAGEM VARCHAR(500) DEFAULT 'Avalie seu atendimento de 1 a 5 estrelas')`] },
|
||||
{ id: 12, descricao: 'Adicionar EQU_ORDEM em CHATC2_EQUIPES (ordenação)', sql: ['ALTER TABLE CHATC2_EQUIPES ADD EQU_ORDEM INTEGER DEFAULT 0'] },
|
||||
{ id: 13, descricao: 'Adicionar campos de triagem em CHATC2_CONFIGURACOES_EMPRESA', sql: ['ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_ENVIAR_NOME_USUARIO CHAR(1) DEFAULT \'N\'', 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_ATIVA CHAR(1) DEFAULT \'N\'', 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_WELCOME VARCHAR(500)', 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_AFTER VARCHAR(500)', 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_BOLETO_NUMERO VARCHAR(10) DEFAULT \'0\''] },
|
||||
{ id: 14, descricao: 'Adicionar CON_MENU_ESTADO em CHATC2_CONVERSAS (navegação triagem)', sql: ['ALTER TABLE CHATC2_CONVERSAS ADD CON_MENU_ESTADO VARCHAR(100)'] },
|
||||
{ id: 15, descricao: 'Adicionar CON_ETIQUETAS_DESC em CHATC2_CONVERSAS', sql: ['ALTER TABLE CHATC2_CONVERSAS ADD CON_ETIQUETAS_DESC VARCHAR(500)'] },
|
||||
{ id: 16, descricao: 'Criar tabela CHATC2_MENUS_EMPRESA para fluxo personalizado', sql: [`CREATE TABLE CHATC2_MENUS_EMPRESA (MNE_CODIGO_ID INTEGER NOT NULL PRIMARY KEY, MNE_EMPRESA_ID INTEGER, MNE_EQUIPE_ID INTEGER, MNE_MENU_PAI_ID INTEGER, MNE_ORDEM INTEGER DEFAULT 0, MNE_TITULO VARCHAR(100), MNE_TIPO CHAR(1) DEFAULT 'M', MNE_TEXTO BLOB SUB_TYPE TEXT, MNE_ACAO_ROTA VARCHAR(100), MNE_ACAO_METODO VARCHAR(10), MNE_ACAO_PROMPT VARCHAR(300), MNE_SITUACAO CHAR(1) DEFAULT 'A')`] },
|
||||
{ id: 17, descricao: 'Adicionar CON_USUARIO_NOME e CON_EQUIPE_NOME em CHATC2_CONVERSAS', sql: ['ALTER TABLE CHATC2_CONVERSAS ADD CON_USUARIO_NOME VARCHAR(100)', 'ALTER TABLE CHATC2_CONVERSAS ADD CON_EQUIPE_NOME VARCHAR(100)'] },
|
||||
{ id: 18, descricao: 'Adicionar MNE_ETIQUETA_IDS em CHATC2_MENUS_EMPRESA', sql: ['ALTER TABLE CHATC2_MENUS_EMPRESA ADD MNE_ETIQUETA_IDS VARCHAR(200)'] },
|
||||
{ id: 19, descricao: 'Adicionar MAT_TRANSCRICAO em CHATC2_MENSAGENS_ATENDIMENTOS', sql: ['ALTER TABLE CHATC2_MENSAGENS_ATENDIMENTOS ADD MAT_TRANSCRICAO BLOB SUB_TYPE TEXT'] },
|
||||
{ id: 20, descricao: 'Criar generators Firebird para eliminar race condition',
|
||||
sql: [
|
||||
'CREATE GENERATOR GEN_CHATC2_CONVERSAS', 'CREATE GENERATOR GEN_CONVERSAS_MENSAGENS',
|
||||
'CREATE GENERATOR GEN_MENSAGENS_ATENDIMENTOS', 'CREATE GENERATOR GEN_CHATC2_EQUIPES',
|
||||
'CREATE GENERATOR GEN_CHATC2_ETIQUETAS', 'CREATE GENERATOR GEN_CHATC2_INSTANCIAS',
|
||||
'CREATE GENERATOR GEN_CHATC2_MENUS_EMPRESA', 'CREATE GENERATOR GEN_CHATC2_CSAT_AVALIACOES',
|
||||
'CREATE GENERATOR GEN_CHATC2_MOTIVOS_ATENDIMENTO',
|
||||
],
|
||||
async after(alias) {
|
||||
const generators = [
|
||||
{ gen: 'GEN_CHATC2_CONVERSAS', tabela: 'CHATC2_CONVERSAS', col: 'CON_CODIGO_ID' },
|
||||
{ gen: 'GEN_CONVERSAS_MENSAGENS', tabela: 'CHATC2_CONVERSAS_MENSAGENS', col: 'CME_CODIGO_ID' },
|
||||
{ gen: 'GEN_MENSAGENS_ATENDIMENTOS', tabela: 'CHATC2_MENSAGENS_ATENDIMENTOS', col: 'MAT_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_EQUIPES', tabela: 'CHATC2_EQUIPES', col: 'EQU_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_ETIQUETAS', tabela: 'CHATC2_ETIQUETAS', col: 'ETI_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_INSTANCIAS', tabela: 'CHATC2_INSTANCIAS', col: 'INS_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_MENUS_EMPRESA', tabela: 'CHATC2_MENUS_EMPRESA', col: 'MNE_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_CSAT_AVALIACOES', tabela: 'CHATC2_CSAT_AVALIACOES', col: 'CSA_CODIGO_ID' },
|
||||
{ gen: 'GEN_CHATC2_MOTIVOS_ATENDIMENTO', tabela: '"CHATC2_MOTIVOS_ATENDIMENTO"', col: 'MOT_CODIGO_ID' },
|
||||
];
|
||||
for (const g of generators) {
|
||||
try {
|
||||
const r = await db.query(alias, `SELECT COALESCE(MAX(${g.col}), 0) + 1 AS VAL FROM ${g.tabela}`);
|
||||
await db.execute(alias, `SET GENERATOR ${g.gen} TO ${r[0]?.VAL || 1}`);
|
||||
} catch (_) {}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// MIGRAÇÃO 21: Índices para busca de telefone (webhook)
|
||||
// ----------------------------------------------------------
|
||||
{
|
||||
id: 21,
|
||||
descricao: 'Índices para busca de cliente por telefone (acelera webhook)',
|
||||
sql: [
|
||||
// Índice na tabela CLIENTES para busca por CELULAR/FONE1/FONE2
|
||||
'CREATE INDEX IDX_CLIENTES_CELULAR ON CLIENTES (CLI_CELULAR)',
|
||||
'CREATE INDEX IDX_CLIENTES_FONE1 ON CLIENTES (CLI_FONE1)',
|
||||
'CREATE INDEX IDX_CLIENTES_FONE2 ON CLIENTES (CLI_FONE2)',
|
||||
'CREATE INDEX IDX_CLIENTES_EMPRESA ON CLIENTES (CLI_EMPRESA_ID)',
|
||||
// Índice composto para a query mais comum do webhook
|
||||
'CREATE INDEX IDX_CONV_NUMERO_EMPRESA ON CHATC2_CONVERSAS (CON_NUMERO, CON_EMPRESA_ID)',
|
||||
'CREATE INDEX IDX_CONV_STATUS ON CHATC2_CONVERSAS (CON_STATUS)',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================================
|
||||
// EXECUTOR
|
||||
// ============================================================
|
||||
|
||||
async function garantirControle(alias) {
|
||||
try {
|
||||
await db.execute(alias, `CREATE TABLE CHATC2_CONTROLE_MIGRACOES (MIG_ID INTEGER NOT NULL PRIMARY KEY, MIG_DESCRICAO VARCHAR(200), MIG_DATA_EXECUCAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP, MIG_STATUS CHAR(1) DEFAULT 'A')`);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
async function migracaoJaExecutada(alias, id) {
|
||||
try {
|
||||
const r = await db.query(alias, 'SELECT COUNT(*) AS CT FROM CHATC2_CONTROLE_MIGRACOES WHERE MIG_ID = ?', [id]);
|
||||
return r[0]?.CT > 0;
|
||||
} catch (_) { return false; }
|
||||
}
|
||||
|
||||
async function registrarMigracao(alias, id, descricao) {
|
||||
try {
|
||||
await db.execute(alias, 'INSERT INTO CHATC2_CONTROLE_MIGRACOES (MIG_ID, MIG_DESCRICAO) VALUES (?, ?)', [id, descricao]);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executa todas as migrações pendentes para um alias.
|
||||
* Idempotente: cada migração roda uma única vez.
|
||||
*
|
||||
* @param {string} alias
|
||||
* @param {boolean} [silencioso=false] - Se true, não loga no console
|
||||
* @returns {Promise<number>} Quantidade de migrações executadas
|
||||
*/
|
||||
async function executarMigracoes(alias, silencioso) {
|
||||
if (!silencioso) console.log(`📦 Verificando migrações para "${alias}"...`);
|
||||
|
||||
const driver = db.driverOf(alias);
|
||||
if (driver !== 'firebird') {
|
||||
if (!silencioso) console.log(` ⏭️ Driver "${driver}" — sem migrações DDL`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
await garantirControle(alias);
|
||||
|
||||
let executadas = 0;
|
||||
for (const mig of MIGRACOES) {
|
||||
if (await migracaoJaExecutada(alias, mig.id)) continue;
|
||||
|
||||
if (!silencioso) console.log(` ▶️ [${mig.id}] ${mig.descricao}`);
|
||||
|
||||
let erros = 0;
|
||||
for (const cmd of mig.sql) {
|
||||
try {
|
||||
await db.execute(alias, cmd);
|
||||
} catch (e) {
|
||||
if (e.message.includes('already exists') || e.message.includes('Violation') || e.message.includes('duplicate')) {
|
||||
continue; // idempotente
|
||||
}
|
||||
if (!silencioso) console.log(` ❌ ${e.message.substring(0, 100)}`);
|
||||
erros++;
|
||||
}
|
||||
}
|
||||
|
||||
if (erros === 0) {
|
||||
if (typeof mig.after === 'function') {
|
||||
try { await mig.after(alias); } catch (_) {}
|
||||
}
|
||||
await registrarMigracao(alias, mig.id, mig.descricao);
|
||||
executadas++;
|
||||
}
|
||||
}
|
||||
|
||||
if (executadas > 0 && !silencioso) console.log(` ✅ ${executadas} migração(ões) aplicada(s)`);
|
||||
else if (!silencioso) console.log(` ✅ Nenhuma migração pendente`);
|
||||
|
||||
return executadas;
|
||||
}
|
||||
|
||||
module.exports = { executarMigracoes, MIGRACOES };
|
||||
Reference in New Issue
Block a user