I am trying to make a function that will be part of building up SQL-like queries. It gives the qfmt() method "Query Format" that can be used to help build a statement. Integers and Floats just need to be converted to a string "WHERE x = 5 " but strings need to be wrapped in (single) quotes "WHERE x = '5' "
Below is my attempt: Most generic types that implement ToString can simply use .to_string(), but strings themselves need the extra quotes.
use std::string::ToString;
pub trait QueryElement {
fn qfmt(&self) -> String;
}
impl<T> QueryElement for T where T: ToString {
fn qfmt(&self) -> String {
self.to_string()
}
}
impl QueryElement for String {
fn qfmt(&self) -> String {
format!("'{}'", &self)
}
}
This returns the following error on compilation:
14 | impl QueryElement for String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for std::string::String
I understand what the compiler is telling me: I am uncertain if there is a workaround. Any ideas are appreciated.
You should consider not using a blanket impl<T> QueryElement for T where T: ToString here—do you really need that level of generality or can you get away with just implementing QueryElement for some numeric types, one at a time? A simple macro can eliminate the boilerplate involved in the second approach.
If you definitely need arbitrary ToString types to work with QueryElement, I'd suggest modifying the blanket impl with a newtype, like this:
pub struct UnquotedLiteral<T>(pub T);
// no more overlap because `String` and `UnquotedLiteral<T>` are distinct,
// for every `T`
impl<T> QueryElement for UnquotedLiteral<T> where T: ToString {
fn qfmt(&self) -> String {
self.0.to_string()
}
}
Then if x is a value of some ToString type, you can do UnquotedLiteral(x).qfmt() to use it for building a statement.
Thanks Cole. I think you are probably right in that selecting a few numeric types and implementing QueryElement for them is the more reasonable option. I will leave the trait as public so users can implement it on a custom or obscure type if they have a particular need.
Note that you’ll want to do more processing than this if these strings are user-supplied. As written, they can break out of the quotes and add arbitrary SQL to the query. (cf XKCD)