-
-
Notifications
You must be signed in to change notification settings - Fork 192
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
Implement sqlx::IntoArguments for Values #275
Conversation
Small question: when writing a u64 to Postgres or Sqlite, since they don't support that format, I try to convert it to a i64 and unwrap if it fails. Would it perhaps be better to fail-fast by panicking for all inputs, forcing the user to do the conversion themselves? |
Example usage in a real project: lldap/lldap#127 |
This is a big shift from the macro (https://github.com/SeaQL/sea-query/blob/master/src/driver/sqlx_sqlite.rs) that was used previously to generate that. Like I suggested a while ago I think those integrations should be in different crates then you can greatly simplify the number of features and stay consistent between this and the bind macro. Different crates would also allow me to write the diesel integration. |
One problem with a different crate is that you can't condition on the sea query features that are enabled (or can you? I didn't find out how to do that for sqlx here). That means that you'll have to repeat the same feature flags for the other crate. Here we can remove all the feature flags that I added with their sqlx versions, you'll just get a not very clear error message if you enable a feature for sea query but not sqlx. How would the conversion look like in the other crate? Adding a Anyway, we should at least keep the |
If we do a separate crate I think its fair to have duplicate features and that a feature X can also enable it on sea-query (like you already did) so you dont have to specify it twice. I mean yeah that could work too. I am just trying to think on what is more confusing for the user. I think that if you enable sqlx-mysql and with-chrono on sea-query its fair to assume that you need to enable chrono on the sqlx dependency too. Documentation can help on that. Hum yeah this is more annoying and one major point in favor of not splitting in another crate. Maybe then its a matter of splitting it in modules so they are not all in one giant file and its easy to enable/disable each flavour. I do plan on bringing my diesel implementation in the same format so lets try to make that work. |
Welcome back, long time no see!
Agree. The reason I don't want to include sqlx as a dependency is because yeah, it forces us to select a runtime and that's not where sea-query should do. Ideally, sqlx (like postgres) would split out a I also can't think of a better idea than moving this |
Only for tests. Otherwise, the only requirement is that in the final binary, a runtime is selected. It's still up to the user to choose what runtime they want. If we have a non-default feature like I added there, it's not a problem (and I only added it to make --all-features work, otherwise it's really not needed). Yeah, ideally sqlx would split out the core types, but that's non-trivial work. Moving |
Another advantage of |
Hmm, no, actually this won't help with the argument resolution, we'd still have to implement it for Any as well. Anyway, what's the decision on this? Do we want to cut this back to only IntoIterator, or keep it like this? |
I think this needs to wait on the merge of #292 |
@Sytten I agree. @nitnelave If you need help adapting your PR, I'm ready to help. |
Thanks for the offer @ikrivosheev ! I should be able to handle it myself, once I understand what I'm adapting to :) What do we want to implement? Are we still on board for the intoargument trait? |
I see that #292 is merged. AFAICT, it's just a refactoring of the drivers, so I'm not sure it changes much our approach here. |
With rust 1.60 we can now do |
@tyt2y3 any opinion here? Do we want to proceed with this PR or not? If we do, I'll add support for the |
@nitnelave I like idea @tyt2y3 about: don't bring sqlx into sea-query. Two variants:
But I don't understand what is different between this and current driver implants? |
The problem is that we can't implement a trait on Note that the sqlx dependency is there only if you enable the sqlx feature. The reason why I consider this approach superior to drivers is:
|
One idea I can come up with is to have a sub crate that implements a new trait on the various queries, adding a It's kinda hard to discover though, in that case we should probably add some comments here around the sqlx feature referencing that crate. |
I would be in favour of moving values to the driver crate, maybe it could be renamed to better express that. |
That doesn't really solve the issue of depending on sqlx: sea-query depends on the driver crate, which depends on sqlx. Plus you'll have to move all the dependencies of Value to that crate as well. I don't think it would bring much clarity. |
@nitnelave, no, sea-query-driver doesn't depend on sqlx... |
But I like your idea and the interface is convenient. |
Agreed but it is a solved problem on 1.60 though as you can mix optional dependencies with features so its just a matter of waiting a couple of weeks for people to upgrade IMO. |
Well, not now, but if we implement |
We could implement pub struct Values(pub sea_query::Values); Then, impl IntoIterator for Values {
type Item = sea_query::Value;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'q> sqlx::IntoArguments<'q, sqlx::postgres::Postgres> for Values {
...
} |
@billy1624 but you still need the macros to wrap the values. Can we merge this with the idea I had above, implementing a new method (via a trait) on the queries that pre-wraps the values? |
Oh, so it's like the current PR, but in an external crate?
I guess this is the same as what we are doing with Rusqlite now. |
@tyt2y3 it would be a mix of my external crate proposal and @billy1624 's proposal: the driver macros introduce a new wrapping Values type and implement IntoArgument for it. And in addition, they create a new trait and implement it for all queries, that adds a |
Sounds like an intricate plan. But that's our end goal yeah. As long as 1) it does not affect existing users 2) is opt-in we will merge it and see how it works in action, and might actually replace our current driving mechanism (which is a bit hacky IMO) |
I updated the implementation, it should be rather complete now. I also added an example for using with @Sytten I'm not sure the two drivers will have anything in common: in the case of sqlx we need to implement At most I can picture a shared wrapper, something like |
One difference between this and the driver approach (more of a difference of choice): the drivers "support" the time arguments for sqlite by calling EDIT: in the example, it's asymmetric: there is custom code to decode, but not to encode. With my update, it makes it more consistent by making the encoding appear. |
Agreed that is what I was suggesting, a |
Any suggestion for the function name? |
Hum no particular idea, just throwing a couple more in the hat: |
Hmm, I disagree with |
Them a |
@billy1624 @tyt2y3 any opinion on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! @nitnelave
args.add(i.map(Into::<i64>::into)); | ||
} | ||
Value::BigUnsigned(i) => { | ||
args.add(i.map(|i| <i64 as std::convert::TryFrom<u64>>::try_from(i).unwrap())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might result in unexpected panic
I guess conversion is required because PostgreSQL doesn't support u64
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. How else would you handle this? Any
is limited to the subset that every DB supports.
sea-query-binders/src/sqlx_mysql.rs
Outdated
Value::ChronoDateTimeWithTimeZone(_) => { | ||
panic!("MySql doesn't support fixed offset chrono types"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can bind it as string just like what we did at
v @ Value::ChronoDateTimeWithTimeZone(_) => query.bind(v.chrono_as_naive_utc_in_string()),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Value::BigUnsigned(i) => { | ||
args.add(i.map(|i| <i64 as std::convert::TryFrom<u64>>::try_from(i).unwrap())); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might result in unexpected panic
Same here.
Btw... I think the related implementation inside sea-query-driver
is faulty as well. We just case u64
as i64
. It will (integer) underflow silently.
Value::BigUnsigned(v) => bind!(v, i64),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no correct behavior here, unless you just want to panic on every u64
(and same for Any
).
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nitnelave thank you for contribution! Some comments
@ikrivosheev @billy1624 Any other comments? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nitnelave, thank you! Sory for delay. LGTM!
Thanks for the review! Can we merge this, then? |
85db1ab
to
7d27267
Compare
7d27267
to
445b660
Compare
@tyt2y3 when you have time for a review :) |
Any chance of a review? |
I am about to make some changes and merge into master |
Fixes #273
PR Info
Adds
Implements sqlx::IntoArguments for Values.
Implement IntoIterator for Values.
Breaking Changes
It will break for users who have enabled an optional feature (e.g. with-chrono) and an sqlx backend.
To avoid that, we could add yet another feature to guard the conversion, but it would make the API less discoverable. On the other hand, the errors you get in the scenario above are very clear (it tells you which feature you need to enable).