Rust diesel orm запросы

Я новичок в ржавчине и дизельном двигателе. Я пытаюсь выполнить следующие действия по моему запросу:

  • считать
  • Выбрать
  • порядок
  • предел

но я получаю сообщение об ошибке.
Я использую базу данных postgres.

Я добавил точную ошибку над запросами в комментарии.
Вот мой код:

schema.rs

table! {
    employee (employee_id) {
        employee_id -> Int4,
        name -> Nullable<Text>,
        age -> Nullable<Int4>,
        address -> Nullable<Text>,
        email -> Nullable<Text>,
        dept_id -> Int4,
        salary -> Nullable<Numeric>,
        created_on -> Nullable<Timestamp>,
        created_by -> Nullable<Text>,
        modified_on -> Nullable<Timestamp>,
        modified_by -> Nullable<Text>,
        is_active -> Nullable<Bool>,
    }
}

models.rs

#![allow(unused)]
#![allow(clippy::all)]
use super::schema::employee;

use bigdecimal::BigDecimal;
use chrono::NaiveDateTime;

#[derive(Queryable, Debug, Identifiable)]
#[table_name = "employee"]
#[primary_key(employee_id)]
pub struct Employee {
    pub employee_id: i32,
    pub name: Option<String>,
    pub age: Option<i32>,
    pub address: Option<String>,
    pub email: Option<String>,
    pub dept_id: i32,
    pub salary: Option<BigDecimal>,
    pub created_on: Option<NaiveDateTime>,
    pub created_by: Option<String>,
    pub modified_on: Option<NaiveDateTime>,
    pub modified_by: Option<String>,
    pub is_active: Option<bool>,
}

cargo.toml

[dependencies]
diesel = { version = "1.4.5", features = ["postgres","chrono","numeric"] }
dotenv = "0.15.0"
chrono = { version = "0.4.19" , features = ["serde"] }
bigdecimal = { version = "0.1.0" }

main.rs

#[macro_use]
extern crate diesel;
extern crate bigdecimal;
extern crate chrono;
extern crate dotenv;

use crate::models::Employee;
use crate::models::Players;
use crate::schema::employee::dsl::*;

use diesel::{pg::PgConnection, prelude::*};
use dotenv::dotenv;
use std::env;

mod models;
mod schema;

fn main() {
    dotenv().ok();
    let data_url: String = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let connection: PgConnection =
        PgConnection::establish(&data_url).expect(&format!("Error connect to {}", data_url));

    //get all employees name
    //This is working fine
    let _employee: Vec<Employee> = employee
        .load::<Employee>(&connection)
        .expect("Error loading department");

    for emp in _employee {
        println!("{}", emp.name.unwrap_or_default());
    }


    //----------------------------------------------
    //get employees count
    /*
    Error: error[E0282]: type annotations needed
           ^^^^^^^^^^^^^^^ consider giving `total_employees` a type
    */
    let total_employees = employee.count().get_result(&connection).expect("Error");
    println!("{}", total_employees);


    //-----------------------------------------------
     //get all names
    /*
        Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not satisfied
         ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let all_names = employee.select(name).load::<String>(&connection)?;
    println!("{}", all_names);


    //----------------------------------------------
    //order name
    /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not          satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let ordered_names = employee
        .select(name)
        .order(name.desc())
        .load::<String>(&connection)?;
    println!("{}", ordered_names);


   //------------------------------------------------
   /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not     satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
     */
    let limited = employee
        .select(name)
        .order(employee_id)
        .limit(1)
        .load::<String>(&connection)?;
    println!("{}", limited);
}

Я что-то упускаю ? Кто-нибудь может меня поправить?
Спасибо!


person Glenn singh    schedule 05.12.2020    source источник


Ответы (2)


Прежде всего: в вашем коде отсутствует важная информация для фактического воспроизведения описанных здесь проблем. Не зная схемы вашей базовой базы данных, можно только догадываться, как это выглядело. В качестве ответа я приму следующую схему:

table! {
    employee(employee_id) {
        employee_id -> Integer,
        name -> Nullable<Text>,
        age -> Nullable<Integer>,
        address -> Nullable<Text>,
        email -> Nullable<Text>,
        dept_id -> Integer,
        salary -> Nullable<Numeric>,
        created_on -> Nullable<Timestamp>,
        created_by -> Nullable<Text>,
        modified_on -> Nullable<Timestamp>,
        modified_by -> Nullable<Text>,
        is_active -> Nullable<Bool>,
    }
}

