From 73137b82ce1d274acb825c76c8e4f99c62826cb4 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Tue, 24 Jan 2023 20:19:38 +0100
Subject: [PATCH] RUST: Separate connexion and queue + add todo functions +
 update visibilities

---
 .../liblektor-rs/lektor_db/src/connexion.rs   | 64 +++----------
 src/rust/liblektor-rs/lektor_db/src/lib.rs    |  7 +-
 src/rust/liblektor-rs/lektor_db/src/models.rs | 24 +++--
 src/rust/liblektor-rs/lektor_db/src/queue.rs  | 93 ++++++++++++++-----
 4 files changed, 103 insertions(+), 85 deletions(-)

diff --git a/src/rust/liblektor-rs/lektor_db/src/connexion.rs b/src/rust/liblektor-rs/lektor_db/src/connexion.rs
index eb4da471..ee7ec977 100644
--- a/src/rust/liblektor-rs/lektor_db/src/connexion.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/connexion.rs
@@ -1,8 +1,4 @@
-use crate::{
-    models::*,
-    queue::{LktDatabasePriority, LktDatabaseQueueRangeIter},
-    *,
-};
+use crate::{models::*, *};
 use kurisu_api::v1 as api_v1;
 use lektor_c_compat::rs::LktCUri;
 
@@ -19,7 +15,6 @@ fn establish_connection(path: impl AsRef<str>) -> Result<SqliteConnection, Strin
 
 pub struct LktDatabaseConnection {
     sqlite: SqliteConnection,
-    queue: queue::LktDatabaseQueue,
 }
 
 /// Get the value of a [LktCUri] and returns Err(String) in case of invalid
@@ -86,10 +81,7 @@ impl LktDatabaseConnection {
         })?;
         let sqlite =
             establish_connection(path.to_string_lossy()).map_err(LktDatabaseError::String)?;
-        Ok(Self {
-            sqlite,
-            queue: Default::default(),
-        })
+        Ok(Self { sqlite })
     }
 
     /// Get a tag id by its name. If the tag doesn't exists, create it.
