Projetando uma DSL Fluente de Consultas
Crie uma API de consultas encadeável e que valide a si mesma.
Projetando uma DSL Fluente de Consultas é uma aula grátis de TypeScript Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de TypeScript Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de TypeScript Academy inclui 4 aulas no total.
Projetando uma DSL fluente de consultas
Projetamos uma DSL de consultas encadeável na qual cada etapa refina as próximas etapas permitidas por meio de tipos de retorno. O resultado se lê como SQL e rejeita ordenações inválidas em tempo de compilação.
Gramática-alvo
Queremos: from seguido de um where opcional (repetível) e depois um select terminal. Não é possível usar select antes de from, nem usar from duas vezes.
Interfaces de estado
Modele cada etapa como uma interface que retorna a etapa seguinte.
interface Builder {
from(table: string): FromStage;
}
interface FromStage {
where(cond: string): FromStage; // repeatable
select(...cols: string[]): Result;
}
interface Result { sql: string; }Impondo a ordem
Como select existe apenas em FromStage, chamá-lo no Builder inicial é um erro de compilação. A ordem é imposta puramente pelos métodos que cada etapa expõe.
declare const db: Builder;
db.from("users").select("id"); // ok
db.select("id"); // Error: select missing on BuilderAcompanhando colunas selecionadas
Adicione um genérico fantasma para lembrar quais colunas foram selecionadas, de modo que o tipo do resultado seja preciso.
interface FromStage<T extends string = never> {
where(c: string): FromStage<T>;
select<C extends string>(...cols: C[]): Result<C>;
}
interface Result<C extends string> { columns: C[]; }Refinando a cada chamada
Cada where também pode acumular restrições no tipo. Aqui mantemos a simplicidade, mas o padrão se generaliza para acompanhar parâmetros vinculados.
const q = db.from("users").where("age > 18").where("active = true");
// still FromStage; select remains availableImpedindo a repetição de from
Como FromStage não expõe from, você não pode chamá-lo duas vezes. A gramática o proíbe estruturalmente, sem necessidade de uma proteção em tempo de execução.
db.from("a").from("b"); // Error: from does not exist on FromStageEtapa terminal
select retorna Result, que não expõe nem where nem from, encerrando a cadeia. Restam apenas operações de leitura do resultado.
const r = db.from("users").select("id", "name");
r.columns; // ("id" | "name")[]
// r.where(...) -> Error: where not on ResultRestrições de colunas tipadas
Restrinja colunas a um esquema de tabela conhecido com outro genérico, para que colunas desconhecidas sejam rejeitadas, combinando esta DSL com as ideias anteriores de ORM.
interface Table<Cols extends string> {
select<C extends Cols>(...cols: C[]): Result<C>;
}
// db.from gives Table<"id" | "name" | "age">Etapas opcionais e obrigatórias
Torne uma etapa obrigatória expondo apenas o método seguinte depois dela. Por exemplo, force pelo menos um where retornando uma etapa cujo select só apareça depois que where for chamado. Os mesmos tipos encadeados também podem inferir o tipo da linha de resultado da execução da consulta, vinculando a gramática em tempo de compilação aos dados em tempo de execução.
Por que isso importa
Uma DSL fluente projetada dessa forma é autodocumentada e impossível de usar incorretamente: o preenchimento automático mostra apenas as próximas etapas válidas, e sequências ilegais nunca são compiladas. Essa é a base de bibliotecas de construtores ergonômicas.
Verificação rápida
Confirme sua compreensão do design de DSLs fluentes.
Recapitulação
Você projetou uma DSL fluente de consultas como uma máquina de estados em nível de tipos: a interface de cada etapa retorna a seguinte, expondo apenas métodos válidos. Genéricos fantasmas acompanham as colunas selecionadas, etapas terminais encerram a cadeia e restrições de colunas rejeitam nomes desconhecidos, tudo imposto pelos tipos de retorno.
Perguntas Frequentes
A aula “Projetando uma DSL Fluente de Consultas” é grátis?
Sim — o texto completo de “Projetando uma DSL Fluente de Consultas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de TypeScript Academy, atualize para CoddyKit PRO. O curso de TypeScript Academy inclui 4 aulas no total.
O que vou aprender em “Projetando uma DSL Fluente de Consultas”?
Crie uma API de consultas encadeável e que valide a si mesma. Você pratica TypeScript Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar TypeScript Academy?
Nenhuma experiência prévia é necessária. TypeScript Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Projetando uma DSL Fluente de Consultas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de TypeScript Academy?
Sim. Cada aula de TypeScript Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- O que é uma DSL no Nível de Tipos
- Projetando uma DSL Fluente de Consultas
- Validação de Entrada em Tempo de Compilação
- Mensagens de Erro em DSLs no Nível de Tipos