如何访问在 Diesel 中通常访问的 table 的具体列?
How to access concrete columns of a table accessed generically in Diesel?
我很难为这个问题选择一个准确简洁的标题。
这个问题扩展了@Shepmaster 在这里给出的出色答案:
其解法为:
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))
}
在上面的代码片段中,Table
和 Expression
作为参数提供。如何进一步抽象此函数,使得 Table
和 Expression
都不必作为参数传递?
我已经想出了如何抽象 Table
(见下文),但我不知道如何删除 Expression
参数以便该函数可以与任何Table
包含 time
列。
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))
}
已更新
像这样:
# 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)
}
不可能以这种通用方式访问列。每列都是它自己的零大小结构,放置在以 table 命名的模块中。 (有关 table!
生成的代码的详细信息,请参阅 "Schema in depth" guide)。 Rust 不提供任何选项来通过泛型处理来自同一模块的不同类型。
写的可以只提供你自己的特征,允许你指定相应的列并为相应的table(或模型,或任何你想要的类型)实现它:
trait MyTimeColumnHelper {
type TimeColumn: Default;
}
impl MyTimeColumnHelper for crate::schema::cat::table {
type TimeColumn = crate::schema::cat::time;
}
这样您的泛型函数就可以绑定到这个附加特征:
pub fn get_most_recent_entry<'a, Tbl, Record>(
conn: &SqliteConnection
) -> Result<i32, String>
where
MyTimeColumnHelper::TimeColumn: diesel::ExpressionMethods,
Tbl: HasTable + MyTimeColumnHelper,
Tbl::Table: OrderDsl<Desc<MyTimeColumnHelper::TimeColumn>>,
Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
Tbl::Table: OrderDsl<Desc<MyTimeColumnHelper::TimeColumn>>,
Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
{
Tbl::table()
.order(MyTimeColumnHelper::TimeColumn::default().desc())
.first(conn)
.optional()
.map(|x| x.map_or(0, |x| x.time()))
.map_err(|e| format!("Error here! {:?}", e))
}
我很难为这个问题选择一个准确简洁的标题。
这个问题扩展了@Shepmaster 在这里给出的出色答案:
其解法为:
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))
}
在上面的代码片段中,Table
和 Expression
作为参数提供。如何进一步抽象此函数,使得 Table
和 Expression
都不必作为参数传递?
我已经想出了如何抽象 Table
(见下文),但我不知道如何删除 Expression
参数以便该函数可以与任何Table
包含 time
列。
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))
}
已更新
像这样:
# 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)
}
不可能以这种通用方式访问列。每列都是它自己的零大小结构,放置在以 table 命名的模块中。 (有关 table!
生成的代码的详细信息,请参阅 "Schema in depth" guide)。 Rust 不提供任何选项来通过泛型处理来自同一模块的不同类型。
写的可以只提供你自己的特征,允许你指定相应的列并为相应的table(或模型,或任何你想要的类型)实现它:
trait MyTimeColumnHelper {
type TimeColumn: Default;
}
impl MyTimeColumnHelper for crate::schema::cat::table {
type TimeColumn = crate::schema::cat::time;
}
这样您的泛型函数就可以绑定到这个附加特征:
pub fn get_most_recent_entry<'a, Tbl, Record>(
conn: &SqliteConnection
) -> Result<i32, String>
where
MyTimeColumnHelper::TimeColumn: diesel::ExpressionMethods,
Tbl: HasTable + MyTimeColumnHelper,
Tbl::Table: OrderDsl<Desc<MyTimeColumnHelper::TimeColumn>>,
Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
Tbl::Table: OrderDsl<Desc<MyTimeColumnHelper::TimeColumn>>,
Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>: LoadQuery<SqliteConnection, Record> + LimitDsl,
Limit<Order<Tbl::Table, Desc<MyTimeColumnHelper::TimeColumn>>>: LoadQuery<SqliteConnection, Record>,
Record: Time,
{
Tbl::table()
.order(MyTimeColumnHelper::TimeColumn::default().desc())
.first(conn)
.optional()
.map(|x| x.map_or(0, |x| x.time()))
.map_err(|e| format!("Error here! {:?}", e))
}