@@ -152,10 +144,7 @@ impl LktDatabaseConnection {
 
     /// Ensure that a given language is present in the database. If it's not
     /// insert it. Existence test is done on the code of the language.
-    pub fn ensure_languages_exist<'a>(
-        &mut self,
-        langs: &[NewLanguage<'a>],
-    ) -> LktDatabaseResult<()> {
+    fn ensure_languages_exist<'a>(&mut self, langs: &[NewLanguage<'a>]) -> LktDatabaseResult<()> {
         self.sqlite.exclusive_transaction(|c| {
             for lang in langs {
                 with_dsl!(iso_639_1 => match iso_639_1.filter(code.eq(lang.code)).count().get_result(c)? {
@@ -168,6 +157,18 @@ impl LktDatabaseConnection {
         })
     }
 
+    /// Add a kara to the history.
+    pub fn add_to_history(&mut self, kara: i64) -> LktDatabaseResult<()> {
+        self.sqlite.exclusive_transaction(|conn| {
+            with_dsl!(history => {
+                let epok = history.select(max(epoch)).first::<Option<i64>>(conn)?.unwrap_or_default() + 1;
+                diesel::delete(history.filter(id.is(kara))).execute(conn)?;
+                diesel::insert_into(history).values(HistoryRecord { kara_id: kara, epoch: epok }).execute(conn)?;
+                Ok(())
+            })
+        })
+    }
+
     /// Add a kara with a request.
     pub fn add_kara_from_request(&mut self, kara: NewKaraRequest) -> LktDatabaseResult<()> {
         let (id, new_kara, karamakers, langs, tags) = kara;
@@ -222,41 +223,6 @@ impl LktDatabaseConnection {
         Ok((id, kara, kara_maker, vec![lang], tags))
     }
 
-    /// Peek the next kara to play
-    pub fn peek_next_kara_in_queue(&self) -> Option<i64> {
-        self.queue.peek_next().copied()
-    }
-
-    /// Pop the next kara to play
-    pub fn pop_next_kara_in_queue(&mut self) -> Option<i64> {
-        self.queue.pop_next()
-    }
-
-    /// Get the content of the queue from a range.
-    pub fn get_queue_content(&self, range: Range<usize>) -> LktDatabaseQueueRangeIter {
-        self.queue.range(range)
-    }
-
-    /// Add a kara at the end of the queue.
-    pub fn enqueue_kara(&mut self, local_id: i64) {
-        self.queue.enqueue_kara(local_id)
-    }
-
-    /// Add a kara at the end of a priority in the queue.
-    pub fn enqueue_kara_with_priority(&mut self, local_id: i64, priority: LktDatabasePriority) {
-        self.queue.enqueue_kara_with_priority(local_id, priority)
-    }
-
-    /// Add a kara at the top of the queue.
-    pub fn insert_kara(&mut self, local_id: i64) {
-        self.queue.insert_kara(local_id)
-    }
-
-    /// Add a kara at the top of a priority in the queue.
-    pub fn insert_kara_with_priority(&mut self, local_id: i64, priority: LktDatabasePriority) {
-        self.queue.insert_kara_with_priority(local_id, priority)
-    }
-
     /// Search the queue by URIs. We return the local ids.
     pub fn queue_search(&mut self, _uri: LktCUri) -> Result<Vec<i64>, String> {
         todo!()
diff --git a/src/rust/liblektor-rs/lektor_db/src/lib.rs b/src/rust/liblektor-rs/lektor_db/src/lib.rs
index b29f7c4f..9767296a 100644
--- a/src/rust/liblektor-rs/lektor_db/src/lib.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/lib.rs
@@ -4,16 +4,17 @@
 
 pub mod connexion;
 pub mod error;
-pub mod models;
 pub mod queue;
-pub mod schema;
+
+pub(self) mod models;
+pub(self) mod schema;
 
 pub(self) use diesel::prelude::*;
 pub(self) use error::*;
 pub(self) use std::{collections::VecDeque, ops::Range, path::Path};
 
 /// All the information needed to add a kara recieved from a repo!
-pub type NewKaraRequest<'a> = (
+pub(self) type NewKaraRequest<'a> = (
     models::KaraId,
     models::NewKara<'a>,
     Vec<models::NewKaraMaker<'a>>,
diff --git a/src/rust/liblektor-rs/lektor_db/src/models.rs b/src/rust/liblektor-rs/lektor_db/src/models.rs
index fb58d92f..c4b53052 100644
--- a/src/rust/liblektor-rs/lektor_db/src/models.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/models.rs
@@ -4,6 +4,22 @@ use crate::{schema::*, *};
 use diesel::{deserialize::FromSqlRow, expression::AsExpression, sql_types};
 use kurisu_api::v1 as api_v1;
 
+#[derive(Debug, Insertable, Queryable, Selectable)]
+#[diesel(table_name = repo_kara)]
+pub struct KaraId {
+    pub repo_id: i64,
+    pub repo_kara_id: i64,
+    pub local_kara_id: i64,
+}
+
+#[derive(Debug, Insertable, Queryable, Selectable)]
+#[diesel(table_name = history)]
+pub struct HistoryRecord {
+    #[diesel(column_name = "id")]
+    pub kara_id: i64,
+    pub epoch: i64,
+}
+
 // First the insertable things
 
 #[derive(Insertable)]
@@ -13,14 +29,6 @@ pub struct NewRepo<'a> {
     pub name: &'a str,
 }
 
-#[derive(Debug, Insertable, Queryable, Selectable)]
-#[diesel(table_name = repo_kara)]
-pub struct KaraId {
-    pub repo_id: i64,
-    pub repo_kara_id: i64,
-    pub local_kara_id: i64,
-}
-
 #[derive(Debug, Insertable)]
 #[diesel(table_name = kara)]
 pub struct NewKara<'a> {
diff --git a/src/rust/liblektor-rs/lektor_db/src/queue.rs b/src/rust/liblektor-rs/lektor_db/src/queue.rs
index 54e3f143..558dc3bd 100644
--- a/src/rust/liblektor-rs/lektor_db/src/queue.rs
+++ b/src/rust/liblektor-rs/lektor_db/src/queue.rs
@@ -5,6 +5,7 @@ use super::*;
 const LKT_DATABASE_QUEUES_COUNT: usize = 5;
 
 /// A type to describe a priority.
+#[derive(Debug, Default)]
 pub struct LktDatabasePriority {
     /// The actual priority. Alaways between `0` and
     /// [LKT_DATABASE_QUEUES_COUNT], both included.
@@ -21,6 +22,11 @@ macro_rules! impl_from_for_proprity {
             }
         }
     };
+
+    ($ty: ty, $($tys: ty),+) => {
+        impl_from_for_proprity!($ty);
+        impl_from_for_proprity!($($tys),+);
+    }
 }
 
 macro_rules! impl_into_for_priority {
@@ -31,19 +37,15 @@ macro_rules! impl_into_for_priority {
             }
         }
     };
-}
-
-impl_from_for_proprity!(u8);
-impl_from_for_proprity!(u16);
-impl_from_for_proprity!(u32);
-impl_from_for_proprity!(u64);
 
-impl_from_for_proprity!(i8);
-impl_from_for_proprity!(i16);
-impl_from_for_proprity!(i32);
-impl_from_for_proprity!(i64);
+    ($ty: ty, $($tys: ty),+) => {
+        impl_into_for_priority!($ty);
+        impl_into_for_priority!($($tys),+);
+    }
+}
 
-impl_into_for_priority!(usize);
+impl_from_for_proprity!(u8, u16, u32, u64, i8, i16, i32, i64);
+impl_into_for_priority!(usize, isize);
 
 /// The iterator for the database queue. The iterator returns references to
 /// karas' id to protect modifications while a reference to some karas are
