Utilisation de diesel

Nouvelles dépendances

Dans lib.rs

#[macro_use]
extern crate diesel;
extern crate r2d2;

use diesel::prelude::*;
use diesel::r2d2::ConnectionManager;

Migrations et schémas

Dans lib.rs

mod schema;

Ajout d'attributs au model

Dans model.rs

use super::schema::reviews;

#[derive(Serialize, Debug, Queryable, Insertable)]
#[table_name = "reviews"]
pub struct Review {
    pub product_id: i32,
    pub reviewer: String,
    pub review: String,
}

Configurer le pool de connection

Dans lib.rs, à la place de l'assignation à db_addr:

let manager = ConnectionManager::<SqliteConnection>::new(CONFIG.database_url.clone());
let pool = r2d2::Pool::builder().build(manager).expect("Failed to create pool.");
let db_addr = SyncArbiter::start(3, move || db::DbExecutor(pool.clone()));

Acteur db db.rs

Importer les nouvelles dépendances

use diesel;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool};

use schema;

Ajouter le pool de connection

Changer la définition de DbExecutor par:

pub struct DbExecutor(pub Pool<ConnectionManager<SqliteConnection>>);

Récupérer les reviews

Changer le message GetReviews par:

#[derive(Debug)]
pub struct GetReviews {
    pub product_id: i32,
}

impl Message for GetReviews {
    type Result = Result<Vec<models::Review>, diesel::result::Error>;
}

impl Handler<GetReviews> for DbExecutor {
    type Result = Result<Vec<models::Review>, diesel::result::Error>;

    fn handle(&mut self, msg: GetReviews, _: &mut Self::Context) -> Self::Result {
        warn!("getting reviews for product {}", msg.product_id);

        use self::schema::reviews::dsl::*;

        let conn: &SqliteConnection = &self.0.get().unwrap();

        let items = reviews
            .filter(product_id.eq(msg.product_id))
            .load::<models::Review>(conn)?;

        Ok(items)
    }
}

Sauvegarder une review

Changer le message SaveReview par:

#[derive(Debug)]
pub struct SaveReview {
    pub review: models::Review,
}

impl Message for SaveReview {
    type Result = Result<models::Review, diesel::result::Error>;
}

impl Handler<SaveReview> for DbExecutor {
    type Result = Result<models::Review, diesel::result::Error>;

    fn handle(&mut self, msg: SaveReview, _: &mut Self::Context) -> Self::Result {
        warn!("saving review {:?}", msg.review);

        use self::schema::reviews::dsl::*;

        let conn: &SqliteConnection = &self.0.get().unwrap();

        diesel::insert_into(reviews)
            .values(&msg.review)
            .execute(conn)?;

        Ok(msg.review)
    }
}

Résultat

On récupère les reviews de la base de données:

curl localhost:9081/reviews/0
{
   "reviews" : [
      {
         "text" : "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!",
         "reviewer" : "Reviewer1"
      },
      {
         "reviewer" : "Reviewer2",
         "text" : "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare."
      }
   ],
   "id" : 0
}

Les avis envoyés sont sauvegardés:

curl localhost:9081/reviews/1 -H 'Content-Type: application/json' -d '{"reviewer":"moi","rating":3,"text":"mon avis"}'
{"reviewer":"moi","text":"mon avis","rating":3}

curl localhost:9081/reviews/1
{
   "id" : 1,
   "reviews" : [
      {
         "text" : "mon avis",
         "reviewer" : "moi"
      }
   ]
}