[fractal/backend: 5/9] backend: Room and Message relation in database



commit c32af3c4c70eea85917f510d62fcae28a53601c5
Author: Daniel GarcĂ­a Moreno <danigm wadobo com>
Date:   Mon Dec 24 18:04:01 2018 +0100

    backend: Room and Message relation in database

 fractal-backend/src/model/message.rs | 51 ++++++++++++++++++++++++++++++++++--
 fractal-backend/src/model/mod.rs     |  1 +
 fractal-backend/tests/models.rs      | 48 +++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+), 2 deletions(-)
---
diff --git a/fractal-backend/src/model/message.rs b/fractal-backend/src/model/message.rs
index 1ece037e..30a7abd8 100644
--- a/fractal-backend/src/model/message.rs
+++ b/fractal-backend/src/model/message.rs
@@ -50,7 +50,6 @@ impl Model for Message {
     }
 
     fn create_sql() -> String {
-        //TODO: implements relation to room as ForeignKey
         format!(
             "
         CREATE TABLE if not exists {} (
@@ -68,7 +67,9 @@ impl Model for Message {
             receipt TEXT NOT NULL,
             redacted BOOLEAN NOT NULL,
             in_reply_to TEXT,
-            extra_content TEXT
+            extra_content TEXT,
+
+            FOREIGN KEY(room) REFERENCES room(id)
         )
         ",
             Self::table_name()
@@ -151,3 +152,49 @@ impl Model for Message {
         }
     }
 }
+
+pub trait MessageModel: Sized {
+    fn get_range(room: &str, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<Self>, Error>;
+}
+
+impl MessageModel for Message {
+    /// Returns a list of Messages from filtering by `room` roomid ordered by
+    /// date
+    ///
+    /// The param `limit` defines the number of messages to return, if it's
+    /// None, all messages will be returned
+    ///
+    /// The param `offset` is used to ignore that number of messages and start
+    /// to return from that.  if it's None, the return will be done from the end
+    /// of the list.
+    fn get_range(room: &str, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<Self>, Error> {
+        let fields = Self::fields().join(",");
+        let mut query = format!(
+            "SELECT {} FROM {} WHERE room = ? ORDER BY date desc",
+            fields,
+            Self::table_name()
+        );
+
+        if let Some(l) = limit {
+            query = query + &format!(" LIMIT {}", l);
+        }
+
+        if let Some(o) = offset {
+            query = query + &format!(" OFFSET {}", o);
+        }
+
+        conn(
+            move |c| {
+                let mut stmt = c.prepare(&query)?;
+                let iter = stmt.query_map(&[room], Self::map_row)?;
+
+                let array = iter
+                    .filter(|r| r.is_ok())
+                    .map(|r| r.unwrap())
+                    .collect::<Vec<Self>>();
+                Ok(array)
+            },
+            Err(err_msg("Connection not init")),
+        )
+    }
+}
diff --git a/fractal-backend/src/model/mod.rs b/fractal-backend/src/model/mod.rs
index 22ba84a4..2864fd87 100644
--- a/fractal-backend/src/model/mod.rs
+++ b/fractal-backend/src/model/mod.rs
@@ -8,6 +8,7 @@ pub mod message;
 pub mod room;
 
 pub use self::message::Message;
+pub use self::message::MessageModel;
 pub use self::room::Room;
 
 pub trait Model: Sized {
diff --git a/fractal-backend/tests/models.rs b/fractal-backend/tests/models.rs
index faf8c5b4..4289f088 100644
--- a/fractal-backend/tests/models.rs
+++ b/fractal-backend/tests/models.rs
@@ -1,10 +1,14 @@
+extern crate chrono;
 extern crate fractal_backend;
 
 use fractal_backend::init_local as init;
 use fractal_backend::model::Message;
+use fractal_backend::model::MessageModel;
 use fractal_backend::model::Model;
 use fractal_backend::model::Room;
 
+use chrono::prelude::*;
+
 #[test]
 fn room_model() {
     let _ = init("").unwrap();
@@ -59,3 +63,47 @@ fn message_model() {
     let really_deleted = Message::get("MSGID");
     assert!(really_deleted.is_err());
 }
+
+#[test]
+fn message_room_relation() {
+    let _ = init("").unwrap();
+
+    let created = Room::create_table();
+    assert!(created.is_ok());
+    let created = Message::create_table();
+    assert!(created.is_ok());
+
+    let r = Room::new("ROOM ID".to_string(), Some("ROOM NAME".to_string()));
+    let stored = r.store();
+    assert!(stored.is_ok());
+
+    let mut msg = Message::default();
+    msg.room = r.id.clone();
+
+    for i in 0..100 {
+        msg.id = Some(format!("MSG {}", i));
+        msg.date = Local.ymd(1970, 1, 1).and_hms(0, i / 60, i % 60);
+        let _ = msg.store();
+    }
+
+    msg.room = "ROOM ID 2".to_string();
+    for i in 0..100 {
+        msg.id = Some(format!("MSG ROOM2 {}", i));
+        msg.date = Local.ymd(1970, 1, 1).and_hms(0, i / 60, i % 60);
+        let _ = msg.store();
+    }
+
+    for i in 0..10 {
+        let items = Message::get_range(&r.id, Some(10), Some(i * 10)).unwrap();
+        for (j, m) in items.iter().enumerate() {
+            let idx = 99 - (10 * i as usize + j);
+            assert_eq!(m.id, Some(format!("MSG {}", idx)));
+        }
+    }
+
+    let items = Message::get_range(&r.id, Some(10), Some(95)).unwrap();
+    assert_eq!(items.len(), 5);
+
+    let items = Message::get_range(&r.id, Some(10), Some(100)).unwrap();
+    assert_eq!(items.len(), 0);
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]