Ir para o conteúdo

Conectando ao PostgreSQL

Problema: você desenvolveu em SQLite e agora quer rodar a mesma aplicação em PostgreSQL — sem reescrever queries, e ajustando o pool de conexões pra produção.

Solução: o banco é identificado pela URL. Trocar de SQLite pra PostgreSQL é trocar a string de conexão; o mesmo modelo, as mesmas queries e migrações valem pros dois. O PostgreSQL roda via postgres.js (async-only).

A teoria em uma frase

createEngine(url) faz parse da URL (parseDatabaseUrl), escolhe o dialeto, e instancia o driver certo. O dialeto compila a mesma AST pra SQL idiomática de cada banco (? no SQLite, $1 no Postgres; ILIKE nativo no Postgres).

1. Instale o driver

SQLite usa o node:sqlite embutido; PostgreSQL precisa do postgres:

npm install postgres

2. Troque a URL

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

// dev
const dev = createEngine("sqlite:///app.db");

// produção — só a string muda
const prod = createEngine("postgresql://app:secret@db.internal:5432/app");

Sufixo de driver async é aceito

URLs no estilo SQLAlchemy com sufixo de driver (postgresql+asyncpg://..., sqlite+aiosqlite://...) são aceitas — o sufixo é ignorado, o dialeto vem do scheme base. Útil pra reusar a mesma DATABASE_URL de um backend Python.

3. Ajuste o pool (produção)

PostgreSQL é async e usa um pool de conexões. Ajuste pelo segundo argumento:

const engine = createEngine("postgresql://app:secret@db.internal/app", {
  pool: {
    size: 10,             // máx. de conexões simultâneas
    idleTimeoutMs: 30_000, // fecha conexões ociosas após 30s
    connectTimeoutMs: 5_000, // desiste de conectar após 5s
  },
});

Pool é ignorado no SQLite

SQLite é uma conexão única (sync ou async) — as opções de pool não se aplicam e são silenciosamente ignoradas. Só passe pool pra PostgreSQL.

4. Tudo async

PostgreSQL não tem engine síncrono (não existe driver sync sério no Node) — createSyncEngine lança em Postgres. Use createEngine e await:

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

const session = engine.session();
const users = await session.execute(select(User).where({ active: true })).all();
await session.close();

O resto da API é idêntico ao SQLite — terminais (.all/.first/.one/…), transações, streaming e o guard de mutação funcionam igual. Veja Executando queries.

5. Migrações no Postgres

A mesma migração roda nos dois bancos, com DDL idiomática por dialeto — basta dizer o dialeto ao runner:

const runner = new MigrationRunner(driver, "postgresql"); // em vez de "sqlite"

No PostgreSQL, column.enum(...) vira um CREATE TYPE ... AS ENUM nomeado, e alter_column é um ALTER direto (sem o table-rebuild que o SQLite exige). Veja o Fluxo de migrações.

PostgreSQL ainda não roda no CI do projeto

A introspecção, o enum nomeado e o pool existem e são compilados, mas ainda não são exercitados contra um Postgres real no CI (só SQLite é). Trate o caminho Postgres como beta e valide no seu ambiente — veja o Roadmap.

Recap

  • Banco identificado pela URL — trocar de banco é trocar a string.
  • createEngine(url, { pool: { size, idleTimeoutMs, connectTimeoutMs } }) pra Postgres.
  • PostgreSQL é async-only; SQLite ignora o pool.
  • Mesmo modelo, queries e migrações nos dois; DDL idiomática por dialeto.