Ir para o conteúdo

tempest-db-js

tempest-db-js é um ORM type-safe e class-based para TypeScript. Ele traz a ergonomia do SQLAlchemy 2.0 — modelos declarados como classes, schema como fonte única da verdade — pro mundo JS/TS, com inferência de tipos forte do começo ao fim: você define a tabela uma vez e o TypeScript sabe o formato de cada linha em todo select, insert, update e delete.

É a camada de dados do futuro tempest-ts-sdk.

Idiomas / Languages — esta documentação é bilíngue. Use o seletor de idioma no topo da página pra alternar entre Português (BR) e English (US).

Status: alpha (v0.2.0) — publicado no npm

O caminho completo funciona de ponta a ponta: schema declarativo, query builder tipado, execução real em SQLite (testada contra node:sqlite), joins, relations, migrações estilo Alembic e um BaseRepository tipado. A superfície pública ainda pode mudar antes da v1.0 — veja o Roadmap.

Por que tempest-db-js?

Você define o modelo uma vez, como classe — e o tempest-db-js infere todo o resto:

import { Model, column, type InferModel, type InferInsert } from "tempest-db-js";

class User extends Model {
  static tablename = "users";
  id = column.integer().primaryKey();
  name = column.text().notNull();
  age = column.integer().notNull();
  nickname = column.text();                  // anulável
  createdAt = column.timestamp().default(new Date());
}

type UserRow    = InferModel<typeof User>;
// { id: number; name: string; age: number; nickname: string | null; createdAt: Date | null }

type UserInsert = InferInsert<typeof User>;
// { name: string; age: number; nickname: string | null; id?: number; createdAt?: Date | null }

Sem interface manual, sem passo de codegen, sem schema e tipo divergindo. A classe é a fonte da verdade — igual ao Mapped[...] declarativo do SQLAlchemy.

E a inferência se propaga pras queries:

import { select } from "tempest-db-js";

// O resultado é inferido como UserRow[] — sem anotação manual
const adults = select(User).where({ age: { gt: 18 } }).orderBy("age", "desc");

// Projeção infere Pick<UserRow, "id" | "name">[]
const names = select(User, ["id", "name"]);

A realidade do TypeScript

O SQLAlchemy lê Mapped[int] em runtime via descriptors; o TypeScript apaga os tipos na compilação. O tempest-db-js contorna isso fazendo cada coluna ser um builder com tipo em runtime (column.integer()) que carrega ao mesmo tempo o tipo SQL (runtime) e o tipo estático (inferência).

Você ganha a ergonomia de classes e inferência forte de resultado de query. O trade-off: a linha retornada é um objeto plano inferido, não uma instância de classe com métodos (active-record fica como objetivo pós-MVP). Detalhes em Arquitetura.

Comece em 1 minuto

npm install tempest-db-js

SQLite não precisa de driver extra (usa o node:sqlite embutido do Node). Pra PostgreSQL, npm install postgres.

import { Model, column, select, insert, createSyncEngine } from "tempest-db-js";

class Task extends Model {
  static tablename = "tasks";
  id = column.integer().primaryKey();
  title = column.text().notNull();
  done = column.boolean().notNull();
}

const engine = createSyncEngine("sqlite://:memory:");
const session = engine.session();

session.execute(insert(Task).values({ title: "escrever docs", done: false }));

const pending = session.execute(select(Task).where({ done: false })).all();
// `pending` é { id: number; title: string; done: boolean }[] — sem anotação manual

A execução é real e testada contra um banco SQLite de verdade (node:sqlite): coerção de tipos, RETURNING, transações e rollback. PostgreSQL roda via postgres.js.

Novo por aqui? Siga o Tutorial — Comece aqui: do primeiro modelo a executar queries contra um banco, um conceito por página.

O que tem dentro

Área Páginas
Tutorial Comece aqui · Modelos · Consultas · Inserir, atualizar, deletar · Executando queries · Joins
Receitas created_at/updated_at · Paginação · Transações · JSON e enum · Serialização · PostgreSQL
Exemplos Todo CLI · Blog · REST API · Fluxo de migrações
Guia Arquitetura · Repository · Migrações · Referência da API
Projeto Roadmap · Contribuindo · Changelog

Princípios

  1. Tipo é o produto. Cada feature entrega testes de tipo, não só de runtime.
  2. Zero SQL por string. Sempre parametrizado — injection-safe por construção.
  3. Class-first, mas honesto com o TS. Abraçamos o que o TS faz bem.
  4. Docs seguem o código. Bilíngue, estilo tutorial, no mesmo commit.