Pular para conteúdo

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:

  1. Segurança: Usa prepared statements prevenindo SQL injection
  2. Condicional: Deleta apenas registros que atendem condições WHERE
  3. Confirmação: Retorna count de registros deletados
  4. Auditoria: Permite verificar se operação foi bem-sucedida
  5. Previne acidentes: Requer conditions obrigatório

Como funciona internamente?

Quando o POSTGRESQL DELETE é executado, o sistema:

  1. Valida config: Verifica credenciais PostgreSQL
  2. Valida conditions: OBRIGATÓRIO ter WHERE (previne delete total)
  3. Substitui variáveis: Troca {{variavel}} em conditions
  4. Monta SQL: Cria DELETE com placeholders ($1, $2...) seguros
  5. Executa: Envia para PostgreSQL com valores parametrizados
  6. Retorna: Devolve rowCount (quantos deletados) e flag deleted (boolean)
  7. 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

  1. Cancelar pedido: "Remover pedido cancelado pelo cliente"
  2. Excluir conta: "Deletar conta de usuário (GDPR/LGPD)"
  3. Limpar dados temporários: "Remover sessões expiradas"
  4. Remover item: "Excluir produto descontinuado"
  5. 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