I'm having difficulty selecting an accurate and concise title for this question.
This question expands on the excellent answer given by @Shepmaster here: https://stackoverflow.com/a/47880065/3224771
The solution of which is:
use diesel::expression::operators::Desc;
use diesel::helper_types::{Limit, Order};
use diesel::query_dsl::methods::{LimitDsl, OrderDsl};
use diesel::query_dsl::LoadQuery;
pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
conn: &SqliteConnection,
table: Tbl,
time: Expr,
) -> Result<i32, String>
where
Expr: diesel::ExpressionMethods,
Tbl: OrderDsl<Desc<Expr>>,
Order<Tbl, Desc<Expr>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl, Desc<Expr>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
{
table
.order(time.desc())
.first(conn)
.optional()
.map(|x| x.map_or(0, |x| x.time()))
.map_err(|e| format!("Error here! {:?}", e))
}
In the snippet above, the Table
and Expression
are being provided as arguments. How could this function be further abstracted such that both the Table
and Expression
do not have to be passed as parameters?
I've figured out how to abstract the Table
(see below), but I can't figure out how to remove the Expression
argument so that the function can be used with any Table
that contains the time
column.
use diesel::expression::operators::Desc;
use diesel::helper_types::{Limit, Order};
use diesel::query_dsl::methods::{LimitDsl, OrderDsl};
use diesel::query_dsl::LoadQuery;
use diesel::SqliteConnection;
use crate::diesel::{RunQueryDsl, OptionalExtension};
use diesel::associations::HasTable;
pub trait Time {
fn time(&self) -> i32;
}
pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
conn: &SqliteConnection,
time: Expr,
) -> Result<i32, String>
where
Expr: diesel::ExpressionMethods,
Tbl: HasTable,
Tbl::Table: OrderDsl<Desc<Expr>>,
Order<Tbl::Table, Desc<Expr>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl::Table, Desc<Expr>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
{
Tbl::table()
.order(time.desc())
.first(conn)
.optional()
.map(|x| x.map_or(0, |x| x.time()))
.map_err(|e| format!("Error here! {:?}", e))
}
UPDATED
Something like this:
# Cargo.toml
[dependencies]
diesel = { version = "1.4.5", features = ["sqlite", "extras"] }
#[derive(Queryable)]
pub struct Cat {
id: u32,
name: String,
time: i32 //time record created
}
impl Time for Cat {
fn time(&self) -> i32 {
self.time
}
}
pub fn get_most_recent_entry<'a, Tbl, Record>(
conn: &SqliteConnection
) -> Result<i32, String>
where
// Don't know how to setup trait bounds for the expression
// to express any table that has the same time column
{
Tbl::table()
.order(Tbl::columns::time.desc()) // Something like this
.first(conn)
.optional()
.map(|x| x.map_or(0, |x| x.time()))
.map_err(|e| format!("Error here! {:?}", e))
}
use crate::schema::cat;
fn main() {
let conn = pool.get()?;
get_most_recent_entry::<cat::dsl::cat, _>(&conn)
}