Pular para o conteúdo

Dext Fluent Query: Engenharia de Software e a Força da Comunidade

Dext Fluent Query

O desenvolvimento de um framework moderno como o Dext não acontece no vácuo. Ele é o resultado de um diálogo constante entre engenharia rigorosa e as necessidades reais de quem está no “front” desenvolvendo aplicações complexas.

Recentemente, a Issue #117 do nosso repositório oficial trouxe à tona discussões valiosas sobre a expressividade e a segurança dos Joins no Fluent Query. O que começou como um pedido de melhoria evoluiu para uma análise profunda, resultando na implementação de melhorias imediatas e na criação da especificação S19, que traça o futuro do motor de consultas do Dext.

Neste artigo, vamos explorar como o Fluent Query eleva a qualidade do código Delphi, o papel crucial da nossa comunidade nesse processo e como estamos transformando feedback em especificações técnicas de alto nível.


1. Código de Qualidade: Legibilidade que se traduz em Manutenibilidade

Seção intitulada “1. Código de Qualidade: Legibilidade que se traduz em Manutenibilidade”

O código que escrevemos é lido muito mais vezes do que é escrito. Compare uma concatenação de strings SQL tradicional com o padrão Fluent do Dext:

O “Jeito Antigo” (Frágil e dependente de strings):

Seção intitulada “O “Jeito Antigo” (Frágil e dependente de strings):”
Query.SQL.Text := 'SELECT * FROM USERS WHERE AGE >= :MIN_AGE ORDER BY NAME ASC';
Query.ParamByName('MIN_AGE').AsInteger := MinAge;
Query.Open;
var u := Prototype.Entity<TUser>;
var Adults := Context.Entities<TUser>
.AsNoTracking
.Where(u.Age >= 18)
.OrderBy(u.Name.Asc)
.Take(50)
.ToList;

Por que isso é qualidade superior?

  • Type Safety Real (Paz de Espírito): Ao usar u.Age, você traz o compilador para o seu lado. Se amanhã você renomear o campo Age para BirthDate na classe TUser, o Delphi não vai te deixar compilar o projeto até que todas as queries sejam corrigidas. Melhor ainda: se você usar uma ferramenta de refatoração, ela irá atualizar todas as referências nas suas queries automaticamente, algo impossível com strings SQL. Esqueça os erros de “Field ‘AGE’ not found” que só aparecem quando o cliente está usando o sistema.
  • Intellisense e Produtividade: Você não precisa decorar o Schema do banco. Ao digitar u., a IDE te mostra exatamente quais campos estão disponíveis, reduzindo a carga cognitiva e eliminando erros de digitação.
  • Intenção Clara: O encadeamento de métodos (.AsNoTracking, .Where, .OrderBy) transforma o código em uma documentação viva. Qualquer desenvolvedor (incluindo você daqui a 6 meses) entende a intenção da query em segundos.
  • Blindagem contra SQL Injection: Como o Fluent Query trabalha com expressões tipadas, o Dext trata a parametrização de forma nativa e segura sob o capô. Você escreve código Pascal, e o framework cuida da segurança do SQL.

Segurança de Tipos


2. O Ecossistema de Testes: Muito Além do Básico

Seção intitulada “2. O Ecossistema de Testes: Muito Além do Básico”

Um dos maiores diferenciais do Dext é que ele não é apenas um ORM; ele é acompanhado por um Framework de Testes completo (Sources\Testing), desenhado para que o Fluent Query seja testado com facilidade absoluta.

Graças à arquitetura baseada em interfaces do Dext, você pode “mockar” seu banco de dados sem esforço. Usando o Dext.Mocks, você pode interceptar chamadas e simular retornos complexos:

var u := TUser.Prototype;
var MockUsers := TList<TUser>.Create;
// Preencher lista simulada...
Mock<IDextContext>.Setup
.Returns(MockUsers)
.When.Entities<TUser>;

2.2 Fluent Assertions: Código que se lê como Inglês

Seção intitulada “2.2 Fluent Assertions: Código que se lê como Inglês”

Esqueça os Assert.AreEqual genéricos. Com as Dext.Assertions, suas verificações são expressivas e tipadas:

// Verificando resultados da query com elegância
Products.Should.HaveCount(3)
.AndAlso.Contain(SomeProduct)
.AndAlso.AllSatisfy(p.IsActive);

2.3 Snapshot Testing: Adeus ao Boilerplate de Assertions

Seção intitulada “2.3 Snapshot Testing: Adeus ao Boilerplate de Assertions”

Para queries que retornam objetos complexos ou grandes payloads JSON, o Dext oferece o Snapshot Testing. Em vez de escrever 50 asserções manuais, você tira uma “foto” do resultado esperado:

