How to resolve mongodb and juniper conflicting over bson in Rust?

I am using both mongodb and juniper in rust. Both use on the bson crate.
I can either import ObjectId from mongodb, like so:

use mongodb::{bson::{doc, oid::ObjectId}, sync::Client};
use juniper::GraphQLObject;
use serde::{Serialize, Deserialize};

In which case Juniper complains:

error[E0277]: the trait bound `mongodb::bson::oid::ObjectId: GraphQLValueAsync<__S>` is not satisfied
 --> src/main.rs:6:10
  |
6 | #[derive(GraphQLObject)]
  |          ^^^^^^^^^^^^^ the trait `GraphQLValueAsync<__S>` is not implemented for `mongodb::bson::oid::ObjectId`
  |
  = note: required because of the requirements on the impl of `GraphQLValueAsync<__S>` for `&mongodb::bson::oid::ObjectId`
  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

or from bson directly, like so:

use mongodb::{bson::doc, sync::Client};
use bson::oid::ObjectId;
use juniper::GraphQLObject;
use serde::{Serialize, Deserialize};

in which case mongodb complains:

error[E0277]: the trait bound `mongodb::bson::Bson: From<bson::oid::ObjectId>` is not satisfied
  --> src/main.rs:20:42
   |
20 |   let commune = collection.find_one(Some(doc! {"_id": oid}), None).expect("result").expect("option");
   |                                          ^^^^^^^^^^^^^^^^^ the trait `From<bson::oid::ObjectId>` is not implemented for `mongodb::bson::Bson`
   |
   = help: the following implementations were found:
             <mongodb::bson::Bson as From<&T>>
             <mongodb::bson::Bson as From<&[T]>>
             <mongodb::bson::Bson as From<&str>>
             <mongodb::bson::Bson as From<Vec<T>>>
           and 20 others

Here is a minimal example (add the lines of code above in turn).

#[derive(Debug, Serialize, Deserialize)]
#[derive(GraphQLObject)]
pub struct User {
    pub _id: ObjectId,
}

fn main() {
  let uri = "URI";
  let client = Client::with_uri_str(uri).expect("unable to connect");
  let db = client.database("Database");

  let oid = ObjectId::new();

  let collection = db.collection::<User>("users");
  let commune = collection.find_one(Some(doc! {"_id": oid}), None).expect("result").expect("option");
  println!("{:?}", commune)
}

Based on the error I am guessing that I need to impl std::convert::From, but I feel like I am doing something wrong here. What is the better way of resolving this?

The issue here is that the juniper crate depends on the 1.x version of bson whereas the latest driver betas depend on the 2.x version. Since they’re different major versions, cargo essentially treats them as two separate crates.

As a workaround, you can downgrade your driver version to 1.x until the juniper crate is updated to support the newer version of bson. It looks like they have a work in progress pull request right now, though it doesn’t appear ready yet.

Another possible workaround that doesn’t require using the 1.x driver is to implement manual conversions between types from the two versions of bson, as you suggested. This does involve a bit of boilerplate, however.

e.g.

#[derive(Debug, Serialize, Deserialize)]
struct MongoUser {
    _id: mongodb::bson::ObjectId,
}
#[derive(Debug, Serialize, Deserialize, GraphQLObject)]
struct JuniperUser {
    _id: bson::ObjectId,
}
impl From<MongoUser> for JuniperUser {
    fn from(mongo_user: MongoUser) -> Self {
        Self { _id: bson::ObjectId::with_bytes(mongo_user._id.bytes()) }
    }
}

// in main()
let oid = mongodb::bson::ObjectId::new();
let collection = db.collection::<MongoUser>("users");
let commune = collection.find_one(mongodb::bson::doc! { "_id": oid }, None).await?;

Hopefully the juniper crate will be updated soon so these workarounds won’t be necessary.

Please let us know if you have any further questions!

3 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.