@@ -63,12 +65,12 @@ pub struct LktDatabaseQueueRangeIter<'a> {
 }
 
 impl<'a> Iterator for LktDatabaseQueueIter<'a> {
-    type Item = &'a i64;
+    type Item = i64;
 
     fn next(&mut self) -> Option<Self::Item> {
         let priority = self.priority?.clamp(0, LKT_DATABASE_QUEUES_COUNT - 1);
         let level = &self.queue.levels[priority];
-        match level.get(self.index) {
+        match level.get(self.index).copied() {
             Some(ret) => {
                 self.index += 1;
                 Some(ret)
@@ -83,7 +85,7 @@ impl<'a> Iterator for LktDatabaseQueueIter<'a> {
 }
 
 impl<'a> Iterator for LktDatabaseQueueRangeIter<'a> {
-    type Item = &'a i64;
+    type Item = i64;
 
     fn next(&mut self) -> Option<Self::Item> {
         let new_remaining = self.remaining.saturating_sub(1);
@@ -100,27 +102,32 @@ impl<'a> Iterator for LktDatabaseQueueRangeIter<'a> {
 #[derive(Debug, Default)]
 pub struct LktDatabaseQueue {
     levels: [VecDeque<i64>; LKT_DATABASE_QUEUES_COUNT],
+    current: Option<i64>,
 }
 
 impl LktDatabaseQueue {
-    pub fn enqueue_kara(&mut self, local_id: i64) {
-        self.levels[0].push_back(local_id);
+    /// Get the current kara in the queue.
+    pub fn current_kara(&self) -> Option<i64> {
+        self.current
     }
 
-    pub fn enqueue_kara_with_priority(&mut self, local_id: i64, priority: LktDatabasePriority) {
+    /// Add a kara in the queue with a given priority.
+    pub fn add_kara(&mut self, local_id: i64, priority: LktDatabasePriority) {
         let priority: usize = priority.into();
         self.levels[priority].push_back(local_id);
     }
 
-    pub fn insert_kara(&mut self, local_id: i64) {
-        self.levels[LKT_DATABASE_QUEUES_COUNT - 1].push_front(local_id);
-    }
-
-    pub fn insert_kara_with_priority(&mut self, local_id: i64, priority: LktDatabasePriority) {
+    /// Add all karas in the queue with a given priority in the passed order.
+    pub fn add_kara_all<I: IntoIterator<Item = i64>>(
+        &mut self,
+        local_ids: I,
+        priority: LktDatabasePriority,
+    ) {
         let priority: usize = priority.into();
-        self.levels[priority].push_front(local_id);
+        self.levels[priority].extend(local_ids.into_iter());
     }
 
+    /// Iterate over the queue content.
     pub fn iter(&self) -> LktDatabaseQueueIter {
         let priority = self
             .levels
@@ -135,19 +142,25 @@ impl LktDatabaseQueue {
         }
     }
 
-    pub fn peek_next(&self) -> Option<&i64> {
+    /// Peek the next kara to play in the queue.
+    pub fn peek_next(&self) -> Option<i64> {
         self.iter().next()
     }
 
+    /// Pop the next kara from the queue and set the current kara to the
+    /// returned value.
     pub fn pop_next(&mut self) -> Option<i64> {
         let level = self
             .levels
             .iter_mut()
             .rev()
             .find(|content| !content.is_empty())?;
-        level.pop_front()
+        let current = level.pop_front();
+        self.current = current;
+        current
     }
 
+    /// Get a range of karas in queue.
     pub fn range(&self, range: Range<usize>) -> LktDatabaseQueueRangeIter {
         let mut iter = self.iter();
         let remaining = range.end.saturating_sub(range.start);
@@ -161,4 +174,34 @@ impl LktDatabaseQueue {
             remaining,
         }
     }
+
+    /// Swap two karas with their positions. Returns the two karas that were
+    /// swaped, the order is not defined. On error returns what went wrong.
+    pub fn swap(&mut self, _from: usize, _to: usize) -> Result<(i64, i64), String> {
+        todo!()
+    }
+
+    /// Delete all occurencies of a given kara in the queue. Returns the number
+    /// of deleted entries.
+    pub fn delete_all(&mut self, _kara_id: i64) -> usize {
+        todo!()
+    }
+
+    /// Clear the queue, returns the number of delete entries. This also clears
+    /// the current kara if the maximal level is passed. Only clears up to
+    /// (including) the passed level.
+    pub fn clear(&mut self, _up_to: LktDatabasePriority) -> usize {
+        todo!()
+    }
+
+    /// Crop the queue. Only the current kara remains. Returns the number of
+    /// deleted entries.
+    pub fn crop(&mut self) -> usize {
+        todo!()
+    }
+
+    /// Shuffle the queue. Do the shuffle in a per-level way.
+    pub fn shuffle(&mut self) {
+        todo!()
+    }
 }
-- 
GitLab