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)
}