// Compara o resultado da query com um baseline JSON salvo em disco
MatchSnapshot(ResultList, 'RelatorioVendas_Janeiro');

O Dext utiliza um Runner moderno inspirado no xUnit/NUnit, permitindo que você escreva testes sem a necessidade de heranças complexas, usando apenas metadados:

  • [Fixture], [Test], [Fact] para definir cenários.
  • [TestCase(1, 2, 3)] para testes parametrizados (Data-Driven).
  • [Category('Integration')] para filtrar execuções no CI/CD.

Dext Testing

Vantagem para o seu CI/CD: Como o ecossistema de testes do Dext é nativo e integrado, seus testes unitários rodam em milissegundos, garantindo que mudanças no mapeamento ou na lógica de filtros sejam validadas instantaneamente.


3. TFluentQuery: Mais que uma Consulta, um Pipeline de Dados

Seção intitulada “3. TFluentQuery: Mais que uma Consulta, um Pipeline de Dados”

Para entender o poder do Dext, é preciso olhar sob o capô do TFluentQuery<T>. Diferente de abordagens tradicionais que executam o SQL imediatamente, o Dext trabalha com Execução Adiada (Deferred Execution).

O TFluentQuery<T> foi implementado como um record. Isso significa:

  • Zero Alocação no Heap: Criar uma query não gera pressão no Memory Manager, pois o estado é mantido na stack.
  • Ciclo de Vida Automático: Como é um tipo valor (record), ele é liberado automaticamente quando sai de escopo.

A query é apenas um “blueprint” (projeto). Você pode compor sua lógica em múltiplas etapas antes de disparar a execução real.

var u := TUser.Prototype;
var Query := Context.Entities<TUser>.AsNoTracking;
// Composição dinâmica baseada em regras de negócio
if OnlyActive then
Query := Query.Where(u.IsActive = True);
if MinAge > 0 then
Query := Query.Where(u.Age >= MinAge);
// O SQL só é gerado e executado AQUI:
var ResultList := Query.OrderBy(u.Name.Asc).ToList;

Existem várias formas de materializar seus dados, dependendo da necessidade:

var u := TUser.Prototype;
var User := Context.Entities<TUser>
.Where(u.Email = 'contato@dext.com')
.FirstOrDefault;
if User <> nil then
ShowMessage('Bem-vindo, ' + User.Name);

Ideal para Grids e APIs, executando o COUNT e o SELECT de forma otimizada.

var p := TProduct.Prototype;
var PagedResult := Context.Entities<TProduct>
.Where(p.Price > 100)
.OrderBy(p.CreatedAt.Desc)
.Paginate(1, 20); // Página 1, 20 registros
WriteLn(Format('Exibindo %d de %d registros', [PagedResult.Items.Count, PagedResult.TotalCount]));
  • .ToList: Para listas completas na memória.
  • .Count / .Any: Para verificar existência ou volume sem trazer os registros.

3.4 Streaming: Processando Milhões com Memória Constante

Seção intitulada “3.4 Streaming: Processando Milhões com Memória Constante”

Para cenários de Big Data ou exportações massivas, o Dext oferece o GetStreamingEnumerator.

var LargeQuery := Context.Entities<TLog>().AsNoTracking;
// O enumerador de streaming reutiliza instâncias de objetos internos
// mantendo o consumo de memória baixo e estável durante toda a iteração
for var Log in LargeQuery.GetStreamingEnumerator do
begin
Process(Log);
end;

O Fluent Query é o motor que alimenta as propriedades de navegação do Dext. Quando você acessa uma coleção marcada como Lazy<T>, o framework utiliza internamente o motor do Fluent Query para resolver essa dependência de forma transparente.


4. Simplicidade Complexa: A Engenharia por Trás da DSL

Seção intitulada “4. Simplicidade Complexa: A Engenharia por Trás da DSL”

Para que a experiência do desenvolvedor fosse de uma simplicidade absoluta, a engenharia interna do Dext precisou ser visceralmente complexa.

O Dext é o resultado de uma “briga” saudável com os limites da linguagem. Não aceitamos o clássico “isso não dá para fazer em Delphi”. Para criar uma DSL (Domain Specific Language) que fosse consistente em todo o framework — do Fluent Query às Collections, do Specification Pattern às Expressions — foi necessário orquestrar uma sinfonia técnica:

  • Generics & Extended RTTI: Para garantir abstrações poderosas sem perder a tipagem.
  • Managed Records & Operator Overloading: Para criar a sintaxe fluida e “zero-allocation” que você vê nas queries.
  • Class Functions & Interfaces: Para uma arquitetura de Injeção de Dependência e Desacoplamento de nível enterprise.
  • Public Functions & Ousadia: O uso criativo e rigoroso de recursos introduzidos desde o Delphi 2009, levados ao limite através de centenas de testes unitários e uma autocrítica constante.

Essa consistência significa que, uma vez que você aprende a usar o Fluent Query, você já sabe como filtrar uma Collection em memória ou como definir uma Specification para uma API Web.

A Arte da Simplicidade Complexa

Imagine o poder de definir uma regra de filtro complexa no seu Frontend (ou camada de serviço) e passá-la diretamente para o Backend, que a traduz em SQL otimizado de forma segura. Isso dispensa a criação de dezenas de endpoints específicos para cada variação de consulta, mantendo seu código limpo, tipado e escalável. É um ecossistema único, onde a complexidade interna trabalha silenciosamente para garantir a sua produtividade.


5. Performance Real e Arquitetura “Dialect-Aware”

Seção intitulada “5. Performance Real e Arquitetura “Dialect-Aware””

Não adianta ser bonito se não for rápido. O pipeline do Fluent Query foi desenhado para alta performance:

  1. AsNoTracking: Reduz drasticamente o overhead de memória em operações de leitura, ignorando o ciclo de vida de tracking quando você só precisa listar dados.
  2. SQL Caching: O Dext identifica assinaturas de consultas repetidas e reaproveita o SQL gerado, economizando ciclos de CPU valiosos.
  3. Qualificação de Colunas (Issue #117): Recentemente, aprimoramos o gerador de SQL para qualificar automaticamente todas as colunas em cenários de JOIN. Isso elimina o erro clássico de ambiguous column name: Id que assombra quem faz joins manuais.

6. Evolução Guiada pela Comunidade: A Issue #117

Seção intitulada “6. Evolução Guiada pela Comunidade: A Issue #117”

O Dext não é construído em uma torre de marfim. A Issue #117 é um exemplo perfeito disso. Recebemos um feedback sobre a necessidade de mais clareza e exemplos nos Joins SQL.

O que entregamos:

  • Melhoria no SQL Generator: Agora mais robusto contra ambiguidades.
  • Overloads Simplificados: Adicionamos formas mais fáceis de descrever a condição de JOIN.
  • Documentação Reforçada: Exemplos reais adicionados ao Orm.EntityDemo e no nosso “Book” oficial.

A evolução do Dext não para na V1. Durante a análise técnica da Issue #117, identificamos oportunidades de levar a experiência de consulta a um novo patamar. Assim nasceu a especificação S19, que define o roadmap pós-V1 para o Fluent Query.

O objetivo da S19 é consolidar o Dext como o ORM mais expressivo e performático do ecossistema Delphi. Entre as novidades planejadas, destacam-se:

  • DSL Totalmente Tipada para JOIN: Eliminação de strings na cláusula ON, utilizando expressões Delphi puras.
  • Clareza de Execução: APIs explícitas para distinguir Joins em banco de dados de Joins em memória (JoinInMemory), evitando materializações acidentais.
  • Projeções Ergonômicas: Novos padrões como SelectJoin<TResult> para mapear resultados complexos sem custo de reflection em tempo de execução.
  • Diagnósticos e Observabilidade: Introdução de TagWith para rastreamento de queries e ToQueryString() para inspeção imediata do SQL gerado e seus parâmetros.

Para os arquitetos que desejam se aprofundar nos detalhes técnicos e nas diretrizes de performance de zero-allocation da próxima fase, a especificação completa está disponível em: S19-FluentQuery-Join-Evolution.md


O TFluentQuery<T> não é apenas para CRUDs simples. Ele é a fundação para:

  • Relatórios Complexos: Projeções e agregações de alta performance.
  • Lógica de Negócio Desacoplada: Repositórios que retornam queries, permitindo que a camada de UI decida sobre paginação ou ordenação.
  • APIs Modernas: Integração nativa com JSON e materialização assíncrona.

Ao dominar o Fluent Query, você não está apenas escrevendo menos código; você está construindo aplicações Delphi preparadas para o futuro.


O Fluent Query do Dext transcende o conceito de mero “Syntax Sugar”. Ele é uma manifestação de engenharia de software rigorosa, projetada para injetar segurança de tipos, performance brutal e testabilidade determinística no coração das aplicações Delphi modernas.

Estamos movendo o Delphi de um passado de “strings quebradiças” para um futuro onde a consulta ao banco de dados é um cidadão de primeira classe, protegida pelo compilador e abraçada pela comunidade.

Se você tem a coragem de abandonar o “jeito de sempre” para abraçar uma arquitetura que escala com confiança, o Dext é o seu próximo passo.

📚 Saiba Mais e Colabore:

🚀 Quer colaborar? Confira a Issue #117 e veja como a sua participação pode transformar o ecossistema Delphi. O futuro do Dext é construído por todos nós.


Publicado por: Equipe Dext Framework Issue #117: Evolução Contínua via Feedback da Comunidade