parsql-postgres
Parsql için PostgreSQL entegrasyon küfesidir. Bu paket, parsql'in PostgreSQL veritabanlarıyla çalışmasını sağlayan senkron API'leri içerir.
Özellikler
- Senkron PostgreSQL işlemleri
- Otomatik SQL sorgu oluşturma
- Güvenli parametre yönetimi
- Generic CRUD işlemleri (get, insert, update, delete)
- Veritabanı satırlarını struct'lara dönüştürme
Kurulum
Cargo.toml dosyanıza şu şekilde ekleyin:
[dependencies]
parsql = { version = "0.3.0", features = ["postgres"] }
veya doğrudan bu paketi kullanmak isterseniz:
[dependencies]
parsql-postgres = "0.3.0"
parsql-macros = "0.3.0"
postgres = "0.19"
Temel Kullanım
Bu paket, PostgreSQL veritabanı ile çalışırken senkron işlemler kullanır. Bu, tokio-postgres gibi async/await kullanımı gerektirmediği anlamına gelir.
Bağlantı Kurma
use postgres::{Client, NoTls, Error};
fn main() -> Result<(), Error> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
client.execute(
"CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
state SMALLINT NOT NULL
)",
&[],
)?;
Ok(())
}
CRUD İşlemleri
Veri Okuma (Get) İşlemi
use parsql::{
core::Queryable,
macros::{FromRow, Queryable, SqlParams},
postgres::{FromRow, SqlParams, get},
};
use postgres::{types::ToSql, Row};
#[derive(Queryable, FromRow, SqlParams, Debug)]
#[table("users")]
#[where_clause("id = $")]
pub struct GetUser {
pub id: i64,
pub name: String,
pub email: String,
pub state: i16,
}
impl GetUser {
pub fn new(id: i64) -> Self {
Self {
id,
name: Default::default(),
email: Default::default(),
state: Default::default(),
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
let get_user = GetUser::new(1);
let get_result = get(&mut client, get_user)?;
println!("Kullanıcı: {:?}", get_result);
Ok(())
}
Veri Ekleme (Insert) İşlemi
use parsql::{
core::Insertable,
macros::{Insertable, SqlParams},
postgres::{SqlParams, insert},
};
use postgres::types::ToSql;
#[derive(Insertable)]
#[table("users")]
pub struct InsertUser {
pub name: String,
pub email: String,
pub state: i16,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
let insert_user = InsertUser {
name: "Ali".to_string(),
email: "ali@parsql.com".to_string(),
state: 1,
};
let insert_result = insert(&mut client, insert_user)?;
println!("Eklenen kayıt ID: {}", insert_result);
Ok(())
}
Veri Güncelleme (Update) İşlemi
use parsql::{
core::Updateable,
macros::{UpdateParams, Updateable},
postgres::{UpdateParams, update},
};
use postgres::types::ToSql;
#[derive(Updateable, UpdateParams)]
#[table("users")]
#[update("name, email")]
#[where_clause("id = $")]
pub struct UpdateUser {
pub id: i64,
pub name: String,
pub email: String,
pub state: i16,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
let update_user = UpdateUser {
id: 1,
name: String::from("Ali Güncellendi"),
email: String::from("ali.updated@gmail.com"),
state: 2,
};
let result = update(&mut client, update_user)?;
println!("Güncellenen kayıt sayısı: {}", result);
Ok(())
}
Veri Silme (Delete) İşlemi
use parsql::{
core::Deletable,
macros::{Deletable, SqlParams},
postgres::{SqlParams, delete},
};
use postgres::types::ToSql;
#[derive(Deletable, SqlParams)]
#[table("users")]
#[where_clause("id = $")]
pub struct DeleteUser {
pub id: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
let delete_user = DeleteUser { id: 1 };
let result = delete(&mut client, delete_user)?;
println!("Silinen kayıt sayısı: {}", result);
Ok(())
}
İşlem (Transaction) Kullanımı
Standard postgres kütüphanesindeki Transaction özelliğini kullanabilirsiniz:
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(
"host=localhost user=postgres password=postgres dbname=test",
NoTls,
)?;
let mut tx = client.transaction()?;
let insert_user = InsertUser {
name: "Mehmet".to_string(),
email: "mehmet@parsql.com".to_string(),
state: 1,
};
let id = insert(&mut tx, insert_user)?;
tx.commit()?;
println!("Ekleme işlemi başarılı, ID: {}", id);
Ok(())
}
Gelişmiş Özellikler
Join Kullanımı
#[derive(Queryable, FromRow, SqlParams, Debug)]
#[table("users")]
#[select("users.id, users.name, posts.title as post_title")]
#[join("LEFT JOIN posts ON users.id = posts.user_id")]
#[where_clause("users.id = $")]
pub struct UserWithPosts {
pub id: i64,
pub name: String,
pub post_title: Option<String>,
}
Gruplama ve Sıralama
#[derive(Queryable, FromRow, SqlParams, Debug)]
#[table("users")]
#[select("state, COUNT(*) as user_count")]
#[group_by("state")]
#[order_by("user_count DESC")]
#[having("COUNT(*) > 5")]
pub struct UserStats {
pub state: i16,
pub user_count: i64,
}
Özel Select İfadeleri
#[derive(Queryable, FromRow, SqlParams, Debug)]
#[table("users")]
#[select("id, name, email, CASE WHEN state = 1 THEN 'Aktif' ELSE 'Pasif' END as status")]
#[where_clause("id = $")]
pub struct UserWithStatus {
pub id: i64,
pub name: String,
pub email: String,
pub status: String,
}
SQL Sorgularını İzleme
Oluşturulan SQL sorgularını görmek için PARSQL_TRACE
çevre değişkenini ayarlayabilirsiniz:
PARSQL_TRACE=1 cargo run
Bu, postgres için oluşturulan tüm sorguları konsola yazdıracaktır.
Tokio-Postgres ile Farklar
Bu paketteki en önemli fark, tokio-postgres paketinin aksine bu paketin senkron API kullanmasıdır:
- Senkron İşlemler: Bu paket, async/await kullanmaz ve senkron işlemler yapar.
- İstemci Referansı: Fonksiyonlara istemciyi
&mut client
olarak iletmeniz gerekir.
- Tokio Runtime Gerektirmez: Tokio runtime'a ihtiyaç duymadan kullanabilirsiniz.
Performans İpuçları
-
Prepared Statements: postgres, sorguları prepared statement olarak çalıştırır ve parsql bu özelliği kullanır, bu SQL enjeksiyon saldırılarına karşı korunmanıza yardımcı olur.
-
Toplu İşlemler: Birden çok işlemi Transaction içinde yapın:
let mut tx = client.transaction()?;
tx.commit()?;
Hata Yakalama
İşlemler sırasında oluşabilecek hataları yakalamak ve işlemek için Rust'ın Result
mekanizmasını kullanın:
match get(&mut client, get_user) {
Ok(user) => println!("Kullanıcı bulundu: {:?}", user),
Err(e) => eprintln!("Hata oluştu: {}", e),
}
Tam Örnek Proje
Tam bir örnek proje için parsql ana deposundaki examples/postgres dizinine bakabilirsiniz.