-
-
Notifications
You must be signed in to change notification settings - Fork 450
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
Possible ergonomic improvements? #480
Comments
What would the type signature of the method be in that case?
We could make that change, but I think there's a simpler solution than adding a bunch of no-op clauses - just slice the parameter list down to the right length:
This is possible in the synchronous interface (it just prepares the statement for you and then immediately uses it). I'd like to do the same for the async library as well, but it's blocked on an upstream bug getting fixed: rust-lang/rust#63832.
Unless I'm misreading, that appears to be designed around returning an inserted or modified row, not for arbitrary queries that return one row. Maybe it works anyway? It might make sense to add something like that, though. I guess we'd probably want it to error if there isn't exactly one row? I don't want to get into a place of having dozens of convenience methods though.
I don't think there's anything fundamental ergonomically that can't be handled in a separate crate - extension traits can add new methods to |
Okay well keep in mind I only just finished reading the Rust book so I'm very new to all of this. Would something like making a new trait
Hooray! The problem with slicing the parameter list down is that depending on how you format the query, you may, for example, use only the 2nd, 4th, and 7th parameter, you know? So it'd be quite cumbersome to have to, in addition to formatting the query, also having to mess with the parameter vector list.
Ah okay well I'm glad it's being thought of in any case! Would be nice to get rid of some of those extra prepare statements
I'd guess that it would return I definitely feel you on not having dozens on convenience methods, but this seems like a special case. Around half of my queries in my application select a single row, so it seems like a common enough use-case to accommodate. A query will either return one row, or many, and currently the API only accommodates the latter case. Edit: I thought of an even more compelling reason. With the current API you need to make the rows that return a mutable variable for the sole reason to be able to call
True enough, it can be definitely handled in another crate. I suppose I'm just worried because what I'm currently using to handle this functionality is a small fork of an already small crate, of which I am not knowledgeable enough to maintain myself. This seems like a relatively core functionality, as I imagine the vast majority of users of this crate are not manually deserializing every query into their own structs. It'd be nice to have some official support for this. |
How would that differ from the |
A query that doesn't use some parameters fails to parse on the Postgres server unless you use #[tokio::test]
async fn foo() {
let mut client = connect("user=postgres").await;
let query = client.prepare("SELECT $2::INT8").await.unwrap();
println!("{:?}", query.params());
}
|
Oh, I guess it'd be a Vector of
Sorry I think I didn't explain it properly, either that or I'm misunderstanding. Here's an example of what I'm looking for:
This currently gives the following runtime error:
Ideally it would sub This is useful for when you're dynamic query building and may only use a subset of the parameters depending on the frontend input to your server. |
Right, that's the bit that can be easily sliced away. I was referring to when you were asking about a query that "use[d] only the 2nd, 4th, and 7th parameter". |
Something like this:
It's nice to just have the parameter list always be the 3 possible parameters that you have to draw from, and able to modify the query to use whichever ones it needs. Does that make sense? |
Sure, but there is nothing I can do about the database not knowing what the type of |
Okay now I'm confused. Why does the database need to know the type of |
It is still passed to the database. The client has no idea which parameters are and aren't mentioned in the query. |
Oh, is there a way to.. not send it to the database? Hmm, looks like there might be a need for a little helper function. I hate to use the "but Diesel" argument again, but IIRC this doesn't happen with their approach. Well in any case I'll try to write a function that helps with this.. shouldn't be too hard I don't think. I think I just need to seek through the query string and find all instances of |
Wait nevermind that wouldn't work I'd need to change the query string too.. Agh, I just don't understand. Why does postgres have to error out just because you're passing it a parameter that it doesn't use? That seems so strange to me. It'd be like if Rust refused to compile because you didn't use a supplied parameter in a function. I'll have to think more on this. |
You'd have to ask the Postgres developers. |
You can now query directly without explicitly preparing a statement in tokio-postgres. |
First of all, I'd like to thank you for all your hard work on this project! My use-case (complex analytical queries) didn't really mesh too well with Diesel, and I've since migrated my entire codebase to tokio-postgres. The ergonomics of async are amazing and have made my code much cleaner and shorter.
However, there are a few things I miss from Diesel, and I was curious to get your thoughts on them. I think with a few small changes that this library could become seriously amazing!
1. Pass by reference
I notice that the array of arguments along with each argument itself needs to be passed by reference to a query. Would it not be more efficient and cleaner to pass small Copy values like integers by value?
2. Required to use all passed parameters to a query
Do you think it might be a good idea to remove the error that results from not using every parameter passed to the query? I use
format!
to assemble some complex queries, and sometimes this results in not having to use every parameter, depending on the circumstances. In Diesel, if a parameter is not used, then it is just ignored and the query proceeds regardless. To accommodate this, I'm currently appending things likeAND $3 = $3
just to satisfy the restriction of having to use all parameters.3. Is it possible to query without calling prepare first?
Some queries I have are so simple that it seems a bit redundant to have to
prepare
the SQL first before executing it. I see that there is asimple_query
function, and apparently this uses a different protocol of which I am ignorant of (simple query protocol). I'm not sure of how or whether or not the semantics of this differs from the regularquery
function. Apparently rows are returned as strings instead? If so, it'd be nice to have aquery
function that just takes a SQL string and has otherwise identical semantics to the regular query.4. Have a function for retrieving a single row?
It is often the case that you are only retrieving a single row from a query. In Diesel this functionality is supported with the get_result function. What do you think about including something like this?
5. Automatic deserialization into a struct
I've brought this up in a separate issue before, but I think this one is probably the most important. It is quite cumbersome to have to manually build a struct by calling
get
on each column. Thankfully I have found the serde_tokio_postgres crate, which provides this exact functionality, which in practice looks like this:Also please note that this is a fork of an already small and relatively stale crate (it required a few changes to work with
tokio_postgres
as opposed to regularrust_postgres
).However, even this is a bit verbose, which I think could be lessened with official integration into the main library. Have you considered merging its functionality with this crate? It would be a huge ergonomic win.
Thanks for reading! Sorry if any of my suggestions are dumb. I'm still new to Rust.
The text was updated successfully, but these errors were encountered: