Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"expected struct String, found struct schema::my_table::columns::my_column" when trying to insert value with Diesel

I am trying to execute an insert multiple columns using Diesel with PostgreSQL.

This is the insert function to add a new Project -

pub fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
    use schema::projects::dsl::*;
    use schema::projects::dsl::{title as t};
    use schema::projects::dsl::{program_id as prog_id};

    let NewProject {
        title
    } = project;

    diesel::insert_into(projects)
        .values((t.eq(title), prog_id.eq(program_id)))
        .execute(conn)
        .is_ok()
}

And Project and NewProject

#[derive(Queryable, Serialize, Debug, Clone)]
pub struct Project {
    pub id: i32,
    pub title: String,
    pub program_id: i32,
    pub is_archived: bool
}

#[derive(Serialize, Deserialize, Insertable)]
#[table_name = "projects"]
pub struct NewProject {
    pub title: String
}

And the projects table looks like this -

CREATE TABLE projects (
    id SERIAL PRIMARY KEY,
    title VARCHAR NOT NULL,
    program_id INTEGER NOT NULL REFERENCES programs (id),
    is_archived BOOLEAN NOT NULL DEFAULT FALSE
);

and the schema.rs -

table! {
projects (id) {
    id -> Int4,
    title -> Varchar,
    program_id -> Int4,
    is_archived -> Bool,
}

When compiled I get an error saying -

title | ^^^^^ expected struct std::string::String, found struct schema::projects::columns::title

and

.execute(conn) | ^^^^^^^ expected struct diesel::query_source::Never, found struct diesel::query_source::Once

I do not get a compile error when I do

.values(&project)

in the insert function instead.

like image 885
Ramsundar Shandilya Avatar asked Oct 24 '18 20:10

Ramsundar Shandilya


1 Answers

Here is a MCVE of your problem:

#[macro_use]
extern crate diesel;

use diesel::pg::PgConnection;
use diesel::prelude::*;

mod schema {
    table! {
        projects (id) {
            id -> Int4,
            title -> Varchar,
            program_id -> Int4,
            is_archived -> Bool,
        }
    }

    #[derive(Debug, Insertable)]
    #[table_name = "projects"]
    pub struct NewProject {
        pub title: String,
    }
}

use schema::NewProject;

fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
    use schema::projects::dsl::*;
    use schema::projects::dsl::{title as t};
    use schema::projects::dsl::{program_id as prog_id};

    let NewProject {
        title
    } = project;

    diesel::insert_into(projects)
        .values((t.eq(title), prog_id.eq(program_id)))
        .execute(conn)
        .is_ok()
}

fn main() {}

You have imported a type called title that conflicts with the destructuring, as the error message states:

error[E0308]: mismatched types
  --> src/main.rs:34:22
   |
34 |     let NewProject { title } = project;
   |                      ^^^^^ expected struct `std::string::String`, found struct `schema::projects::columns::title`
   |
   = note: expected type `std::string::String`
              found type `schema::projects::columns::title`

This can be reduced to a very small case:

struct foo;
struct Thing { foo: String }

fn example(t: Thing) {
    let Thing { foo } = t;
}
error[E0308]: mismatched types
 --> src/lib.rs:5:17
  |
5 |     let Thing { foo } = t;
  |                 ^^^ expected struct `std::string::String`, found struct `foo`
  |
  = note: expected type `std::string::String`
             found type `foo`

Note that this struct is defined without curly braces, which makes it a unit-like struct. These are convenient, but they have the subtle nuance that they create both a type and a value:

struct foo;

fn example() {
    let foo: foo = foo;
    //             ^-- the only value of the type `foo`
    //       ^-------- the type `foo`
    //  ^------------- newly-defined unrelated identifier
}

When destructuring, the pattern is preferred as a type, not an identifier.

Don't import that type and you won't have a conflict:

fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
    use schema::projects::dsl;

    let NewProject { title } = project;

    diesel::insert_into(dsl::projects)
        .values((dsl::title.eq(title), dsl::program_id.eq(program_id)))
        .execute(conn)
        .is_ok()
}
like image 161
Shepmaster Avatar answered Nov 15 '22 08:11

Shepmaster