Versions
-
Rust:
rustc 1.35.0-nightly
-
Diesel:
diesel 1.3.0
-
Database:
PostgreSQL 10
-
Operating System
Ubuntu
Feature Flags
[“postgres”, “r2d2”, “chrono”]
Problem Description
I want to receive data from a database with a flexible response structure. I do not have a specific structure for each response from the database. My requests are formed through a set of stackable conditions and the result of the request can be each query unique, so I can’t fit it into any response structure but I should to that
let data = query.load::<_>(&connection)?;
What are you trying to achieve?
I want to get the raw response data from the database, in which I can generate json, hashmap (key, value) or any other flexible structure, I do not know how many columns contain the answer
What is the expected output?
Array of rows and columns
What is the actual output?
I should set type for query result
Example
let mut query = users::table
.left_join(profile::table)
.left_join(posts::table)
.left_join(notes::table)
.left_join(bookmarks::table)
.into_boxed();
if !filter.is_empty() {
query = query.filter(sql(" ").bind::<Text, _>(filter))
}
if !select.is_empty() {
query = query.select(sql(" ").bind::<Text, _>(select))
}
if !group.is_empty() {
query = query.filter(sql("GROUP BY ").bind::<Text, _>(group));
}
let result = query.load(connection)
Firstly that’s currently not possible using diesel, but we’ve plan to add “something” like this in our next release. We are currently looking how to
Could you describe how that would look like with more details? How would such an returning type look like? Could you maybe even provide a actual type definition for that?
The good example is a create https://crates.io/crates/postgres where we can see
conn.execute("INSERT INTO person (name, data) VALUES ($1, $2)",
&[&me.name, &me.data]).unwrap();
for row in &conn.query("SELECT id, name, data FROM person", &[]).unwrap() {
let person = Person {
id: row.get(0),
name: row.get(1),
data: row.get(2),
};
println!("Found person {}", person.name);
}
and I want to use all the features of diesel to sanitize my raw db query, but got a raw result without deserialization, where I can create my own dynamic data structure in each row of the query result.
If we describe it as some kind of code, it will look like this.
let mut query = users::table
.left_join(profile::table)
.left_join(posts::table)
.left_join(notes::table)
.left_join(bookmarks::table)
.into_boxed();
if !filter.is_empty() {
query = query.filter(sql(" ").bind::<Text, _>(filter))
}
if !select.is_empty() {
query = query.select(sql(" ").bind::<Text, _>(select))
}
if !group.is_empty() {
query = query.filter(sql("GROUP BY ").bind::<Text, _>(group));
}
for row in &connection.query(&query)? {
row.get(0)
}
As already written in the github issue: You cannot use binds to insert sql. So that never will work that way.
Additionally even if we add that interface you will have to choose between using the type save approach which requires us to know at least the return types at compile time our building your own query from string parts that will just be passed to the database as it is provided.
There is any method to sanitize the query? This will be enough for my case and I would just like to get a set of row and columns for my query.
There is no way to sanitise a sql query without fully parsing it. Given that diesel supports multiple backends that is it lot more complex than writing only a simple sql parser (and even that is quite challenging). So that’s clearly out of scope for diesel.
Most of you dynamic query building issues are already solved in our dsl by using some of the boxed variants linked in the original github issue. The only missing part is currently the ability to build dynamic select clauses which we may solve for diesel 2.0.
1 Like
When can we expect the release of diesel 2.0
Currently we do not have ETAs. More people helping to implement the necessary features may make it happen faster.
1 Like