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:
[]
= "1.0"
= { = "0.8", = ["runtime-tokio", "postgres", "chrono"] }
= { = "1", = ["full"] }
= "0.53"
Basic example
use PgPool;
use ;
async
With default capacity
When you don't know the row count upfront:
let df = query_as!
.fetch
.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