Diesel查找或过滤以执行删除的一般用法

问题描述 投票:0回答:1

我正在尝试使用通用柴油机功能来缩减重复性任务,例如根据主键删除行。

我得到的通用行插入工作相对较快,但删除查询似乎很难。我尝试使用find()filter()解决它。我也咨询了类似的主题12没有成功。

Using find

use diesel::prelude::*;
use diesel::query_dsl::methods::FindDsl;
use std::error::Error;

pub struct DB {
    conn: SqliteConnection,
}

impl DB {
    pub fn remove_row<'a, T>(&self, table: T, pk: &'a str) -> Result<(), Box<Error>>
    where
        T: FindDsl<&'a str>,
        <T as FindDsl<&'a str>>::Output: diesel::Identifiable,
        <T as FindDsl<&'a str>>::Output: diesel::associations::HasTable,
    {
        diesel::delete(table.find(pk)).execute(&self.conn)?;
        Ok(())
    }
}

这会导致以下错误,我根本无法解释:

error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
   --> src/db/mod.rs:103:3
    |
103 |         diesel::delete (table.find (pk)) .execute (&self.conn) ?;
    |         ^^^^^^^^^^^^^^
    |
    = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
    = note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<_>` for `<<<T as diesel::query_dsl::filter_dsl::FindDsl<&'a str>>::Output as diesel::associations::HasTable>::Table as diesel::query_builder::AsQuery>::Query`
    = note: required because of the requirements on the impl of `diesel::query_builder::IntoUpdateTarget` for `<T as diesel::query_dsl::filter_dsl::FindDsl<&'a str>>::Output`
    = note: required by `diesel::delete`

Using filter()

use diesel::prelude::*;
use diesel::query_dsl::methods::FilterDsl;
use std::error::Error;

pub struct DB {
    conn: SqliteConnection,
}

impl DB {
    pub fn remove_row<T>(&self, table: T, pk: &str) -> Result<(), Box<Error>>
    where
        T: FilterDsl<bool>,
        <T as FilterDsl<bool>>::Output: diesel::Identifiable,
        <T as FilterDsl<bool>>::Output: diesel::associations::HasTable,
    {
        diesel::delete(table.filter(id.eq(pk))).execute(&self.conn)?;
        Ok(())
    }
}

除了上一个错误之外,还有一条关于id在数据结构中未知的错误消息。我可以考虑一个缺失的特性,它保证了那一行的存在,但我还没有发现任何关于这种行为的信息。

error[E0425]: cannot find value `id` in this scope
   --> src/db/mod.rs:117:33
    |
117 |         diesel::delete (table.filter (id.eq (pk))) .execute (&self.conn) ?;
    |                                       ^^ not found in this scope
help: possible candidates are found in other modules, you can import them into scope
    |
4   | use crate::db::schema::events::columns::id;
    |
4   | use crate::db::schema::ignored_events::columns::id;
    |
4   | use crate::db::schema::locations::columns::id;
    |
4   | use std::process::id;


error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
   --> src/db/mod.rs:117:3
    |
117 |         diesel::delete (table.filter (id.eq (pk))) .execute (&self.conn) ?;
    |         ^^^^^^^^^^^^^^
    |
    = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
    = note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<_>` for `<<<T as diesel::query_dsl::filter_dsl::FilterDsl<bool>>::Output as diesel::associations::HasTable>::Table as diesel::query_builder::AsQuery>::Query`
    = note: required because of the requirements on the impl of `diesel::query_builder::IntoUpdateTarget` for `<T as diesel::query_dsl::filter_dsl::FilterDsl<bool>>::Output`
    = note: required by `diesel::delete`
generics rust generic-programming rust-diesel
1个回答
0
投票

泛型并不容易。像Diesel这样的高度通用系统中的泛型更难。

我宁愿将步骤分解成非常小的部分,并尽可能避免链接。有了这个,你基本上需要为每一步添加特征界限。一件好事是为非常复杂的特征边界使用/创建类型别名。 Diesel provides a number of these,你可以自己做特殊用途。

当我查看生成的错误消息时,我主要查看被调用的函数/方法描述的类型边界。

逐点:

  1. .find来自FindDsl
  2. delete需要IntoUpdateTarget
  3. 调用delete的结果类型是DeleteStatement,用T::TableT::WhereClause参数化。这是自定义类型别名DeleteFindStatement
  4. .execute来自ExecuteDsl
use diesel::{
    associations::HasTable,
    helper_types::Find,
    query_builder::{DeleteStatement, IntoUpdateTarget},
    query_dsl::methods::ExecuteDsl,
};

type DeleteFindStatement<F> =
    DeleteStatement<<F as HasTable>::Table, <F as IntoUpdateTarget>::WhereClause>;

impl DB {
    pub fn remove_row<Tbl, Pk>(&self, table: Tbl, pk: Pk) -> Result<(), Box<Error>>
    where
        Tbl: FindDsl<Pk>,
        Find<Tbl, Pk>: IntoUpdateTarget,
        DeleteFindStatement<Find<Tbl, Pk>>: ExecuteDsl<SqliteConnection>,
    {
        let find = table.find(pk);
        let delete = diesel::delete(find);
        delete.execute(&self.conn)?;
        Ok(())
    }
}

您将需要自己尝试基于filter的版本,因为您没有提供足够的代码来告诉id应该是什么;如您的错误消息中所示。

也可以看看:

即使在所有情况下都是&str,使主键通用是否有好处?

对我来说,使用泛型类型比插入一堆通用生命周期参数更容易。

© www.soinside.com 2019 - 2024. All rights reserved.