Validação, ganchos e marcas
O que o modelo recusa antes de gravar, o que ele preenche sozinho, e a remoção que não apaga.
Três coisas que todo sistema escreve à mão em cada lugar — e que, escritas em cada lugar, são esquecidas em um deles.
Validar devolve TODOS os problemas#
Parar no primeiro erro faz o formulário ser corrigido campo a campo, num vaivém: a pessoa conserta o nome, envia, e descobre que o e-mail também estava errado. A lista inteira é o que a tela precisa.
dataforge
adopt Arcane.Forge as Forge
db := Forge.memoria()
Forge.limpar_modelos()
Usuario := Forge.modelo("Usuario", {"id": "Serial"})
Usuario.campo("nome", "Texto", obrigatorio := yes)
Usuario.campo("email", "Texto", obrigatorio := yes, unico := yes)
Usuario.campo("idade", "Inteiro", padrao := 0)
Forge.ligar(Usuario, db)
Usuario.migrar()
// Faltam os DOIS obrigatorios, e a lista traz os dois.
problemas := Usuario.validar({"idade": 30})
out $"{len(problemas)} problema(s) — e nao so o primeiro:"
cycle p in problemas:
out $" {p['campo']}: {p['motivo']}"
assert len(problemas) is 2
assert len(Usuario.validar({"nome": "Ana", "email": "ana@x.com", "idade": 30})) is 0
out "o valido passa"
Forge.fechar(db)Ganchos#
dataforge
adopt Arcane.Forge as Forge
db := Forge.memoria()
Forge.limpar_modelos()
Conta := Forge.modelo("Conta", {"id": "Serial", "email": "Texto"})
Forge.ligar(Conta, db)
Conta.migrar()
// O e-mail entra sempre em minusculas. Normalizar na aplicacao e o
// que faz o comportamento deixar de depender do motor: o MySQL
// compara sem diferenciar maiusculas, e o Postgres diferencia.
action normalizar(dados):
dados["email"] := (dados["email"] ?? "").lower()
yield dados
Conta.antes_de_salvar(normalizar)
c := Conta.criar({"email": "Ana@LOJA.com"})
out $"gravado como: {c['email']}"
assert c["email"] is "ana@loja.com"
Forge.fechar(db)Marcas de tempo e remoção suave#
| O que faz | Por que | |
|---|---|---|
com_marcas_de_tempo() | criado_em e atualizado_em, mantidos sozinhos | a pergunta “quando isto mudou?” aparece em toda investigação, e não dá para responder depois |
com_remocao_suave() | remover marca; as buscas ignoram o marcado | apagar de verdade é irreversível, e o pedido mais comum depois de um apagar é desfazer |
dataforge
adopt Arcane.Forge as Forge
db := Forge.memoria()
Forge.limpar_modelos()
Nota := Forge.modelo("Nota", {"id": "Serial", "texto": "Texto"})
Nota.com_marcas_de_tempo()
Nota.com_remocao_suave()
Forge.ligar(Nota, db)
Nota.migrar()
n := Nota.criar({"texto": "primeira"})
out $"criado_em preenchido: {n['criado_em'] isnt void}"
Nota.criar({"texto": "segunda"})
assert Nota.contar() is 2
Nota.remover(n["id"])
// As buscas ignoram o removido — mas ele continua no banco.
assert Nota.contar() is 1
out "removida da vista, e nao do disco"
Forge.fechar(db)