Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic function using Diesel causes overflow

Tags:

generics

rust

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

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

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.

like image 581
Luuk Wester Avatar asked Jan 28 '18 15:01

Luuk Wester


People also ask

What happens if you put Def in a diesel engine?

If you suspect you have DEF in your diesel’s fuel system, do not drive the vehicle and do not attempt to start the engine. Don’t even turn the key on, as this will energize the fuel system and could pump DEF-contaminated fuel into the rest of the fuel system.

How is overflow fuel returned to the fuel tank?

When the day tank (freestanding or generator sub-base mounted) is served by an underground storage tank (below grade), the return of overflow fuel may be possible by gravity alone.

What does the NFPA say about fuel overflow?

The National Fire Protection Association (NFPA) addresses fuel overflow by stating that any fuel tank filled by a pump shall be equipped with an overflow return line (NFPA 37 6.5.4, 6.5.4.1, 6.5.4.2). Of key importance, NFPA also requires that this overflow return line be routed “back to the source tank, or to a collection system”.

What causes a diesel engine to overheat with coolant?

1. Coolant Leaks Coolant Leaks are the primary cause of overheating in diesel engines and can be easily identified, as you will notice either a low coolant level or an excessive amount of bubbles in the coolant. This can be a result of engine components, such as the cylinder head, expanding due to excess heat.


Video Answer


1 Answers

You weren't far off:

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

Points to note:

  1. Diesel has a bunch of helper type aliases which make writing trait bounds easier. Here, the Find alias has been used.

  2. 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>,
    
  3. 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?

  4. 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.

like image 55
Shepmaster Avatar answered Sep 21 '22 15:09

Shepmaster