Exploração gerada no Claude a partir da proposta da Relational API v2
ORMs sempre viveram num limbo desconfortável: ou você escreve SQL puro e perde type-safety, ou usa um ORM que te trava quando precisa de algo complexo. Drizzle v2 ataca esse problema de frente.
A mudança parece pequena à primeira vista:
// v1
where: (pets, { eq }) => eq(pets.ownerId, 1)
// v2
where: { ownerId: 1 }Mas essa simplicidade superficial esconde algo mais profundo.
A API funciona em camadas. Você começa simples e descobre poder conforme precisa:
// Camada 1: O óbvio
where: { ownerId: 1 }
// Camada 2: Combinações (AND implícito)
where: { ownerId: 1, name: "pikachu" }
// Camada 3: Operadores explícitos
where: { OR: [{ ownerId: 1 }, { name: "pikachu" }] }
// Camada 4: Comparações complexas
where: { ownerId: { gt: 1, lte: 10 } }
// Camada 5: Escape hatch
where: { RAW: (pets, { sql }) => sql`lower(${pets.name}) = 'pikachu'` }Cada camada te dá mais controle, mas você nunca é forçado a conhecer todas de cara. Aprende conforme cresce.
Toda abstração precisa de uma saída de emergência. O momento em que você pensa "eu só preciso fazer X mas a API não deixa" é quando você abandona a ferramenta.
Drizzle entendeu isso. Sempre tem um RAW esperando quando você precisar. A API não tenta ser mais inteligente que você.
Isso aparece em todo canto:
- CSS Modules →
style={{ ... }} - React Hooks →
useEffect - Git →
--force
As melhores ferramentas sabem quando sair do caminho.
Compare as duas versões de declarar relações:
// v1: imports intermináveis
import { relations } from 'drizzle-orm';
import { users } from './users';
import { posts } from './posts';
// v2: contexto rico
relations(schema, (r) => ({
posts: {
author: r.one({
from: r.users.id,
to: r.posts.authorId,
})
}
}))O r carrega todo o conhecimento necessário. Você não perde tempo gerenciando imports - pensa direto no relacionamento.
Reduzir imports não é só conveniência. É reduzir carga cognitiva. Cada import é um contexto que você precisa carregar na cabeça.
Eles trocaram fields e references por from, to, one, many, through.
Tecnicamente? Talvez menos preciso.
Na prática? Infinitamente mais claro.
A API fala a língua do usuário, não da implementação interna. Quando você escreve r.one({ from: ..., to: ... }), você está pensando na direção do relacionamento, não em foreign keys.
Bom naming é sobre intenção, não exatidão.
Múltiplos filtros viram AND automaticamente:
where: { ownerId: 1, name: "pikachu" }Mas quando você quer OR, precisa ser explícito:
where: { OR: [{ ownerId: 1 }, { name: "pikachu" }] }A convenção cobre 80% dos casos. Os outros 20% pedem clareza, não magia.
Configuração demais vira burocracia. Convenção demais vira surpresa. O truque é saber onde colocar cada uma.
A maioria das APIs falha porque otimiza 100% para um lado:
- Simples demais → trava em casos complexos (Prisma antigo)
- Complexo demais → curva de aprendizado brutal (Hibernate)
Drizzle inverte: design para 80% de casos simples, mas obsessivamente suporte os 20% complexos.
Você consegue fazer where: { id: 1 } (trivial) e where: { RAW: sql... } (total liberdade) na mesma API. Sem conflito.
A API é totalmente tipada. TypeScript conhece cada campo, cada relação, cada operador possível.
Mas quando o sistema de tipos te trava? RAW está lá. Um any controlado, consciente, documentado.
Type safety vale muito. Mas tiranizar o usuário com tipos vale menos que zero.
Drizzle v1 tinha problemas. Naming confuso, imports demais, many-to-many complicado.
Ao invés de defender ("foi uma escolha consciente"), eles ouviram feedback por um ano e refizeram do zero.
v2 contradiz v1 em vários lugares. E está tudo bem.
Essa humildade é rara. A maioria das empresas defende decisões ruins por orgulho. Drizzle admitiu "erramos" e consertou.
Produtos mediocres mantêm consistência a todo custo. Produtos extraordinários mantêm qualidade a todo custo.
Esses princípios aparecem em todo canto:
CLI Design:
git commit -m "fix" # simples
git commit --amend --no-edit # avançado
git commit --allow-empty # escape hatchUI/UX:
- Figma: retângulos simples → Auto Layout → plugins
- Linear: issues básicas → custom views → API
Produtos:
- Features padrão → customização → white-label
- Self-service → customer success → enterprise
Código:
- Funções → classes → metaprogramação
- Components → hooks → refs
Sempre três camadas: simples por padrão, poder quando necessário, liberdade como último recurso.
Bom design de API tem menos a ver com sintaxe e mais com filosofia:
- Deixe usuários começar sem pensar
- Deixe usuários crescer sem refazer
- Deixe usuários escapar sem travar
Drizzle v2 acerta os três.
E talvez o mais importante: mostra que vale a pena ouvir quem usa seu produto. Um ano de feedback resultou numa API radicalmente melhor.
Isso importa mais que qualquer decisão técnica individual.
- Drizzle ORM Relational API v2 Proposal
- Discussão completa com 63 comentários e 108 respostas da comunidade