Rust e SQLx em 2026: Consultas Verificadas em Tempo de Compilação e Perguntas de Entrevista

Guia completo sobre SQLx com Rust: consultas SQL verificadas em compilação, comparação com ORMs, e perguntas técnicas para entrevistas de emprego.

Rust e SQLx em 2026: Consultas Verificadas em Tempo de Compilação e Perguntas de Entrevista

SQLx representa uma abordagem revolucionária para a interação com bancos de dados em Rust. Diferentemente dos ORMs tradicionais, SQLx verifica as consultas SQL diretamente durante a compilação, eliminando toda uma categoria de erros antes mesmo da execução do programa. Essa característica única o torna uma ferramenta preferida para aplicações críticas onde a confiabilidade da camada de dados é primordial.

Em 2026, SQLx se estabeleceu como a solução de referência para desenvolvedores Rust trabalhando com PostgreSQL, MySQL e SQLite. Sua crescente adoção na indústria significa que perguntas relacionadas ao SQLx aparecem cada vez mais frequentemente em entrevistas técnicas para posições de Rust.

SQLx utiliza as macros procedurais de Rust para analisar consultas SQL em tempo de compilação. Essa verificação requer uma conexão com o banco de dados durante o build, mas garante que cada consulta seja sintaticamente correta e compatível com o esquema.

Configuração Inicial do SQLx

A instalação do SQLx em um projeto Rust começa adicionando as dependências apropriadas. A configuração varia de acordo com o mecanismo de banco de dados alvo.

toml
[dependencies]
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "macros", "chrono", "uuid"] }
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"

A variável de ambiente DATABASE_URL deve ser configurada para permitir a verificação em tempo de compilação:

bash
export DATABASE_URL="postgres://user:password@localhost:5432/mydb"

Consultas com Verificação em Tempo de Compilação

A macro sqlx::query! constitui o núcleo da funcionalidade de verificação. Ela analisa a consulta SQL, verifica sua validade contra o esquema do banco de dados e gera código Rust tipado.

rust
use sqlx::PgPool;

#[derive(Debug)]
struct User {
    id: i32,
    email: String,
    created_at: chrono::DateTime<chrono::Utc>,
}

async fn get_user_by_id(pool: &PgPool, user_id: i32) -> Result<Option<User>, sqlx::Error> {
    let row = sqlx::query!(
        r#"
        SELECT id, email, created_at
        FROM users
        WHERE id = $1
        "#,
        user_id
    )
    .fetch_optional(pool)
    .await?;

    Ok(row.map(|r| User {
        id: r.id,
        email: r.email,
        created_at: r.created_at,
    }))
}

Se uma coluna não existir ou o tipo não corresponder, o compilador sinaliza o erro imediatamente.

Uso de query_as para Mapeamento Automático

Para simplificar o mapeamento entre resultados SQL e estruturas Rust, query_as! oferece uma sintaxe mais concisa:

rust
use sqlx::FromRow;

#[derive(Debug, FromRow)]
struct Article {
    id: i32,
    title: String,
    content: String,
    author_id: i32,
    published: bool,
}

async fn get_published_articles(pool: &PgPool) -> Result<Vec<Article>, sqlx::Error> {
    sqlx::query_as!(
        Article,
        r#"
        SELECT id, title, content, author_id, published
        FROM articles
        WHERE published = true
        ORDER BY id DESC
        LIMIT 50
        "#
    )
    .fetch_all(pool)
    .await
}

Gerenciamento de Transações

As transações garantem a integridade de operações múltiplas. SQLx propõe uma API elegante para manipulá-las:

rust
async fn transfer_funds(
    pool: &PgPool,
    from_account: i32,
    to_account: i32,
    amount: rust_decimal::Decimal,
) -> Result<(), sqlx::Error> {
    let mut tx = pool.begin().await?;

    sqlx::query!(
        "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
        amount,
        from_account
    )
    .execute(&mut *tx)
    .await?;

    sqlx::query!(
        "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
        amount,
        to_account
    )
    .execute(&mut *tx)
    .await?;

    tx.commit().await?;
    Ok(())
}

Modo Offline para Ambientes CI/CD

Em pipelines de build onde o banco de dados não está acessível, SQLx suporta um modo offline. Os metadados das consultas são salvos em um arquivo JSON:

bash
cargo sqlx prepare --workspace

Esse comando gera um diretório .sqlx/ contendo as informações de esquema necessárias para a compilação sem conexão ativa.

rust
// Com SQLX_OFFLINE=true, a compilação usa os metadados em cache
let users = sqlx::query_as!(User, "SELECT * FROM users WHERE active = true")
    .fetch_all(&pool)
    .await?;

Comparação com Diesel e SeaORM

SQLx difere fundamentalmente de ORMs como Diesel ou SeaORM em sua abordagem:

rust
// SQLx: SQL cru com verificação
sqlx::query!("SELECT * FROM users WHERE email LIKE $1", pattern)
    .fetch_all(&pool)
    .await?;

