Introdução: Por que Rust e bancos de dados são a combinação ideal
Rust é uma linguagem de programação de sistemas moderna que vem ganhando cada vez mais popularidade devido ao seu desempenho, segurança de memória e abstrações de custo zero. Muitos desenvolvedores vindos do mundo Python, JavaScript ou Go se perguntam: como trabalhar com bancos de dados em Rust? A resposta é simples: Rust fornece drivers poderosos e seguros para trabalhar tanto com bancos de dados relacionais (PostgreSQL) quanto com bancos de dados orientados a documentos (MongoDB).
Neste artigo, vamos abordar os fundamentos do trabalho com PostgreSQL e MongoDB em Rust. Você aprenderá como configurar o projeto, conectar-se aos bancos de dados e executar operações CRUD básicas. O artigo é voltado para iniciantes, portanto usaremos exemplos simples e compreensíveis.
1. Configuração do projeto e instalação de dependências
Antes de começar, certifique-se de ter Rust e Cargo instalados. Crie um novo projeto:
cargo new rust_db_examplecd rust_db_exampleAbra o arquivo Cargo.toml e adicione as dependências necessárias. Para trabalhar com PostgreSQL, usaremos a crate tokio-postgres (driver assíncrono) e serde para serialização de dados. Para MongoDB — o driver oficial mongodb.
[dependencies]tokio = { version = "1", features = ["full"] }tokio-postgres = "0.7"serde = { version = "1", features = ["derive"] }serde_json = "1"mongodb = "2.8"Observe: estamos usando tokio como runtime assíncrono, pois ambos os drivers funcionam de forma assíncrona. Esta é uma prática padrão para aplicações Rust modernas.
2. Trabalhando com PostgreSQL em Rust
PostgreSQL é um poderoso banco de dados relacional. Para trabalhar com ele em Rust, usaremos a crate tokio-postgres. Ela fornece uma interface assíncrona para executar consultas SQL.
2.1 Conexão ao banco de dados
Vamos criar uma função para conectar a um banco de dados PostgreSQL local. Certifique-se de que o servidor PostgreSQL esteja em execução e que um banco de dados (por exemplo, test_db) tenha sido criado:
use tokio_postgres::{NoTls, Error};
#[tokio::main]async fn main() -> Result<(), Error> { // String de conexão: postgresql://user:password@localhost/dbname let (client, connection) = tokio_postgres::connect( "host=localhost user=postgres dbname=test_db", NoTls, ).await?;
// Inicia a conexão em segundo plano tokio::spawn(async move { if let Err(e) = connection.await { eprintln!("Connection error: {}", e); } });
println!("Conexão com PostgreSQL estabelecida!"); Ok(())}2.2 Criação de tabela e inserção de dados
Agora vamos criar a tabela users e inserir alguns registros:
// Criando a tabelaclient .execute( "CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(150) UNIQUE NOT NULL )", &[], ) .await?;
// Inserindo dadoslet name = "Alice";let email = "alice@example.com";client .execute( "INSERT INTO users (name, email) VALUES ($1, $2)", &[&name, &email], ) .await?;
println!("Usuário {} adicionado!", name);2.3 Leitura e atualização de dados
Vamos executar uma consulta SELECT e atualizar um registro:
// Leitura de dadoslet rows = client .query("SELECT id, name, email FROM users", &[]) .await?;
for row in rows { let id: i32 = row.get(0); let name: &str = row.get(1); let email: &str = row.get(2); println!("ID: {}, Name: {}, Email: {}", id, name, email);}
// Atualização de registroclient .execute( "UPDATE users SET email = $1 WHERE name = $2", &[&"alice_new