-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
content(api)
: criar novo status deleted
#348
Comments
content(api)
: criar novo status deleted
Você acredita ter necessidade de criar um novo status Assim ficaria organizado e teríamos acesso direto para consulta, mas o Isso nos ajudaria a manter o último status do conteúdo antes dele ter sido deletado e poderíamos contar com uma das maravilhas de se usar soft delete: análise de dados. Com o tempo poderíamos saber se a maioria dos conteúdos são deletadas enquanto ainda estão com o status Uma pergunta: Pergunto isso pois se não tiver e não formos adicionar esta possibilidade no futuro, o campo EDIT: Verifiquei na issue #349 que hoje o status |
Ótimo ponto @tembra mas na minha visão fica menos semântico, por exemplo, imagina montar uma query que agrupa todos os posts pelos seus status ou o Talvez se um dia quisermos fazer essa leitura dos dados, a modelagem do banco deveria ser INSERT ONLY (o que eu acharia ótimo), ou salvar essas ações em outro lugar para consulta. Dado a isso, voto em manter uma modelagem mais comum e previsível, mesmo que nesse caso seja um dado redundante.
Na verdade o status |
Sabe aquele tipo de problema que você acha que vai matar rapidão, mas quem te mata é o problema? 😂 então, quem está me matando é a CONSTRAINT UNIQUE envolvendo Por exemplo, considerando o que está em Produção, o segundo insert daria problema porque ele possui o mesmo INSERT INTO contents (owner_id, slug, title, body, status) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug', 'title', 'body', 'published');
INSERT INTO contents (owner_id, slug, title, body, status) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug', 'title', 'body', 'published'); Resultado:
Isso porque temos isso de constraint: Agora, rodando uma nova migration para considerar também o exports.up = async (pgm) => {
await pgm.addColumns('contents', {
deleted_at: {
type: 'timestamp with time zone',
notNull: false,
},
});
await pgm.dropConstraint('contents', 'contents_uniqueness_fkey');
await pgm.addConstraint('contents', 'contents_uniqueness_fkey', 'UNIQUE (owner_id, slug, deleted_at)');
}; Show, atualizou a constraint: Só que agora eu posso fazer múltiplos inserts, pois por padrão uma coluna Que E procurando na internet, esse é o comportamento mesmo e estão sugerindo uma alternativa com índices, mas puts, que bizarro demais:
E agora? Alguém conhece alguma alternativa mais elegante? |
Bom, não consigo encontrar outra solução a não ser deletar a constraint e substituir por um índice. Fiz da seguinte forma no arquivo de migração: // pgm.createIndex(tablename, columns, options)
await pgm.createIndex('contents', ['owner_id', 'slug', '(deleted_at IS NULL)'], {
name: 'contents_owner_id_slug_deleted_at_unique_index',
unique: true,
where: 'deleted_at IS NULL',
}); O que gera: CREATE UNIQUE INDEX "contents_owner_id_slug_deleted_at_unique_index" ON "contents" ("owner_id", "slug", (deleted_at IS NULL)) WHERE deleted_at IS NULL; E o comportamento de ir fazendo INSERTs em relação ao índice e o INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug', 'title', 'body', 'published', NULL);
-- OK
INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug', 'title', 'body', 'published', NULL);
-- NOT OK
-- ERROR: duplicate key value violates unique constraint "contents_owner_id_slug_deleted_at_unique_index"
-- DETAIL: Key (owner_id, slug, (deleted_at IS NULL))=(88717cd5-d255-4ada-a235-e8c38bffe173, slug, t) already exists.
INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug-sera-deletado', 'title', 'body', 'published', NULL);
-- OK
INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug-sera-deletado', 'title', 'body', 'deleted', NULL);
-- NOT OK: ta certo, pois só mudei o `status` para `deleted` sem ter adicionado um `deleted_at`
-- ERROR: duplicate key value violates unique constraint "contents_owner_id_slug_deleted_at_unique_index"
-- DETAIL: Key (owner_id, slug, (deleted_at IS NULL))=(88717cd5-d255-4ada-a235-e8c38bffe173, slug-sera-deletado, t) already exists.
INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug-sera-deletado', 'title', 'body', 'deleted', NOW());
-- OK: não esbarra mais por conta do `deleted_at`
INSERT INTO contents (owner_id, slug, title, body, status, deleted_at) VALUES ('88717cd5-d255-4ada-a235-e8c38bffe173', 'slug-sera-deletado', 'title', 'body', 'deleted', NOW());
-- OK: não esbarra mais por conta do `deleted_at` O mesmo comportamento se garante se eu tentar sair fazendo |
Uma alternativa nada semântica seria usar uma data específica do passado no lugar de |
E se eu te falar que sempre preencher uma data foi a primeira alternativa que pensei quando comecei a entender que não daria para resolver usando constraint e null 😂 🤝👍 |
Elegante? Nada! Funciona? Perfeitamente... hahaha |
@filipedeschamps aqui na empresa utilizamos 2 informações para registros apagados E o campo int = 0 não daria o mesmo problema certo? |
@rodrigoKulb o problema seria que o mesmo usuário não conseguiria apagar duas vezes a postagem com o mesmo Edit para melhor clareza: Esse problema é se a sugestão foi usar o |
Interessantíssimo @rodrigoKulb 👍 no nosso caso o id do usuário é um E acho ótimo anotar esse tipo de informação, mas sugiro não fazer nessa versão (até porque vamos ter tudo isso registrado em logs caso a gente precise investigar). E daí numa próxima interação fazer a anotação de quem editou um conteúdo (não somente deletou), até porque esse "soft delete" é uma "edição de conteúdo" (que altera o status para |
@aprendendofelipe verdade! 😅️
@filipedeschamps verdade 😅️ show! Seguimos quebrando a cabeça aqui! |
Só para jogar uma ideia aqui, se utilizarmos o campo: Assim poderia utilizar o ZERO sem problemas = Jan 01 1970 00:00:00 GMT+0000 |
@rodrigoKulb gosto de você por estar com a mesma raiva que eu em ter que usar um índice para controlar o Mas apesar dessa ideia tecnicamente ser válida, semanticamente fica estranho o |
Comentando aqui somente pra registrar a normalidade de se usar unique index em soft deletes: Trabalho há +10 anos com grandes ERPs e todos os que possuem soft delete utilizam desta estratégia. Seja com banco de dados SQL Server, Oracle ou Postgres. Sempre é criado um índice único contendo o flag do registro de deleção. Para entendermos melhor o porquê do Postgres permitir múltiplos nulos devemos lembrar da tradução da palavra Tendo isto em mente entendemos que a maioria das implementações dos SGBDs utiliza Dessa forma agregando agora o conceito de Ainda sim em alguns SGBDs (como no Postgres) é preciso informar explicitamente que determinada coluna poderá conter o valor CREATE UNIQUE INDEX "contents_owner_id_slug_deleted_at_unique_index"
ON "contents" ("owner_id", "slug", (deleted_at IS NULL))
WHERE deleted_at IS NULL; |
Explicação sensacional @tembra e isso me tranquiliza bastante sobre a escolha então de criarmos o índice para controlar isso 🤝 |
Fechado pelo PR #431 🤝 |
Turma, olha o que está por vir na versão 15 do Postgres 😍 https://blog.rustprooflabs.com/2022/07/postgres-15-unique-improvement-with-null |
|
Contexto
Para fazer um "soft delete" de um
content
, vamos criar um novo statusdeleted
e um novo campodeleted_at
.Execução
Hoje a tabela
contents
possui uma constraint entreowner_id
eslug
para que um usuário não possa criar posts com um mesmo identificador.tabnews.com.br/infra/migrations/1649621949432_create-content-table.js
Line 70 in 1d57c1e
O problema de manter essa constraint, é que acaba não se tornando mais possível deletar
contents
que acabem tendo o mesmo slug. Por exemplo:/filipedeschamps/teste
/filipedeschamps/teste
, o backend vai reclamar, pois já existe essa combinação, mas uma delas (a primeira) está com o statusdeleted
.E se adicionar o
status
nessa constraint, não adianta também, pois daí eu não vou poder soft delete dois conteúdos com o mesmo indicador.Então em conversas passadas com o @rodrigoKulb , ele fez uma sugestão de criar uma propriedade
deleted_at
e adicionar ela na constraint. Achei genial.Fora isso, uma vez um
content
ganhando ostatus
dedeleted
, não é mais possível voltar atrás.The text was updated successfully, but these errors were encountered: