Serialização (linha ↔ JSON)¶
Problema: uma linha do banco tem tipos nativos — Date, bigint, Uint8Array — que
não sobrevivem ao JSON.stringify sozinhos (bigint lança, Date vira string sem
controle, blob vira lixo). E quando um JSON chega de fora (request HTTP, fila), você
quer validar e coagir de volta pros tipos certos antes de gravar.
Solução: o tempest-db-js traz um par de funções que conhecem o schema do modelo —
toJSON/stringify pra sair, fromDict/parse pra entrar — à la
model_dump/model_validate do Pydantic.
A teoria em uma frase¶
A serialização é dirigida pelo modelo: cada função olha as colunas da classe e coage cada campo pelo tipo SQL dele. Colunas desconhecidas são ignoradas; obrigatórias que faltam viram erro de validação.
Saída: linha → JSON¶
import { Model, column, toJSON, stringify, toDict } from "tempest-db-js";
class Event extends Model {
static tablename = "events";
id = column.bigInteger().primaryKey(); // bigint
name = column.text().notNull();
at = column.datetime().notNull(); // Date
payload = column.blob().notNull(); // Uint8Array
}
const row = {
id: 9007199254740993n,
name: "deploy",
at: new Date("2026-06-29T12:00:00Z"),
payload: new Uint8Array([1, 2, 3]),
};
toJSON(Event, row);
// {
// id: "9007199254740993", // bigint → string (sem perder precisão)
// name: "deploy",
// at: "2026-06-29T12:00:00.000Z", // Date → ISO
// payload: "AQID", // Uint8Array → base64
// }
stringify(Event, row); // == JSON.stringify(toJSON(Event, row))
toDict vs toJSON
toDict(Model, row)devolve os valores nativos, restritos às colunas conhecidas (sem coerção) — útil pra passar adiante dentro do TS.toJSON(Model, row)devolve uma versão JSON-safe (Date→ISO,bigint→string,Uint8Array→base64) — pronta proJSON.stringify/ resposta HTTP.
Entrada: JSON/dict → linha validada¶
fromDict coage cada campo de volta pro tipo nativo (string→Date/bigint/Uint8Array,
JSON.parse em colunas json) e valida obrigatórios:
import { fromDict, parse, ValidationError } from "tempest-db-js";
const row = fromDict(Event, {
id: "9007199254740993", // string → bigint
name: "deploy",
at: "2026-06-29T12:00:00.000Z", // string → Date
payload: "AQID", // base64 → Uint8Array
});
row.at instanceof Date; // true
// parse = fromDict(Model, JSON.parse(json))
const fromHttp = parse(Event, requestBodyString);
Faltou uma coluna obrigatória (notNull e sem default)? ValidationError:
try {
fromDict(Event, { id: "1" }); // faltam name, at, payload
} catch (err) {
if (err instanceof ValidationError) {
console.error(err.message); // descreve as colunas obrigatórias ausentes
}
}
Onde isso encaixa numa API
Numa rota HTTP: parse(Model, await req.text()) pra validar o corpo na entrada, e
toJSON(Model, row) pra montar a resposta na saída. O BaseRepository já devolve
linhas nativas — serialize só na borda. Veja o exemplo REST API.
Recap¶
toJSON/stringify→ linha → JSON-safe (Date→ISO,bigint→string,blob→base64).toDict→ valores nativos restritos às colunas (sem coerção).fromDict/parse→ JSON/dict → linha validada e coagida; lançaValidationError.- Tudo dirigido pelo schema do modelo — uma fonte da verdade, igual ao Pydantic.