POSTGRESQL DELETE - Deletar Registro
O que é este Node?
O POSTGRESQL DELETE é o node responsável por deletar registros de tabelas PostgreSQL de forma segura usando prepared statements.
Por que este Node existe?
Deletar dados é operação crítica em aplicações. O POSTGRESQL DELETE existe para:
- Segurança: Usa prepared statements prevenindo SQL injection
- Condicional: Deleta apenas registros que atendem condições WHERE
- Confirmação: Retorna count de registros deletados
- Auditoria: Permite verificar se operação foi bem-sucedida
- Previne acidentes: Requer conditions obrigatório
Como funciona internamente?
Quando o POSTGRESQL DELETE é executado, o sistema:
- Valida config: Verifica credenciais PostgreSQL
- Valida conditions: OBRIGATÓRIO ter WHERE (previne delete total)
- Substitui variáveis: Troca {{variavel}} em conditions
- Monta SQL: Cria DELETE com placeholders ($1, $2...) seguros
- Executa: Envia para PostgreSQL com valores parametrizados
- Retorna: Devolve rowCount (quantos deletados) e flag deleted (boolean)
- Se erro: Lança exceção (foreign key constraint, etc.)
Código interno (postgresql.executor.ts:156-177):
private async deleteRow(
pool: Pool,
table: string,
conditions: Record<string, any>,
context: ExecutionContext,
): Promise<any> {
const replacedConditions = this.replaceObjectVariables(conditions, context.variables);
const whereClause = Object.keys(replacedConditions)
.map((key, i) => `${key} = $${i + 1}`)
.join(' AND ');
const valueArray = Object.values(replacedConditions);
const query = `DELETE FROM ${table} WHERE ${whereClause}`;
const result = await pool.query(query, valueArray);
return {
rowCount: result.rowCount,
deleted: result.rowCount > 0,
};
}
Quando você DEVE usar este Node?
Use POSTGRESQL DELETE quando precisar remover registros permanentemente:
Casos de uso
- Cancelar pedido: "Remover pedido cancelado pelo cliente"
- Excluir conta: "Deletar conta de usuário (GDPR/LGPD)"
- Limpar dados temporários: "Remover sessões expiradas"
- Remover item: "Excluir produto descontinuado"
- Deleção condicional: "Remover apenas registros específicos"
Quando NÃO usar POSTGRESQL DELETE
- Soft delete: Use UPDATE para marcar como inativo (mantém histórico)
- Auditoria necessária: Marque como deletado ao invés de remover
- Relacionamentos: Verifique foreign keys antes (ON DELETE CASCADE/SET NULL)
- Sem condições: NUNCA delete sem WHERE (deletaria tudo!)
- Dados importantes: Considere soft delete ou arquivamento
Parâmetros Detalhados
config (object, obrigatório)
O que é: Configuração de conexão com PostgreSQL.
table (string, obrigatório)
O que é: Nome da tabela onde registros serão deletados.
conditions (object, obrigatório)
O que é: Condições WHERE para identificar quais registros deletar.
CRÍTICO: DELETE sem WHERE deletaria TODA a tabela! Sempre especifique conditions.
Flow completo para testar:
{
"name": "Teste PostgreSQL - Delete",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "ID para Deletar",
"parameters": {
"message": "ID do registro a deletar:",
"variable": "registroId"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Tem certeza que deseja deletar o registro {{registroId}}?\n\n1 - Sim, deletar\n2 - Não, cancelar"
}
}
},
{
"id": "input_2",
"type": "input",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Confirmação",
"parameters": {
"message": "Escolha:",
"variable": "confirmacao"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Confirmado?",
"parameters": {
"conditions": [
{
"variable": "confirmacao",
"operator": "equals",
"value": "1",
"nextNode": "postgres_1"
}
],
"defaultNextNode": "message_cancelled"
}
}
},
{
"id": "postgres_1",
"type": "postgresql",
"position": { "x": 1100, "y": 50 },
"data": {
"label": "Deletar",
"parameters": {
"operation": "delete",
"config": {
"host": "localhost",
"port": 5432,
"database": "crm",
"user": "app_user",
"password": "secure_password",
"ssl": false
},
"table": "clientes",
"conditions": {
"id": "{{registroId}}"
},
"responseVariable": "resultado"
}
}
},
{
"id": "message_deleted",
"type": "message",
"position": { "x": 1300, "y": 50 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "Registro {{registroId}} deletado com sucesso!\n\n{{resultado.rowCount}} registro(s) removido(s)."
}
}
},
{
"id": "message_cancelled",
"type": "message",
"position": { "x": 1100, "y": 150 },
"data": {
"label": "Cancelado",
"parameters": {
"message": "Operação cancelada. Nenhum registro foi deletado."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "message_1" },
{ "source": "message_1", "target": "input_2" },
{ "source": "input_2", "target": "condition_1" },
{ "source": "postgres_1", "target": "message_deleted" },
{ "source": "message_deleted", "target": "end_1" },
{ "source": "message_cancelled", "target": "end_1" }
]
}
Teste: Registro é deletado apenas se confirmado.
responseVariable (string, opcional)
O que é: Nome da variável para armazenar resultado no contexto.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| operation | string | Sim | Deve ser "delete" |
| config | object | Sim | Configuração de conexão PostgreSQL |
| table | string | Sim | Nome da tabela |
| conditions | object | Sim | Condições WHERE (OBRIGATÓRIO) |
| responseVariable | string | Não | Variável para armazenar resultado |
Exemplo 1: Limpar Sessões Expiradas
Objetivo: Remover sessões antigas automaticamente
JSON para Importar
{
"name": "PostgreSQL - Limpar Sessões",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "postgres_1",
"type": "postgresql",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Deletar Expiradas",
"parameters": {
"operation": "executeQuery",
"config": {
"host": "localhost",
"port": 5432,
"database": "app",
"user": "app_user",
"password": "secure_password",
"ssl": false
},
"query": "DELETE FROM sessions WHERE expires_at < CURRENT_TIMESTAMP",
"responseVariable": "resultado"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Resultado",
"parameters": {
"message": "Limpeza de sessões concluída!\n\n{{resultado.rowCount}} sessão(ões) expirada(s) removida(s)."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "postgres_1" },
{ "source": "postgres_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada:
Sistema: Limpeza de sessões concluída!
15 sessão(ões) expirada(s) removida(s).
Exemplo 2: Cancelar Pedido com Confirmação
Objetivo: Permitir cliente cancelar pedido pendente
JSON para Importar
{
"name": "PostgreSQL - Cancelar Pedido",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Número Pedido",
"parameters": {
"message": "Número do pedido a cancelar:",
"variable": "pedidoId"
}
}
},
{
"id": "postgres_buscar",
"type": "postgresql",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Buscar Pedido",
"parameters": {
"operation": "executeQuery",
"config": {
"host": "localhost",
"port": 5432,
"database": "ecommerce",
"user": "app_user",
"password": "secure_password",
"ssl": false
},
"query": "SELECT id, status, total FROM pedidos WHERE id = {{pedidoId}} AND cliente_id = '{{phone}}'",
"responseVariable": "pedido"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Existe?",
"parameters": {
"conditions": [
{
"variable": "pedido.rowCount",
"operator": "greater_than",
"value": 0,
"nextNode": "condition_2"
}
],
"defaultNextNode": "message_notfound"
}
}
},
{
"id": "condition_2",
"type": "condition",
"position": { "x": 900, "y": 50 },
"data": {
"label": "Status Válido?",
"parameters": {
"conditions": [
{
"variable": "pedido.rows[0].status",
"operator": "equals",
"value": "pendente",
"nextNode": "message_confirm"
}
],
"defaultNextNode": "message_invalid"
}
}
},
{
"id": "message_confirm",
"type": "message",
"position": { "x": 1100, "y": 0 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "Pedido #{{pedidoId}}\nTotal: R$ {{pedido.rows[0].total}}\n\nConfirma cancelamento?\n\n1 - Sim\n2 - Não"
}
}
},
{
"id": "input_2",
"type": "input",
"position": { "x": 1300, "y": 0 },
"data": {
"label": "Confirmação",
"parameters": {
"message": "Escolha:",
"variable": "confirmacao"
}
}
},
{
"id": "condition_3",
"type": "condition",
"position": { "x": 1500, "y": 0 },
"data": {
"label": "Confirmou?",
"parameters": {
"conditions": [
{
"variable": "confirmacao",
"operator": "equals",
"value": "1",
"nextNode": "postgres_delete"
}
],
"defaultNextNode": "message_cancelled"
}
}
},
{
"id": "postgres_delete",
"type": "postgresql",
"position": { "x": 1700, "y": -50 },
"data": {
"label": "Cancelar",
"parameters": {
"operation": "delete",
"config": {
"host": "localhost",
"port": 5432,
"database": "ecommerce",
"user": "app_user",
"password": "secure_password",
"ssl": false
},
"table": "pedidos",
"conditions": {
"id": "{{pedidoId}}",
"status": "pendente"
},
"responseVariable": "resultado"
}
}
},
{
"id": "message_success",
"type": "message",
"position": { "x": 1900, "y": -50 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "Pedido #{{pedidoId}} cancelado com sucesso!"
}
}
},
{
"id": "message_notfound",
"type": "message",
"position": { "x": 900, "y": 150 },
"data": {
"label": "Não Encontrado",
"parameters": {
"message": "Pedido não encontrado ou não pertence a você."
}
}
},
{
"id": "message_invalid",
"type": "message",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Status Inválido",
"parameters": {
"message": "Pedido já está {{pedido.rows[0].status}}. Não pode ser cancelado."
}
}
},
{
"id": "message_cancelled",
"type": "message",
"position": { "x": 1700, "y": 50 },
"data": {
"label": "Cancelado",
"parameters": {
"message": "Cancelamento não confirmado. Pedido mantido."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 2100, "y": 50 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "postgres_buscar" },
{ "source": "postgres_buscar", "target": "condition_1" },
{ "source": "condition_1", "target": "message_confirm" },
{ "source": "message_confirm", "target": "input_2" },
{ "source": "input_2", "target": "condition_3" },
{ "source": "postgres_delete", "target": "message_success" },
{ "source": "message_success", "target": "end_1" },
{ "source": "message_notfound", "target": "end_1" },
{ "source": "message_invalid", "target": "end_1" },
{ "source": "message_cancelled", "target": "end_1" }
]
}
Saída esperada:
Sistema: Número do pedido a cancelar:
Usuário: 1523
Sistema: Pedido #1523
Total: R$ 350.00
Confirma cancelamento?
1 - Sim
2 - Não
Usuário: 1
Sistema: Pedido #1523 cancelado com sucesso!
Resposta do Node
{
"rowCount": 1,
"deleted": true
}
Quando nenhum registro é deletado:
{
"rowCount": 0,
"deleted": false
}
Boas Práticas
✅ SIM:
- SEMPRE use conditions (WHERE) para evitar deletar toda tabela
- Confirme operação com usuário antes de deletar
- Verifique rowCount para confirmar deleção
- Use soft delete para dados importantes (UPDATE ativo = false)
- Considere foreign keys e ON DELETE CASCADE/SET NULL
- Teste conditions antes em SELECT
- Use transações para deletar registros relacionados
❌ NÃO:
- NUNCA delete sem WHERE (conditions obrigatório!)
- Não delete dados auditáveis (use soft delete)
- Não ignore foreign key constraints
- Não delete sem confirmar com usuário
- Não delete sem verificar relacionamentos
- Não use DELETE quando soft delete é apropriado
Dicas
💡 Soft Delete: Para auditoria, use UPDATE com campo deleted_at ao invés de DELETE
💡 rowCount = 0: Significa que nenhum registro atendeu conditions (não existe)
💡 Foreign Keys: Configure ON DELETE CASCADE para deletar relacionados ou SET NULL
💡 Teste primeiro: Execute SELECT com mesmas conditions para ver o que será deletado
💡 Transações: Para deletar múltiplos registros relacionados atomicamente
💡 RETURNING: PostgreSQL suporta RETURNING * em DELETE (use EXECUTEQUERY)
💡 Backup: Sempre tenha backups antes de operações de deleção em massa
Próximo Node
→ POSTGRESQL UPDATE - Atualizar registros → POSTGRESQL INSERT - Inserir registros → POSTGRESQL INSERTORUPDATE - Upsert (Insert ou Update) → POSTGRESQL EXECUTEQUERY - Consultas personalizadas