Теперь в качестве общего правила: Diesel использует это определение как источник истины и поддерживает только определенные сопоставления типов. Если вы столкнулись с ошибкой компиляции, это, вероятно, означает, что одна из следующих вещей неверна:

  • Вы пытались сопоставить результат запроса со структурой, содержащей несовместимые поля для какого-то возвращенного столбца.
  • Вы пытались сопоставить результат запроса со структурой, содержащей больше или меньше полей, чем возвращено вашим запросом

Чтобы ответить на ваши конкретные сообщения об ошибках:

    //----------------------------------------------
    //get employees count
    /*
    Error: error[E0282]: type annotations needed
           ^^^^^^^^^^^^^^^ consider giving `total_employees` a type
    */
    let total_employees = employee.count().get_result(&connection).expect("Error");
    println!("{}", total_employees);

Rustc должен знать тип total_employees здесь, поскольку get_result возвращает общий тип, а println, с другой стороны, использует общий тип. Rustc необходимо точно знать, какой тип там следует использовать. Документация по дизельному топливу здесь немного скудна относительно правильного типа возврата, но сообщение об ошибке в Daniel Porteous указывает, что этот запрос возвращает BigInt, который совместим с i64, как описано в здесь. Это означает, что этот запрос будет работать:

    let total_employees: i64 = employee.count().get_result(&connection).expect("Error");

Следующие три запроса не могут быть скомпилированы по существу с тем же сообщением об ошибке:


    //-----------------------------------------------
     //get all names
    /*
        Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not satisfied
         ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let all_names = employee.select(name).load::<String>(&connection)?;
    println!("{}", all_names);


    //----------------------------------------------
    //order name
    /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not          satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let ordered_names = employee
        .select(name)
        .order(name.desc())
        .load::<String>(&connection)?;
    println!("{}", ordered_names);


   //------------------------------------------------
   /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not     satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
     */
    let limited = employee
        .select(name)
        .order(employee_id)
        .limit(1)
        .load::<String>(&connection)?;
    println!("{}", limited);

Теперь это сообщение об ошибке указывает на то, что вы пытаетесь сопоставить поле, возвращаемое запросом, с несовместимым типом на стороне ржавчины. В этом случае сопоставление поля Text, которое не является NOT NULL, с String не поддерживается, потому что в этом случае дизель будет представлять значение NULL. В документации говорится, что вам необходимо обернуть типы, допускающие значение NULL. в Option на стороне ржавчины. Это означает, что если вы измените тип возвращаемого значения на Option<String>, во всех случаях все будет успешно скомпилировано.

person weiznich    schedule 07.12.2020
comment
Вы все правильно поняли. Моя схема такая же, как вы упомянули выше. Я также редактировал вопрос, и теперь у него есть schema.rs. Извини, что пропустил. - person Glenn singh; 07.12.2020
comment
Смена типа возврата !!! Вы хотели сказать, что другие мои запросы должны быть такими: let all_names: Option ‹String› = employee.select (name) .load :: ‹String› (& connection) ?; и это для limit: let limited: Option ‹String› = employee .select (name) .order (employee_id) .limit (1) .load :: ‹String› (& connection) ?; Ты об этом говоришь? - person Glenn singh; 07.12.2020
comment
Под изменением типа возвращаемого значения я подразумеваю изменение типа, возвращаемого этими запросами. Вы уже установили их с помощью синтаксиса turbofish на .load, поэтому просто измените .load::<String>(&connection)? на .load::<Option<String>>(&connection)?. - person weiznich; 08.12.2020
comment
Объяснение проблемы было очень полезным, спасибо @weiznich - person Tolumide; 23.03.2021

let total_employees = employee.count().get_result(&connection).expect("Error");

Для этого попробуйте аннотировать total_employees, например:

let total_employees: u64 = employee.count().get_result(&connection).expect("Error");

Это поможет вам продолжить. Даже если функция не возвращает такой тип, ошибка теперь по крайней мере скажет вам, какой это тип.

person Daniel Porteous    schedule 05.12.2020
comment
Я заметил, что для загрузки ваших сотрудников вы используете турбореактивную рыбу, например .load::<Employee>(). Вам это тоже нужно для count()? - person Daniel Porteous; 05.12.2020
comment
Это не работает. Я все еще получаю сообщение об ошибке ^^^^^^^^^^ черта FromSql<diesel::sql_types::BigInt, Pg> не реализована для u64 - person Glenn singh; 06.12.2020
comment
Этот ответ вводит в заблуждение, поскольку u64 не является типом, поддерживаемым дизельным двигателем (как сообщает сообщение об ошибке) - person weiznich; 07.12.2020
comment
Ответ помогает, потому что теперь задающий вопрос знает, что им нужно использовать BigInt. Общий совет заключался в том, чтобы добавить аннотацию типа, чтобы компилятор сообщал вам, с каким типом вы работаете. - person Daniel Porteous; 07.12.2020