Rust Diesel,加载从多个表中选择列的 sql_query 的结果时出错

Yth*_*her 6 rust rust-diesel

我尝试使用 Diesel 执行与单个表不匹配的 sql_query,但出现以下错误:

    error[E0277]: the trait bound `Untyped: load_dsl::private::CompatibleType<TimeCountSumaryEntry, _>` is not satisfied
        --> src/api/cra_service.rs:263:10
         |
    263  |         .load::<TimeCountSumaryEntry>(connection)
         |          ^^^^ the trait `load_dsl::private::CompatibleType<TimeCountSumaryEntry, _>` is not implemented for `Untyped`
         |
         = help: the trait `load_dsl::private::CompatibleType<U, DB>` is implemented for `Untyped`
         = note: required because of the requirements on the impl of `LoadQuery<'_, _, TimeCountSumaryEntry>` for `SqlQuery`
    note: required by a bound in `diesel::RunQueryDsl::load
Run Code Online (Sandbox Code Playgroud)

这是相关代码(其中子句是固定的以简化实验):

#[derive(QueryableByName, Debug)]
struct TimeCountSumaryEntry {
    #[diesel(sql_type = Integer)]
    month: i32,
    #[diesel(sql_type = Integer)]
    year: i32,
    #[diesel(sql_type = Integer)]
    project_id: i32,
    #[diesel(sql_type = Text)]
    project_code: String,
    #[diesel(sql_type = Double)]
    time_spent: f32,
    #[diesel(sql_type = Text)]
    fullname: String,
}

fn _timecount_by_filters(
    user_id: Option<i32>,
    month: Option<u8>,
    year: Option<u16>,
    connection: &mut PgConnection,
) {
    let query =
        "SELECT
            EXTRACT(MONTH FROM tc.date_assigned) as \"month\",
            EXTRACT(YEAR FROM tc.date_assigned) as \"year\",
            tc.project_id as project_id,
            p.project_code as project_code,
            sum(tc.time_spent) as time_spent,
            u.lastname || ' ' || u.firstname as fullname
        FROM
            time_count tc
            JOIN cra c on tc.cra_id = c.cra_id
            JOIN project p on p.project_id = tc.project_id
            JOIN \"user\" u on u.user_id = c.user_id
        WHERE
            u.user_id = 3
            and EXTRACT(MONTH FROM tc.date_assigned) = 8
            and EXTRACT(YEAR FROM tc.date_assigned) = 2022
        GROUP BY
            tc.project_id, u.lastname, u.firstname, \"month\", \"year\", p.project_code
        ORDER BY
            \"year\", \"month\", u.lastname, u.firstname, tc.project_id";

    let time_counts_sumary = diesel::dsl::sql_query(query)
        .load::<TimeCountSumaryEntry>(connection)
        .expect("Error getting cra ids");
    println!("{:?}", time_counts_sumary);
}
Run Code Online (Sandbox Code Playgroud)

我找不到任何提及如何处理此用例的资源(甚至这根本不可能)。我第一次尝试使用查询生成器,但似乎不可能,所以我认为 sql_query 是从数据库(postgresql)获取这些数据的方法,而不会在此过程中获取无用的信息,但也许有更好的方法。

有没有人遇到过这个用例或有任何关于如何处理它的提示?

Yth*_*her 7

如果有人遇到同样的问题,我找到了问题所在。

Diesel 无法匹配它来自的类型sql_query和我在 中提到的内容TimeCountSumaryEntry

首先这里:

#[diesel(sql_type = Double)]
time_spent: f32,
Run Code Online (Sandbox Code Playgroud)

我打错了Double(应该是f64

其次,该EXTRACT()函数返回postgresql 中的数字。我可以使用数字柴油功能,但就我而言(年和月),整数就足够了。所以我必须在请求中指定类型CAST()。像这样:

CAST(EXTRACT(MONTH FROM tc.date_assigned) as Integer) as "month",
CAST(EXTRACT(YEAR FROM tc.date_assigned) as Integer) as "year",
Run Code Online (Sandbox Code Playgroud)

这是工作代码:

#[derive(QueryableByName, Debug)]
struct TimeCountSumaryEntry {
    #[diesel(sql_type = Integer)]
    month: i32,
    #[diesel(sql_type = Integer)]
    year: i32,
    #[diesel(sql_type = Integer)]
    project_id: i32,
    #[diesel(sql_type = Text)]
    project_code: String,
    #[diesel(sql_type = Double)]
    time_spent: f64,
    #[diesel(sql_type = Text)]
    fullname: String,
}

fn _timecount_by_filters(
    user_id: Option<i32>,
    month: Option<u8>,
    year: Option<u16>,
    connection: &mut PgConnection,
) {
    let query =
        "SELECT
            CAST(EXTRACT(MONTH FROM tc.date_assigned) as integer) as \"month\",
            CAST(EXTRACT(YEAR FROM tc.date_assigned) as integer) as \"year\",
            tc.project_id as project_id,
            p.project_code as project_code,
            sum(tc.time_spent) as time_spent,
            u.lastname || ' ' || u.firstname as fullname
        FROM
            time_count tc
            JOIN cra c on tc.cra_id = c.cra_id
            JOIN project p on p.project_id = tc.project_id
            JOIN \"user\" u on u.user_id = c.user_id
        WHERE
            u.user_id = 3
            and EXTRACT(MONTH FROM tc.date_assigned) = 8
            and EXTRACT(YEAR FROM tc.date_assigned) = 2022
        GROUP BY
            tc.project_id, u.lastname, u.firstname, \"month\", \"year\", p.project_code
        ORDER BY
            \"year\", \"month\", u.lastname, u.firstname, tc.project_id";

    let time_counts_sumary = diesel::dsl::sql_query(query)
        .load::<TimeCountSumaryEntry>(connection)
        .expect("Error getting cra ids");
    println!("{:?}", time_counts_sumary);
}
Run Code Online (Sandbox Code Playgroud)