Diesel的查找或过滤器执行删除操作的一般用法 [英] Generic usage of Diesel's find or filter to perform deletions

查看:109
本文介绍了Diesel的查找或过滤器执行删除操作的一般用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用通用Diesel函数来缩小重复性任务,例如基于主键删除行.

I'm trying to use generic Diesel functions to shrink repetitive tasks like deleting a row based on the primary key.

我对行进行通用插入的速度相对较快,但是删除查询似乎非常困难.我尝试通过使用find()filter()来解决它.我还参考了类似的主题 1

I got generic insertion of rows working relatively quick, but deletion queries seem to be quite hard. I tried solving it both by using find() and filter(). I also consulted similar topics 1 and 2 without success.

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

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

This leads to the following error which I cannot interpret at all:

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`

使用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在数据结构中未知.我可以考虑一个缺失的特征,该特征保证了该行的存在,但是我没有发现任何有关这种行为的东西.

In addition to the previous error, this has an error message about id not being known in the data structure. I can think about one missing trait, which guarantees the existence of that row, but I haven’t found anything about such behavior.

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`

推荐答案

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

Generics aren't easy. Generics in a highly generic system like Diesel are even harder.

我更喜欢将步骤分解为非常小的部分,并尽可能避免链接.有了它,您基本上将需要为每个步骤添加特征范围.一件不错的事情是对非常复杂的特征范围使用/创建类型别名. 柴油提供了许多此类,您可以自己制造您的特殊用途.

I prefer to break the steps down into very small parts and avoid chaining as much as possible. With that in play, you will basically need to add trait bounds for each step. One nice thing to do is to use / create type aliases for very complicated trait bounds. Diesel provides a number of these and you can make your own for your special uses.

当我查看生成的错误消息时,我主要查看了由调用的函数/方法描述的类型范围.

While I looked at the error messages generated, I mostly looked at the type bounds described by the functions / methods being called.

逐点:

  1. .find 来自 FindDsl .
  2. delete 需要 ,并用T::TableT::WhereClause参数化.这是自定义类型别名DeleteFindStatement.
  3. .execute 来自 ExecuteDsl .
  1. .find comes from FindDsl.
  2. delete requires IntoUpdateTarget.
  3. The resulting type of calling delete is a DeleteStatement, parameterized with T::Table and T::WhereClause. This is the custom type alias DeleteFindStatement.
  4. .execute comes from 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应该是什么.如错误消息中所示.

You will need to try it on your own for the filter-based version, as you didn't provide enough code to tell what id should even be; as shown in your error message.

另请参阅:

即使在所有情况下都为&str,也可以使主键具有通用性吗?

is there a benefit in making the primary key generic, even if it is &str in all cases?

对我来说,使用通用类型比插入一堆通用生命周期参数要容易得多.

For me, it's easier to use a generic type than it is to insert a bunch of generic lifetime parameters.

这篇关于Diesel的查找或过滤器执行删除操作的一般用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