-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] Implement serde::Serialize for sqlx::Row #182
Comments
With #181 closed and available on the master branch, has there been any interest in this? It would be nice to avoid |
Confirmation: I would love this so i can directly export to CSV without parsing, ie dumping the entire rows' values |
If you're using Postgres, you can use the let mut stream: BoxStream<sqlx::Result<Bytes>> = pg_pool.copy_out_raw(
"COPY (SELECT * FROM my_table) TO STDOUT (FORMAT CSV)"
).await?; |
unfortunately CockroachDB doesn't implement this :) thank you though! |
Heh, CockroachDB doesn't implement a lot of things. |
if possible, an example that shows how to iterate through all columns in a row of type PgRow / SqlxRow would also be more than sufficient |
Is it currently possible to implement this behavior on the consumer side? When simply trying to decode a column to serde_json::Value i somethings get errors like on VARCHAR columns
on INT columns
Using some kind of PostgreSQL trick is sadly not an options as we're stuck on mysql. |
Yes, that would be a great addition ! Here is how I work around the problem in the meantime : struct SerializeRow<R: Row>(R);
impl<'r, R: Row> Serialize for &'r SerializeRow<R>
where usize: sqlx::ColumnIndex<R>,
&'r str: sqlx::Decode<'r, <R as Row>::Database>,
f64: sqlx::Decode<'r, <R as Row>::Database>,
i64: sqlx::Decode<'r, <R as Row>::Database>,
bool: sqlx::Decode<'r, <R as Row>::Database>,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, {
use sqlx::{TypeInfo, ValueRef};
let columns = self.0.columns();
let mut map = serializer.serialize_map(Some(columns.len()))?;
for col in columns {
let key = col.name();
match self.0.try_get_raw(col.ordinal()) {
Ok(raw_value) if !raw_value.is_null()=> match raw_value.type_info().name() {
"REAL" | "FLOAT" | "NUMERIC" | "FLOAT4" | "FLOAT8" | "DOUBLE" =>
map_serialize::<_, _, f64>(&mut map, key, raw_value),
"INT" | "INTEGER" | "INT8" | "INT2" | "INT4" | "TINYINT" | "SMALLINT" | "BIGINT" =>
map_serialize::<_, _, i64>(&mut map, key, raw_value),
"BOOL" | "BOOLEAN" =>
map_serialize::<_, _, bool>(&mut map, key, raw_value),
// Deserialize as a string by default
_ => map_serialize::<_, _, &str>(&mut map, key, raw_value)
},
_ => map.serialize_entry(key, &()) // Serialize null
}?
}
map.end()
}
}
fn map_serialize<'r, M: SerializeMap, DB: Database, T: Decode<'r, DB> + Serialize>(
map: &mut M, key: &str, raw_value: <DB as sqlx::database::HasValueRef<'r>>::ValueRef,
) -> Result<(), M::Error> {
let val = T::decode(raw_value).map_err(serde::ser::Error::custom)?;
map.serialize_entry(key, &val)
} |
For those hitting this page... The above SerializeRow kinda/sorta works. It's a great start.
|
Any plan to release this feature? |
I created a small library for this (postgres only): |
@brianbruggeman the query! macro returns anonymous records, I want a simple way to serialize them, would the snippet posted @lovasoa work on SQLite? I have a pet project to learn Rust: a micro baas built with clap, actix-web, sqlx and all the popular crates. Let's say I have a collections API, each collection is a table in SQLite. This would be the use case POST /collections -> CREATE TABLE {name} -> 201 Created -> JSON { message: "Success" } I having trouble wrapping my head on how to stringify a query result without having a struct on build time. |
Not sufficiently, but maybe for your use case? You'll have to decide that.
This probably isn't a great project for just starting out on Rust. I don't really know your background, but there's a ton of learning just in building a simple clap. Building a microservice-based saas project as a first project probably isn't a good learning experience. But good luck!
The preferred useage of sqlx is to build a new serde-compatible struct (with Debug) for every query. If you need to you can always use This doesn't work, but this is what I had hoped sqlx had implemented. You could, of course fork or add this locally, but this would probably satisfy about 90% of the requests around serialization. let url = "sqlite::memory:";
let sql = r#"SELECT * FROM foo"#;
let pool = sqlx::sqlite::SqlitePoolOptions::new()
.max_connections(5)
.connect(url)
.await
.unwrap();
let rows: Vec<serde_json::Value> = sqlx::query_as(sql).fetch_all(&pool).await.unwrap();
// JSONL output
for row in rows {
let json_string = serde_json::to_string(row)?;
println!("{json_string}");
}
} |
I would really like to have this feature. At the moment I am doing this for MySql DB
I can't figure out how to get dates to work. My use case is json -> sql query -> json so have arbitrary query/response. |
This is what my version in SQLPage currently looks like: https://github.com/lovasoa/SQLpage/blob/main/src/webserver/database/sql_to_json.rs#L43-L91 |
@lovasoa |
Idea: It would be interesting to select rows from the database and instantly and easily serialize to a data format.
Blocked on #181
The text was updated successfully, but these errors were encountered: