306 lines
13 KiB
JavaScript
306 lines
13 KiB
JavaScript
#!/usr/bin/env node
|
|
// pg-convert.js — Converte queries MySQL/adapter → PostgreSQL nativo
|
|
// Executa: node pg-convert.js
|
|
import { readFileSync, writeFileSync } from 'fs';
|
|
|
|
let src = readFileSync('./server.js', 'utf8');
|
|
|
|
// ── 1. Substituir ? por $n seqencial em cada pool.query / client.query ─────────
|
|
function replacePlaceholders(sql) {
|
|
let n = 0;
|
|
return sql.replace(/\?/g, () => `$${++n}`);
|
|
}
|
|
|
|
// Aplica em strings simples: pool.query('...?...', [...])
|
|
src = src.replace(/(pool|client)\.query\(('(?:[^'\\]|\\.)*')\s*,/g, (m, obj, str) => {
|
|
const raw = str.slice(1, -1);
|
|
if (raw.includes('SET ?') || raw.includes('DUPLICATE') || raw.includes('DATE_FORMAT')) return m;
|
|
return `${obj}.query('${replacePlaceholders(raw)}',`;
|
|
});
|
|
|
|
// Aplica em template literals: pool.query(`...?...`, [...])
|
|
src = src.replace(/(pool|client)\.query\((`(?:[^`\\]|\\.)*`)\s*,/g, (m, obj, tpl) => {
|
|
const inner = tpl.slice(1, -1);
|
|
if (inner.includes('SET ?') || inner.includes('DUPLICATE') || inner.includes('DATE_FORMAT')) return m;
|
|
return `${obj}.query(\`${replacePlaceholders(inner)}\`,`;
|
|
});
|
|
|
|
// ── 2. Corrigir lida = 1 / lida = 0 para booleano PG ──────────────────────────
|
|
src = src.replace(/SET lida = 1/g, 'SET lida = TRUE');
|
|
src = src.replace(/WHERE lida = 0/g, 'WHERE lida = FALSE');
|
|
|
|
// ── 3. Corrigir erro MySQL → PG ────────────────────────────────────────────────
|
|
src = src.replace(/'ER_DUP_ENTRY'/g, "'23505'");
|
|
|
|
// ── 4. DATE_FORMAT / CURDATE / DATE_SUB → PG equivalentes ────────────────────
|
|
src = src.replace(
|
|
/DATE_FORMAT\s*\(\s*"?dataVencimento"?\s*,\s*'%Y-%m'\s*\)/g,
|
|
`TO_CHAR("dataVencimento", 'YYYY-MM')`
|
|
);
|
|
src = src.replace(
|
|
/dataVencimento\s*>=\s*DATE_SUB\(CURDATE\(\)\s*,\s*INTERVAL\s*6\s*MONTH\)/g,
|
|
`"dataVencimento" >= NOW() - INTERVAL '6 months'`
|
|
);
|
|
src = src.replace(/GROUP BY mes/g, 'GROUP BY TO_CHAR("dataVencimento", \'YYYY-MM\')');
|
|
|
|
// ── 5. Remover SET FOREIGN_KEY_CHECKS / SET NAMES (MySQL-only) ─────────────────
|
|
src = src.replace(/\s*await pool\.query\('SET FOREIGN_KEY_CHECKS = [01]'\);\r?\n/g, '');
|
|
src = src.replace(/\s*await pool\.query\('SET NAMES utf8mb4'\);\r?\n/g, '');
|
|
src = src.replace(/\s*await pool\.query\('SET CHARACTER SET utf8mb4'\);\r?\n/g, '');
|
|
|
|
// ── 6. INSERT INTO table SET ? → buildInsert ───────────────────────────────────
|
|
// pacientes
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO pacientes SET ?', p);",
|
|
"await pool.query(buildInsert('pacientes', p));"
|
|
);
|
|
// dentistas
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO dentistas SET ?', { ...d, ordem });",
|
|
"await pool.query(buildInsert('dentistas', { ...d, ordem }));"
|
|
);
|
|
// especialidades
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO especialidades SET ?', { ...req.body, ordem });",
|
|
"await pool.query(buildInsert('especialidades', { ...req.body, ordem }));"
|
|
);
|
|
// planos
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO planos SET ?', req.body);",
|
|
"await pool.query(buildInsert('planos', req.body));"
|
|
);
|
|
// financeiro
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO financeiro SET ?', req.body);",
|
|
"await pool.query(buildInsert('financeiro', req.body));"
|
|
);
|
|
// leads
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO leads SET ?', req.body);",
|
|
"await pool.query(buildInsert('leads', req.body));"
|
|
);
|
|
// gto_items
|
|
src = src.replace(
|
|
"await pool.query('INSERT INTO gto_items SET ?', item);",
|
|
"await pool.query(buildInsert('gto_items', item));"
|
|
);
|
|
// procedimentos (inside connection)
|
|
src = src.replace(
|
|
"await connection.query('INSERT INTO procedimentos SET ?', payload);",
|
|
"await client.query(buildInsert('procedimentos', payload));"
|
|
);
|
|
src = src.replace(
|
|
/await connection\.query\('INSERT INTO procedimentos_valores_planos SET \?',\s*\{[^}]+\}\);\s*/g,
|
|
(m) => m.replace('connection', 'client').replace("SET ?', {", "SET ?', {").replace(
|
|
"await client.query('INSERT INTO procedimentos_valores_planos SET ?',",
|
|
"await client.query(buildInsert('procedimentos_valores_planos',"
|
|
)
|
|
);
|
|
|
|
// ── 7. UPDATE table SET ? WHERE id = ? → buildUpdate ─────────────────────────
|
|
src = src.replace(
|
|
"await pool.query('UPDATE pacientes SET ? WHERE id = ?', [req.body, req.params.id]);",
|
|
"await pool.query(buildUpdate('pacientes', req.body, 'id', req.params.id));"
|
|
);
|
|
src = src.replace(
|
|
"await pool.query('UPDATE dentistas SET ? WHERE id = ?', [req.body, req.params.id]);",
|
|
"await pool.query(buildUpdate('dentistas', req.body, 'id', req.params.id));"
|
|
);
|
|
src = src.replace(
|
|
"await pool.query('UPDATE especialidades SET ? WHERE id = ?', [req.body, req.params.id]);",
|
|
"await pool.query(buildUpdate('especialidades', req.body, 'id', req.params.id));"
|
|
);
|
|
src = src.replace(
|
|
"await pool.query('UPDATE planos SET ? WHERE id = ?', [req.body, req.params.id]);",
|
|
"await pool.query(buildUpdate('planos', req.body, 'id', req.params.id));"
|
|
);
|
|
src = src.replace(
|
|
"await pool.query('UPDATE financeiro SET ? WHERE id = ?', [req.body, req.params.id]);",
|
|
"await pool.query(buildUpdate('financeiro', req.body, 'id', req.params.id));"
|
|
);
|
|
src = src.replace(
|
|
"await connection.query('UPDATE procedimentos SET ? WHERE id = ?', [updateData, req.params.id]);",
|
|
"await client.query(buildUpdate('procedimentos', updateData, 'id', req.params.id));"
|
|
);
|
|
|
|
// ── 8. Corrigir pool.getConnection() → withTransaction pattern ────────────────
|
|
// dentistas/reorder
|
|
src = src.replace(
|
|
`app.put('/api/dentistas/reorder', async (req, res) => {
|
|
const { orders } = req.body; // Array of {id, ordem}
|
|
const connection = await pool.getConnection();
|
|
try {
|
|
await connection.beginTransaction();
|
|
for (const item of orders) {
|
|
await connection.query('UPDATE dentistas SET ordem = ? WHERE id = ?', [item.ordem, item.id]);
|
|
}
|
|
await connection.commit();
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
await connection.rollback();
|
|
res.status(500).json({ error: err.message });
|
|
} finally { connection.release(); }
|
|
});`,
|
|
`app.put('/api/dentistas/reorder', async (req, res) => {
|
|
const { orders } = req.body;
|
|
try {
|
|
await withTransaction(async (client) => {
|
|
for (const item of orders) {
|
|
await client.query('UPDATE dentistas SET ordem = $1 WHERE id = $2', [item.ordem, item.id]);
|
|
}
|
|
});
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});`
|
|
);
|
|
|
|
// especialidades/reorder
|
|
src = src.replace(
|
|
`app.put('/api/especialidades/reorder', async (req, res) => {
|
|
const { orders } = req.body; // Array of {id, ordem}
|
|
const connection = await pool.getConnection();
|
|
try {
|
|
await connection.beginTransaction();
|
|
for (const item of orders) {
|
|
await connection.query('UPDATE especialidades SET ordem = ? WHERE id = ?', [item.ordem, item.id]);
|
|
}
|
|
await connection.commit();
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
await connection.rollback();
|
|
res.status(500).json({ error: err.message });
|
|
} finally { connection.release(); }
|
|
});`,
|
|
`app.put('/api/especialidades/reorder', async (req, res) => {
|
|
const { orders } = req.body;
|
|
try {
|
|
await withTransaction(async (client) => {
|
|
for (const item of orders) {
|
|
await client.query('UPDATE especialidades SET ordem = $1 WHERE id = $2', [item.ordem, item.id]);
|
|
}
|
|
});
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});`
|
|
);
|
|
|
|
// procedimentos/reorder
|
|
src = src.replace(
|
|
`app.put('/api/procedimentos/reorder', async (req, res) => {
|
|
const { orders } = req.body; // Array of {id, ordem}
|
|
const connection = await pool.getConnection();
|
|
try {
|
|
await connection.beginTransaction();
|
|
for (const item of orders) {
|
|
await connection.query('UPDATE procedimentos SET ordem = ? WHERE id = ?', [item.ordem, item.id]);
|
|
}
|
|
await connection.commit();
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
await connection.rollback();
|
|
res.status(500).json({ error: err.message });
|
|
} finally { connection.release(); }
|
|
});`,
|
|
`app.put('/api/procedimentos/reorder', async (req, res) => {
|
|
const { orders } = req.body;
|
|
try {
|
|
await withTransaction(async (client) => {
|
|
for (const item of orders) {
|
|
await client.query('UPDATE procedimentos SET ordem = $1 WHERE id = $2', [item.ordem, item.id]);
|
|
}
|
|
});
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});`
|
|
);
|
|
|
|
// DELETE dentista (transaction)
|
|
src = src.replace(
|
|
`app.delete('/api/dentistas/:id', async (req, res) => {
|
|
const connection = await pool.getConnection();
|
|
try {
|
|
const { id } = req.params;
|
|
await connection.beginTransaction();
|
|
|
|
// 1. Remove Google Tokens associated with this dentist
|
|
await connection.query('DELETE FROM google_tokens WHERE owner_id = ?', [id]);
|
|
|
|
// 2. Remove clinical links (if any)
|
|
await connection.query('DELETE FROM vinculos WHERE usuario_id = ?', [id]);
|
|
|
|
// 3. Set to NULL in agendamentos if it exists
|
|
await connection.query('UPDATE agendamentos SET dentistaId = NULL WHERE dentistaId = ?', [id]);
|
|
|
|
// 4. Delete from dentistas table
|
|
await connection.query('DELETE FROM dentistas WHERE id = ?', [id]);
|
|
|
|
await connection.commit();
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
await connection.rollback();
|
|
console.error('Error deleting dentist:', err);
|
|
res.status(500).json({ error: err.message });
|
|
} finally {
|
|
connection.release();
|
|
}
|
|
});`,
|
|
`app.delete('/api/dentistas/:id', async (req, res) => {
|
|
const { id } = req.params;
|
|
try {
|
|
await withTransaction(async (client) => {
|
|
await client.query('DELETE FROM google_tokens WHERE owner_id = $1', [id]);
|
|
await client.query('DELETE FROM vinculos WHERE usuario_id = $1', [id]);
|
|
await client.query('UPDATE agendamentos SET "dentistaId" = NULL WHERE "dentistaId" = $1', [id]);
|
|
await client.query('DELETE FROM dentistas WHERE id = $1', [id]);
|
|
});
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
console.error('Error deleting dentist:', err);
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});`
|
|
);
|
|
|
|
// ── 9. Corrigir google/events pool.query sem placeholders ─────────────────────
|
|
src = src.replace(
|
|
"const [tokenRows] = await pool.query('SELECT * FROM google_tokens');",
|
|
"const { rows: tokenRows } = await pool.query('SELECT * FROM google_tokens');"
|
|
);
|
|
src = src.replace(
|
|
"const [dent] = await pool.query('SELECT nome FROM dentistas WHERE id = ?', [tokenData.owner_id]);",
|
|
"const { rows: dent } = await pool.query('SELECT nome FROM dentistas WHERE id = $1', [tokenData.owner_id]);"
|
|
);
|
|
src = src.replace(
|
|
"if (dent[0]) ownerName = dent[0].nome;",
|
|
"if (dent[0]) ownerName = dent[0].nome;"
|
|
);
|
|
src = src.replace(
|
|
"const [rows] = await pool.query('SELECT data FROM settings WHERE id = \"main\"');",
|
|
"const { rows } = await pool.query(\"SELECT data FROM settings WHERE id = 'main'\");"
|
|
);
|
|
src = src.replace(
|
|
"const [dName] = await pool.query('SELECT nome FROM dentistas WHERE id = ?', [dentistId]);",
|
|
"const { rows: dName } = await pool.query('SELECT nome FROM dentistas WHERE id = $1', [dentistId]);"
|
|
);
|
|
|
|
// ── 10. Corrigir destructuring [rows] → { rows } para pool.query simples ──────
|
|
// Algumas queries sem parâmetro ainda usam o padrão antigo [rows]
|
|
src = src.replace(
|
|
/const \[rows\] = await pool\.query\('SELECT \* FROM (\w+)'\);/g,
|
|
"const { rows } = await pool.query('SELECT * FROM $1');"
|
|
);
|
|
src = src.replace(
|
|
/const \[rows\] = await pool\.query\('SELECT \* FROM (\w+) ORDER BY ([^']+)'\);/g,
|
|
"const { rows } = await pool.query('SELECT * FROM $1 ORDER BY $2');"
|
|
);
|
|
|
|
// ── 11. Remover initTables (função morta MySQL DDL) ───────────────────────────
|
|
const initStart = src.indexOf('// Initialization: Create tables if not exist');
|
|
const initEnd = src.indexOf('\n// generateIntelligentNotifications');
|
|
if (initStart > 0 && initEnd > initStart) {
|
|
src = src.slice(0, initStart) + src.slice(initEnd + 1);
|
|
}
|
|
|
|
writeFileSync('./server.js', src, 'utf8');
|
|
console.log('[pg-convert] Done! server.js updated in place.');
|