使用Diesel的通用功能导致溢出 [英] Generic function using Diesel causes overflow

查看:122
本文介绍了使用Diesel的通用功能导致溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用Rust编写的API,目的是在数据库中公开约15个表.我已经编写了几个非常相似的函数来公开每个表,所以我认为我会努力破解多态性以简化代码.

I have an API written in Rust and it's goal is to expose ~15 tables in a database. I've written several very similar functions to expose each table so I thought I'd take a crack at polymorphism to simplify the code.

我已将所有代码简化为一个文件:

I've reduced all the code to a single file:

#[macro_use]
extern crate diesel;
extern crate dotenv;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

table! {
    table1 (id) {
        id -> Int4,
        value -> Text,
    }
}

table! {
    table2 (id) {
        id -> Int4,
        value -> Text,
    }
}

#[derive(Identifiable, Queryable, Serialize)]
#[table_name = "table1"]
struct Model1 {
    pub id: i32,
    pub value: String,
}

#[derive(Identifiable, Queryable, Serialize)]
#[table_name = "table2"]
struct Model2 {
    pub id: i32,
    pub value: String,
}

use dotenv::dotenv;
use std::env;

fn get_connection() -> PgConnection {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    PgConnection::establish(&database_url).expect("Database not working")
}

use diesel::QueryDsl;
use diesel::pg::PgConnection;
use diesel::query_dsl::LoadQuery;
use diesel::result::Error;
use diesel::query_dsl::filter_dsl::FindDsl;
use serde::Serialize;
use serde_json::to_string;

fn get_row<'a, Model, Table>(table: Table, id: i32) -> Result<String, Error>
where
    Table: QueryDsl,
    <Table as FindDsl<i32>>::Output: LoadQuery<PgConnection, Model>,
    Model: Serialize,
{
    let result: Model = table.find(id).load(&get_connection())?;
    Ok(to_string(&result)?)
}

fn main() {
    let row1 = get_row::<Model1, _>(table1::table, 1);
    let row2 = get_row::<Model2, _>(table2::table, 1);
}

这是我的Cargo.toml文件

This is my Cargo.toml file

[package]
name = "question"
version = "0.1.0"

[dependencies]
diesel = {version = "*", features = ["postgres"]}
diesel_codegen = "*"
serde = "*"
serde_derive = "*"
serde_json = "*"
dotenv = "*"

当我尝试运行它时,出现以下编译器错误:

When I try to run this, I get the following compiler error:

error[E0275]: overflow evaluating the requirement `<Table as diesel::query_dsl::filter_dsl::FilterDsl<_>>::Output`
  --> src/main.rs:54:1
   |
54 | / fn get_row<'a, Model, Table>(table: Table, id: i32) -> Result<String, Error>
55 | | where
56 | |     Table: QueryDsl,
57 | |     <Table as FindDsl<i32>>::Output: LoadQuery<PgConnection, Model>,
...  |
61 | |     Ok(to_string(&result)?)
62 | | }
   | |_^
   |
   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate

编译器告诉我可以通过增加递归限制来解决此问题,但我尝试将其执行到8096,但错误仍未得到解决.

The compiler tells me that I might resolve the issue by increasing the recursion limit, but I tried doing that up to 8096 and the error still wasn't resolved.

推荐答案

距离您并不遥远:

use diesel::dsl::Find;
use diesel::pg::PgConnection;
use diesel::query_dsl::{LoadQuery, RunQueryDsl};
use diesel::query_dsl::filter_dsl::FindDsl;
use diesel::result::Error;

fn get_row<'a, Model, Table>(table: Table, id: i32) -> Result<String, Error>
where
    Table: FindDsl<i32>,
    Find<Table, i32>: LoadQuery<PgConnection, Model>,
{
    let conn = get_connection();
    let result = table.find(id).load::<Model>(&conn)?;
    unimplemented!()
}

注意事项:

  1. Diesel具有许多辅助类型别名,这些别名使编写特征范围更加容易.在这里,已使用Find别名.

使用更具体的特征范围而不是不太具体的特征范围会更加明显.在这里,切换到FindDsl而不是QueryDsl可能是导致代码编译的原因. QueryDsl并不意味着您可以作为find ="nofollow noreferrer"> QueryDsl::find方法实际上还有更多的特征范围:

It can be more obvious to use more specific trait bounds instead of less specific ones. Here, switching to FindDsl instead of QueryDsl is probably what makes the code compile. QueryDsl doesn't mean that you can call find as the QueryDsl::find method actually has further trait bounds:

fn find<PK>(self, id: PK) -> Find<Self, PK>
where
    Self: FindDsl<PK>,

  • load的返回值是结果的Vec,但是您已将类型注释为单个值.也许您想使用get_resultfirst代替?

  • The return value of load is a Vec of results, but you had annotated the type as a single value. Perhaps you wanted to use get_result or first instead?

    我删除了Serde专用代码,因为没有明显的方法可以将Serde错误转换为Diesel错误.这取决于您.

    I removed the Serde-specific code because there's no obvious way to convert the Serde error to a Diesel error; that's up to you.

    这篇关于使用Diesel的通用功能导致溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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