thedodd / wither

An ODM for MongoDB built on the official MongoDB Rust driver.
https://docs.rs/wither
Other
328 stars 40 forks source link

Code fails while deserializing DateTime data type. #56

Closed amber-m-o-r-e closed 4 years ago

amber-m-o-r-e commented 4 years ago

I have the following code-

use futures::stream::StreamExt;
use serde::{Serialize, Deserialize};
use wither::{prelude::*, Result};
use wither::bson::{doc, oid::ObjectId};
use wither::mongodb::Client;
use chrono::{DateTime, Duration, Utc};
use uuid::Uuid;

#[derive(Debug, Model, Serialize, Deserialize)]
#[model(index(keys=r#"doc!{"uid": 1}"#, options=r#"doc!{"unique": true}"#))]
struct ToDo {
    /// The ID of the model.
    #[serde(rename="_id", skip_serializing_if="Option::is_none")]
    pub id: Option<ObjectId>,
    /// The to_do's email address.
    pub uid: String,
    pub task: String,
    pub completed: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub deleted_at: DateTime<Utc>
}

#[tokio::main]
async fn main() -> Result<()> {
    // Connect & sync indexes.
    let db = Client::with_uri_str("mongodb://localhost:27017/").await?.database("mydb");
    //User::sync(db.clone()).await?;

    // Create a user.
    let mut me = ToDo {
        id: None, uid: Uuid::new_v4().to_string(),
        task: String::from("Task 1"), completed: false, 
        created_at: Utc::now(), updated_at: Utc::now(),
        deleted_at: Utc::now()
    };
    me.save(db.clone(), None).await?;

    // Update user's email address.
    me.update(db.clone(), None, doc!{"$set": doc!{"task": "New task1", "updated_at": Utc::now()}}, None).await?;

    // Fetch all users.
    let mut cursor = ToDo::find(db.clone(), None, None).await?;
    while let Some(to_do) = cursor.next().await {
        println!("{:?}", to_do);
    }
    Ok(())
}

toml-

[dependencies]
chrono = { version = "0.4", features = ["serde"] }
futures = "0.3.5"
global = "0.4.3"
serde = "1.0.114"
serde_derive = "1.0.114"
wither = { version = "0.9.0-alpha.1", default-features = false, features = ["async-std-runtime"] }
#tokio = { version = "0.2.21", features = ["full"] }
tokio = { version = "0.2.21", features = ["macros"] }
uuid = { version = "0.8", features = ["serde", "v4"] }

This code fails at ToDo::find and gives runtime error-

Err(BsonDe(DeserializationError { message: "invalid type: map, expected a formatted date and time string or a unix timestamp" }))

While inserting record it stores datetime value in string format in Mongo, but at update it saves update_at in perfect datetime in Mongo. But then while fetching it breaks, If you will not pass updated_at while updating record it works well without an error. If deleted_at will make it as optional as "pub deleted_at: Option\<DateTime\>" and pass None while inserting record then also at retrieve code fails with the same error.

Err(BsonDe(DeserializationError { message: "invalid type: map, expected a formatted date and time string or a unix timestamp" }))

Expected is to store perfectly DateTime marked data in datetime format at insertion as well as at update in Mongo. And If None is provided for optional then the program should tackle without failing while retrieving records.

Value of datetime in mongo while inserting is "2020-07-05T11:39:39.352802472Z" and after the update is ISODate("2020-07-05T11:39:39.360Z").

thedodd commented 4 years ago

@amber-m-o-r-e this appears to be an issue with the bson lib, as wither doesn't do anything with bson other than call its public interfaces and such.

I would recommend opening an issue in the bson repo. Feel free to reference back to this issue as well, of course. Sounds like you've got a pretty solid repo pattern, and you probably don't even need a database involved. You could setup a reproduction test case with the same struct you are using here, and then do some serialization / deserialization on the struct, then compare it against the output of the macro.

Keep me posted. Happy to help.

amber-m-o-r-e commented 4 years ago

Hi thedodd,

Can you open a ticket as your self? as you are the owner of this repo and you can explain this problem properly in a ticket to bson guys.

thedodd commented 4 years ago

@amber-m-o-r-e looks like someone beat you to it. Here is an issue in the bson crate describing the same problem: https://github.com/mongodb/bson-rust/issues/121

thedodd commented 4 years ago

@amber-m-o-r-e given that this is a known issue originating from outside of this project, I'm going to close this issue. Let me know if you still need help resolving the issue.