Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error[E0277]: the trait bound *const str: diesel::deserialize::FromSql<diesel::sql_types::Array<diesel::sql_types::Text>, diesel::pg::Pg> is not satisfied #2434

Closed
2 tasks done
jaredforth opened this issue Jun 12, 2020 · 2 comments

Comments

@jaredforth
Copy link

jaredforth commented Jun 12, 2020

Setup

Versions

  • Rust:
    Running rustup show gives:
active toolchain
----------------

stable-x86_64-unknown-linux-gnu (default)
rustc 1.41.1 (f3e1a954d 2020-02-24)
  • Diesel: 1.4.3
  • Database: PostgreSQL 12.2
  • Operating System: Ubuntu 18.04 (Windows Subsystem for Linux)

Feature Flags

  • diesel: { version = "1.4.3", features = ["postgres"] }

Problem Description

What are you trying to accomplish?

I am trying to call the load() function to return a Vec of a struct that implements Queryable.

Instead of compiling, running cargo build gives me error[E0277]: the trait bound *const str: diesel::deserialize::FromSql<diesel::sql_types::Arraydiesel::sql_types::Text, diesel::pg::Pg> is not satisfied.

There are two issues that have described similar problems to mine, but neither are quite the same.

The first is #330, and the issue was simply that the user was trying to use a Nullable<Integer> SQL value with a model that had an i32 type instead of an Option<i32>.

The second is #2011, with the issue being that the struct in models.rs had a different order than the table! macro in schema.rs.

Neither of these solutions apply to my problem, which is why I suspect it might be a bug.

Steps to reproduce

The load() function is called with the following code:

use actix::{Message, Handler};
use std::io;
use crate::models;
use crate::db::DbExecutor;

use diesel::prelude::*;

pub struct Webpages;

impl Message for Webpages {
    type Result = io::Result<Vec<models::Webpage>>;
}

impl Handler<Webpages> for DbExecutor {
    type Result = io::Result<Vec<models::Webpage>>;

    fn handle(&mut self, _: Webpages, _: &mut Self::Context) -> Self::Result {
        use crate::schema::webpage::dsl::*;

        let w = match webpage.load::<models::Webpage>(&self.conn) {
            Ok(items) => items,
            Err(_) => {
                return Err(io::Error::new(io::ErrorKind::Other, "Database error"));
            }
        };

        Ok(w)
    }
}

The DbExecutor is just a connection to Postgres, but I am including it here:

/// Database [SyncArbiter](https://actix.rs/book/actix/sec-6-sync-arbiter.html)
/// with a connection field to Postgres
pub struct DbExecutor {
    conn: PgConnection
}

/// Create Sync Actor
impl Actor for DbExecutor {
    type Context = SyncContext<Self>;
}

/// Implement new `DbExecutor` with a live Postgres connection
impl DbExecutor {
    pub fn new(db_url: &str) -> DbExecutor {
        let conn = PgConnection::establish(db_url)
            .expect(&format!("Error connecting to {}", db_url));
        // Run database migrations
        diesel_migrations::run_pending_migrations(&conn).unwrap();
        DbExecutor {
            conn
        }
    }
}

My Webpage model in models.rs is as follows:

#[allow(non_snake_case)]
#[belongs_to(Website)]
#[derive(Serialize, Queryable, Debug, Associations, Identifiable)]
#[table_name="webpage"]
pub struct Webpage {
    pub id: i32,
    website_id: i32,
    scraped_data_ids: Vec<i32>,
    url: Option<String>,
    title: Option<String>,
    meta: Option<String>,
    canonical: Option<String>,
    h1s: Option<Vec<String>>,
    h2s: Option<Vec<String>>,
    h3s: Option<Vec<String>>,
    h4s: Option<Vec<String>>,
    h5s: Option<Vec<String>>,
    h6s: Option<Vec<String>>,
    ps: Option<Vec<String>>,
    images: Option<String>,
    is_secure: bool
}

My schema.rs webpage table is as follows:

table! {
    webpage (id) {
        id -> Int4,
        website_id -> Int4,
        scraped_data_ids -> Array<Int4>,
        url -> Nullable<Varchar>,
        title -> Nullable<Varchar>,
        meta -> Nullable<Varchar>,
        canonical -> Nullable<Varchar>,
        h1s -> Nullable<Array<Text>>,
        h2s -> Nullable<Array<Text>>,
        h3s -> Nullable<Array<Text>>,
        h4s -> Nullable<Array<Text>>,
        h5s -> Nullable<Array<Text>>,
        h6s -> Nullable<Array<Text>>,
        ps -> Nullable<Array<Text>>,
        images -> Nullable<Array<Text>>,
        is_secure -> Bool,
    }
}

My up.sql for the migration that generated the schema is:

CREATE TABLE webpage (
     id SERIAL PRIMARY KEY,
     website_id INTEGER NOT NULL,
     scraped_data_ids INTEGER[] NOT NULL,
     url VARCHAR,
     title VARCHAR,
     meta VARCHAR,
     canonical VARCHAR,
     h1s TEXT[],
     h2s TEXT[],
     h3s TEXT[],
     h4s TEXT[],
     h5s TEXT[],
     h6s TEXT[],
     ps TEXT[],
     images TEXT[],
     is_secure BOOLEAN NOT NULL DEFAULT 'f'
)

In the code above, the model, schema, and SQL all have the same order, and every value that is not specified as NOT NULL is wrapped in an Option<T>.

Checklist

  • I have already looked over the issue tracker for similar issues.
  • This issue can be reproduced on Rust's stable channel. (Your issue will be
    closed if this is not the case)
@weiznich
Copy link
Member

Your struct implementing Queryable uses a Option<String> as 15. field (images). This type is not compatible with the Nullable<Array<Text>> returned by your query at this position.

@jaredforth
Copy link
Author

@weiznich I literally just noticed that and was about to close this ticket. Sorry for adding noise to the issue triage here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants