Describe the bug
A clear and concise description of what the bug is.
I would appreciate any help for the error below
error
error[E0277]: the trait bound `r2d2::PooledConnection<r2d2_mysql::MysqlConnectionManager>: diesel::Connection` is not satisfied
--> src/graphql.rs:36:46
|
36 | .load::<crate::models::Customer>(&executor.context().db_con)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Connection` is not implemented for `r2d2::PooledConnection<r2d2_mysql::MysqlConnectionManager>`
|
= note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<r2d2::PooledConnection<r2d2_mysql::MysqlConnectionManager>, models::Customer>` for `schema::customers::table`
error[E0277]: the trait bound `r2d2::PooledConnection<r2d2_mysql::MysqlConnectionManager>: diesel::Connection` is not satisfied
--> src/graphql.rs:56:52
|
56 | .get_result::<crate::models::Customer>(&executor.context().db_con)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the
To Reproduce
Steps to reproduce the behavior:
(code example preferred)
cargo build --release
[dependencies]
actix-web = "1.0.9"
actix-cors = "0.1.0"
juniper = "0.14.1"
juniper-from-schema = "0.5.1"
juniper-eager-loading = "0.5.0"
r2d2_mysql = "*"
r2d2-diesel = "0.16.0"
mysql = "*"
r2d2 = "*"
src/graphql.rs
use std::convert::From;
use std::sync::Arc;
use actix_web::{web, Error, HttpResponse};
use futures01::future::Future;
use juniper::http::playground::playground_source;
use juniper::{http::GraphQLRequest, Executor, FieldResult};
use juniper_from_schema::graphql_schema_from_file;
use diesel::prelude::*;
use itertools::Itertools;
use crate::{DbCon, DbPool};
graphql_schema_from_file!("src/schema.graphql");
pub struct Context {
db_con: DbCon,
}
impl juniper::Context for Context {}
pub struct Query;
pub struct Mutation;
impl QueryFields for Query {
fn field_customers(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
) -> FieldResult<Vec<Customer>> {
use crate::schema::customers;
customers::table
.load::<crate::models::Customer>(&executor.context().db_con)
.and_then(|customers| Ok(customers.into_iter().map_into().collect()))
.map_err(Into::into)
}
}
impl MutationFields for Mutation {
fn field_create_customer(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
name: String,
email: String,
) -> FieldResult<Customer> {
use crate::schema::customers;
let new_customer = crate::models::NewCustomer { name: &name, email: &email };
diesel::insert_into(customers::table)
.values(&new_customer)
.get_result::<crate::models::Customer>(&executor.context().db_con)
.map(Into::into)
.map_err(Into::into)
}
}
pub struct Customer {
id: u64,
name: String,
email: String,
}
impl CustomerFields for Customer {
fn field_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.id.to_string()))
}
fn field_name(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.name)
}
fn field_email(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.email)
}
}
impl From<crate::models::Customer> for Customer {
fn from(customer: crate::models::Customer) -> Self {
Self {
id: customer.id,
name: customer.name,
email: customer.email,
}
}
}
fn playground() -> HttpResponse {
let html = playground_source("");
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html)
}
fn graphql(
schema: web::Data<Arc<Schema>>,
data: web::Json<GraphQLRequest>,
db_pool: web::Data<DbPool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
let ctx = Context {
db_con: db_pool.get().unwrap(),
};
web::block(move || {
let res = data.execute(&schema, &ctx);
Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?)
})
.map_err(Error::from)
.and_then(|customer| {
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(customer))
})
}
pub fn register(config: &mut web::ServiceConfig) {
let schema = std::sync::Arc::new(Schema::new(Query, Mutation));
config
.data(schema)
.route("/", web::post().to_async(graphql))
.route("/", web::get().to(playground));
}
src/main.rs
#[macro_use]
extern crate diesel;
extern crate r2d2;
use actix_cors::Cors;
use actix_web::{web, App, HttpServer};
use r2d2_mysql::mysql::{Opts, OptsBuilder};
use r2d2_mysql::MysqlConnectionManager;
use diesel::{
prelude::*,
};
pub mod graphql;
pub mod models;
pub mod schema;
pub type DbPool = r2d2::Pool<MysqlConnectionManager>;
pub type DbCon = r2d2::PooledConnection<MysqlConnectionManager>;
fn main() {
let db_pool = create_db_pool();
let port: u16 = std::env::var("PORT")
.ok()
.and_then(|p| p.parse().ok())
.unwrap_or(8080);
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));
HttpServer::new(move || {
App::new()
.data(db_pool.clone())
.wrap(Cors::new())
.configure(graphql::register)
.default_service(web::to(|| "404"))
})
.bind(addr)
.unwrap()
.run()
.unwrap();
}
pub fn create_db_pool() -> DbPool {
let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let opts = Opts::from_url(&db_url).unwrap();
let builder = OptsBuilder::from_opts(opts);
let manager = MysqlConnectionManager::new(builder);
r2d2::Pool::new(manager).expect("Failed to create DB Pool")
}
Expected behavior
A clear and concise description of what you expected to happen.
I need to connect to the mysql with juniper without the error above
Additional context
Add any other context about the problem here.
What does your schema.graphql file look like?
@davidpdrsn
thanks for your help!
schema.graphql
schema {
query: Query
mutation: Mutation
}
type Query {
customers: [Customer!]! @juniper(ownership: "owned")
}
type Mutation {
createCustomer(
name: String!,
email: String!,
): Customer! @juniper(ownership: "owned")
}
type Customer {
id: ID! @juniper(ownership: "owned")
name: String!
email: String!
}
Thanks! I'll look into it.
This isn't a juniper issue.
Having looked into the code I'm a bit confused. Do you want to use the diesel crate to talk with MySQL or the mysql crate? From looking at your dependencies it seems like you're going with mysql but the code is referencing Diesel. Note that r2d2_mysql works with the mysql crate _not_ with diesel. For that you have to use diesel's r2d2 feature flag. Is that intentional?
Anyways if you're going with Diesel this works:
In Cargo.toml:
[dependencies]
actix-web = "1.0.9"
actix-cors = "0.1.0"
juniper = "0.14.1"
juniper-from-schema = "0.5.1"
juniper-eager-loading = "0.5.0"
r2d2 = "*"
diesel = { version = "1", features = ["mysql", "r2d2"] }
In main.rs
use diesel::r2d2::ConnectionManager;
pub type DbPool = r2d2::Pool<ConnectionManager<MysqlConnection>>;
pub type DbCon = r2d2::PooledConnection<ConnectionManager<MysqlConnection>>;
In graphql.rs
let models =
customers::table.load::<crate::models::Customer>(&executor.context().db_con)?;
You didn't quite provide all your code (schema.rs and models.rs are missing) but applying those changes should fix the immediate error you're getting.
Hope this helps 馃槉
I'm gonna close the issue since it isn't juniper related. Feel free to comment if you have more questions.
@davidpdrsn
appreciation for your great support, and it solved the error with DbPool and DbCon.
thanks again.
However, when I Implement MutationField for graphQl mutation, the return requires FieldResult
are there some solutions to integrate diesel with juniper for mysql insertion ?
code
impl MutationFields for Mutation {
fn field_create_customer(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
name: String,
email: String,
) -> FieldResult<Customer> {
let new_customer = crate::models::NewCustomer { name: name, email: email };
let test = diesel::insert_into(customers::table)
.values(&new_customer)
.execute(&executor.context().db_con)? // <- it only returns usize. but in posgres, it get_result returns vector...
.map(Into::into)
.map_err(Into::into)
diesel's api doc
in posgres
fn get_results<U>(self, conn: &Conn) -> QueryResult<Vec<U>>
in mysql
fn execute(self, conn: &Conn) -> QueryResult<usize> // I want Vec here
I don't have much experience with MySQL but postgres supports a returning clause on insert, update, and delete. Diesel also has APIs for that https://docs.rs/diesel/1.4.5/diesel/query_builder/struct.InsertStatement.html#method.returning.
If that isn't supported by MySQL you'll have to somehow get out the id of the new row and run a regular select statement to get the remaining data I guess.
If you have more questions regarding Diesel I think going to stack overflow will give better answers.
@davidpdrsn
I asked the diesel community, and i got to know that I need to do a separate query, selecting the newly inserted data as you also mentioned.
thanks for your support !