Pular para o conteúdo

Escalares próprios

Data, dinheiro e CPF como tipo — validados na fronteira, uma vez.

Um campo String que na verdade é uma data acaba validado em quinze lugares — e em catorze deles com uma regra ligeiramente diferente. Um escalar próprio move a validação para a fronteira, onde ela acontece uma vez.

dataforge
adopt Arcane.Lavra as Lavra
adopt Arcane.Time as T

action data_para_texto(valor):
    yield str(valor)

action data_de_texto(texto):
    partes := texto.split("-")
    given len(partes) is not 3:
        trigger "uma Data é 'AAAA-MM-DD'"
    yield texto

esq := Lavra.esquema("agenda")
Lavra.escalar(esq, "Data", data_para_texto, data_de_texto,
              "uma data no formato AAAA-MM-DD")

record Evento:
    id: Integer
    quando: String

Lavra.tipo(esq, Evento)
Lavra.campo(esq, "Evento", "quando", "Data!")
Lavra.busca(esq, "evento", "Evento",
    resolve := lambda r, a, c => Evento(1, "2026-09-22"))
Lavra.conferir(esq)

r := Lavra.executar(esq, "busca:\n    evento:\n        quando")
assert r["dados"]["evento"]["quando"] is "2026-09-22"
out r["dados"]

A validação acontece na entrada, e a recusa é clara#

dataforge
adopt Arcane.Lavra as Lavra

action de_texto(texto):
    given len(texto.split("-")) is not 3:
        // 'Lavra.erro' vira um erro da RESPOSTA, com código; um
        // 'trigger' de texto vira falha do servidor, e o cliente
        // recebe 500 onde devia receber "o argumento está errado".
        trigger Lavra.erro("uma Data é 'AAAA-MM-DD'", "argumento")
    yield texto

esq := Lavra.esquema("a")
Lavra.escalar(esq, "Data", lambda v => str(v), de_texto)
Lavra.busca(esq, "quando", "String",
    args := {"dia": "Data!"}, resolve := lambda r, a, c => a["dia"])
Lavra.conferir(esq)

bom := Lavra.executar(esq, 'busca:\n    quando(dia: "2026-01-01")')
assert bom["dados"]["quando"] is "2026-01-01"

ruim := Lavra.executar(esq, 'busca:\n    quando(dia: "ontem")')
assert len(ruim["erros"]) is 1
out ruim["erros"][0]["mensagem"]

Os quatro que quase todo esquema quer#

EscalarPor que não String
Data, DataHorafuso, formato e ordenação — e um String não ordena como data
DinheiroFloat não serve: 0,1 + 0,2 não é 0,3. Use Decimal, e transporte como texto
Email, Cpfa validação passa a existir num lugar só, e o tipo documenta
URLrecusar javascript: na fronteira é mais barato que em cada tela