// Diesel: DSL Rust compilado para SQL
users::table
    .filter(users::email.like(pattern))
    .load::<User>(&mut conn)?;

// SeaORM: API fluente com modelos gerados
User::find()
    .filter(user::Column::Email.like(&pattern))
    .all(&db)
    .await?;

SQLx privilegia o SQL nativo, oferecendo controle total sobre as consultas enquanto mantém a segurança de tipos. Os ORMs abstraem o SQL mas podem limitar o acesso a funcionalidades específicas de cada mecanismo.

Gerenciamento de Migrações

SQLx integra um sistema de migração robusto:

bash
sqlx migrate add create_users_table

Esse comando cria um arquivo de migração versionado:

sql
-- migrations/20260912120000_create_users_table.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_users_email ON users(email);

A aplicação de migrações é realizada programaticamente ou via CLI:

rust
sqlx::migrate!().run(&pool).await?;

Pool de Conexões e Configuração

A configuração do pool de conexões impacta diretamente o desempenho:

rust
use sqlx::postgres::PgPoolOptions;
use std::time::Duration;

async fn create_pool() -> Result<PgPool, sqlx::Error> {
    PgPoolOptions::new()
        .max_connections(20)
        .min_connections(5)
        .acquire_timeout(Duration::from_secs(3))
        .idle_timeout(Duration::from_secs(600))
        .max_lifetime(Duration::from_secs(1800))
        .connect(&std::env::var("DATABASE_URL").unwrap())
        .await
}

Perguntas Técnicas de Entrevista

As entrevistas técnicas sobre SQLx exploram vários domínios chave.

Pergunta: Como o SQLx verifica as consultas em tempo de compilação?

SQLx usa macros procedurais para estabelecer uma conexão com o banco de dados durante a compilação. A macro query! executa um comando PREPARE para validar a sintaxe e os tipos, então gera código Rust tipado baseado no esquema real.

Pergunta: Qual é a diferença entre query! e query_as!?

A macro query! retorna um tipo anônimo com campos correspondentes às colunas selecionadas. query_as! mapeia diretamente os resultados para uma estrutura definida, simplificando o código quando a estrutura corresponde exatamente ao resultado.

Pergunta: Como lidar com consultas dinâmicas com SQLx?

rust
use sqlx::QueryBuilder;

async fn search_users(
    pool: &PgPool,
    name: Option<&str>,
    email: Option<&str>,
) -> Result<Vec<User>, sqlx::Error> {
    let mut builder: QueryBuilder<sqlx::Postgres> = QueryBuilder::new(
        "SELECT id, email, created_at FROM users WHERE 1=1"
    );

    if let Some(n) = name {
        builder.push(" AND name ILIKE ");
        builder.push_bind(format!("%{}%", n));
    }

    if let Some(e) = email {
        builder.push(" AND email = ");
        builder.push_bind(e);
    }

    builder
        .build_query_as::<User>()
        .fetch_all(pool)
        .await
}

Pergunta: Como testar código que usa SQLx?

A abordagem recomendada usa transações revertidas para isolar os testes:

rust
#[sqlx::test]
async fn test_create_user(pool: PgPool) -> sqlx::Result<()> {
    let user = create_user(&pool, "test@example.com").await?;
    assert_eq!(user.email, "test@example.com");
    Ok(())
    // A transação é automaticamente revertida
}

Pronto para mandar bem nas entrevistas de Rust?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Boas Práticas de Produção

Vários padrões otimizam o uso do SQLx em produção:

rust
// Wrapper para gerenciamento centralizado de erros
pub struct Database {
    pool: PgPool,
}

impl Database {
    pub async fn new() -> Result<Self, sqlx::Error> {
        let pool = PgPoolOptions::new()
            .max_connections(20)
            .connect(&std::env::var("DATABASE_URL").unwrap())
            .await?;
        
        sqlx::migrate!().run(&pool).await?;
        
        Ok(Self { pool })
    }

    pub fn pool(&self) -> &PgPool {
        &self.pool
    }
}

O encapsulamento do pool em uma estrutura permite adicionar facilmente funcionalidades como logging, métricas ou retentativas.

Conclusão

SQLx estabelece um novo padrão para a interação com bancos de dados em Rust. Sua verificação em tempo de compilação elimina os erros SQL em tempo de execução enquanto preserva a flexibilidade do SQL nativo. Para desenvolvedores preparando entrevistas técnicas, o domínio do SQLx demonstra uma compreensão profunda do ecossistema Rust e dos princípios de segurança de tipos aplicados às camadas de dados. A combinação de desempenho ótimo, tipagem forte e uma API ergonômica faz do SQLx uma escolha acertada para aplicações Rust modernas.

Desafio do dia

Você saberia encontrar o bug em Rust?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 12 de setembro de 2026

Compartilhar

Artigos relacionados