3 stable releases
Uses new Rust 2024
| 1.0.2 | Mar 7, 2026 |
|---|
#1 in #sqlx
8KB
129 lines
postgres_to_polars
A Rust library for streaming PostgreSQL query results directly into Polars DataFrames using sqlx.
Derive IntoDataFrame on your struct, use sqlx's query_as! macro, and call .to_dataframe() on the stream. That's it.
Usage
Add to your Cargo.toml:
[dependencies]
postgres_to_polars = "1.0"
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "chrono"] }
tokio = { version = "1", features = ["full"] }
polars = "0.53"
Basic example
use sqlx::PgPool;
use postgres_to_polars::{IntoDataFrame, StreamToDataFrame};
#[derive(sqlx::FromRow, IntoDataFrame)]
struct User {
id: i32,
name: Option<String>,
email: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = PgPool::connect("postgres://user:pass@localhost/db").await?;
// With estimated row count (avoids reallocations)
let df = sqlx::query_as!(User, "SELECT id, name, email FROM users")
.fetch(&pool)
.to_dataframe(100_000)
.await?;
println!("{}", df);
Ok(())
}
With default capacity
When you don't know the row count upfront:
let df = sqlx::query_as!(User, "SELECT id, name, email FROM users WHERE active = true")
.fetch(&pool)
.to_dataframe_default()
.await?;
Supported types
| Rust type | PostgreSQL type | Polars type |
|---|---|---|
i32 |
int4 | Int32 |
i64 |
int8 | Int64 |
f32 |
float4 | Float32 |
f64 |
float8 | Float64 |
bool |
bool | Boolean |
String |
text, varchar | String |
chrono::NaiveDate |
date | Date |
chrono::NaiveDateTime |
timestamp | Datetime |
chrono::NaiveTime |
time | Time |
Vec<String> |
text[] | List(String) |
All types support Option<T> for nullable columns.
How it works
#[derive(IntoDataFrame)]generates a columnar builder for your struct.to_dataframe(capacity)streams rows from PostgreSQL and pushes each row into the builder (no intermediateVec<Struct>)- The builder converts each column
Vecinto a PolarsSeriesand assembles theDataFrame
This approach is memory-efficient: rows are consumed one at a time from the stream and stored directly in columnar format.
Performance
Benchmarks on 500K rows (PostgreSQL running locally in Docker):
| Query | Time |
|---|---|
| 500K rows × 1 column (i32) | ~100ms |
| 500K rows × 4 columns (i32 + 3×String) | ~173ms |
| 100K rows × 4 columns | ~33ms |
| 10K rows × 4 columns | ~3.7ms |
License
Apache-2.0
lib.rs:
Proc-macro crate providing #[derive(IntoDataFrame)].
This is an implementation detail of the postgres_to_polars crate.
Use postgres_to_polars::IntoDataFrame instead of depending on this crate directly.
Dependencies
~89–425KB
~10K SLoC