moving to generic based models instead of traits

This commit is contained in:
Chris Cochrun 2024-10-08 12:48:07 -05:00
parent 8f065380aa
commit 7a8e6c41cd
4 changed files with 150 additions and 140 deletions

View file

@ -1,11 +1,68 @@
use std::path::PathBuf;
use sqlx::query_as;
use tracing::error;
use crate::model::Model;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Image { pub struct Image {
_title: String, pub title: String,
pub path: PathBuf,
}
impl Model<Image> {
pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let result = query_as!(Image, r#"SELECT title as "title!", filePath as "path!" from images"#).fetch_all(&mut self.db).await;
match result {
Ok(v) => {
for image in v.into_iter() {
let _ = self.add_item(image);
}
}
Err(e) => error!("There was an error in converting songs: {e}"),
}
});
}
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
fn test_image(title: String) -> Image {
Image {
title,
path: PathBuf::from("~/pics/camprules2024.mp4"),
..Default::default()
}
}
#[test] #[test]
pub fn test_image() { pub fn test_db_and_model() {
assert_eq!(true, true) let mut image_model: Model<Image> = Model::default();
image_model.load_from_db();
if let Some(image) = image_model.get_item(3) {
let test_image = test_image("ncca4".into());
assert_eq!(test_image.title, image.title);
} else {
assert!(false);
}
}
#[test]
pub fn test_add_image() {
let image = test_image("A new image".into());
let mut image_model: Model<Image> = Model::default();
let result = image_model.add_item(image.clone());
let new_image = test_image("A newer image".into());
match result {
Ok(_) => {
assert_eq!(&image, image_model.get_item(0).unwrap());
assert_ne!(&new_image, image_model.get_item(0).unwrap());
}
Err(e) => assert!(false, "There was an error adding the image: {:?}", e),
}
} }
} }

View file

@ -1,4 +1,6 @@
use color_eyre::eyre::Result; use std::mem::replace;
use color_eyre::eyre::{eyre, Result};
use sqlx::{Connection, SqliteConnection}; use sqlx::{Connection, SqliteConnection};
#[derive(Debug)] #[derive(Debug)]
@ -6,34 +8,43 @@ pub struct Model<T> {
pub items: Vec<T>, pub items: Vec<T>,
pub db: SqliteConnection, pub db: SqliteConnection,
} }
impl<T> Model<T> {
pub fn add_item(&mut self, item: T) -> Result<()> {
self.items.push(item);
Ok(())
}
// impl<T> Modeling for Model<T> { pub fn add_to_db(&mut self, item: T) -> Result<()> {
// type Item = T; todo!()
// fn add_item(&mut self, item: Self::Item) -> Result<()> { }
// self.items.push(item);
// Ok(())
// }
// fn add_to_db(&mut self, item: Self::Item) -> Result<()> { pub fn update_item(&mut self, item: T, index: i32) -> Result<()> {
// todo!() if let Some(current_item) = self.items.get_mut(index as usize)
// } {
let _old_item = replace(current_item, item);
Ok(())
} else {
Err(eyre!(
"Item doesn't exist in model. Id was {}",
index
))
}
}
// fn update_item(&mut self, item: Self::Item, index: i32) -> Result<()> { pub fn remove_item(&mut self, index: i32) -> Result<()> {
// todo!() self.items.remove(index as usize);
// } Ok(())
}
// fn remove_item(&mut self, index: i32) -> Result<()> { pub fn get_item(&self, index: i32) -> Option<&T> {
// todo!() self.items.get(index as usize)
// } }
// fn get_item(&self, index: i32) -> Option<&Self::Item> { pub fn insert_item(&mut self, item: T, index: i32) -> Result<()> {
// todo!() self.items.insert(index as usize, item);
// } Ok(())
}
// fn insert_item(&mut self, item: Self::Item, index: i32) -> Result<()> { }
// todo!()
// }
// }
impl<T> Default for Model<T> { impl<T> Default for Model<T> {
fn default() -> Self { fn default() -> Self {
@ -72,21 +83,6 @@ pub trait Modeling {
.expect("problems") .expect("problems")
}) })
} }
fn add_item(&mut self, item: Self::Item) -> Result<()>;
fn add_to_db(&mut self, item: Self::Item) -> Result<()>;
fn update_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()>;
fn remove_item(&mut self, index: i32) -> Result<()>;
fn get_item(&self, index: i32) -> Option<&Self::Item>;
fn insert_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()>;
} }
#[cfg(test)] #[cfg(test)]

View file

@ -31,53 +31,6 @@ const VERSE_KEYWORDS: [&'static str; 24] = [
"Other 2", "Other 3", "Other 4", "Other 2", "Other 3", "Other 4",
]; ];
impl Modeling for Model<Song> {
type Item = Song;
fn add_item(&mut self, item: Self::Item) -> Result<()> {
self.items.push(item);
Ok(())
}
fn add_to_db(&mut self, _item: Self::Item) -> Result<()> {
todo!()
}
fn update_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()> {
if let Some(current_song) = self.items.get_mut(index as usize)
{
let _old_song = replace(current_song, item);
Ok(())
} else {
Err(eyre!(
"Song doesn't exist in model. Id was {}",
index
))
}
}
fn get_item(&self, index: i32) -> Option<&Self::Item> {
self.items.get(index as usize)
}
fn remove_item(&mut self, index: i32) -> Result<()> {
self.items.remove(index as usize);
Ok(())
}
fn insert_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()> {
self.items.insert(index as usize, item);
Ok(())
}
}
impl Model<Song> { impl Model<Song> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
// static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; // static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
@ -277,7 +230,7 @@ You saved my soul"
#[test] #[test]
pub fn test_db_and_model() { pub fn test_db_and_model() {
let mut song_model = Model::default(); let mut song_model: Model<Song> = Model::default();
song_model.load_from_db(); song_model.load_from_db();
if let Some(song) = song_model.get_item(3) { if let Some(song) = song_model.get_item(3) {
let test_song = test_song(); let test_song = test_song();
@ -291,7 +244,7 @@ You saved my soul"
pub fn test_update() { pub fn test_update() {
let song = test_song(); let song = test_song();
let cloned_song = song.clone(); let cloned_song = song.clone();
let mut song_model = Model::default(); let mut song_model: Model<Song> = Model::default();
song_model.load_from_db(); song_model.load_from_db();
match song_model.update_item(song, 2) { match song_model.update_item(song, 2) {

View file

@ -2,6 +2,9 @@ use crate::model::Model;
use crate::model::Modeling; use crate::model::Modeling;
use color_eyre::eyre::eyre; use color_eyre::eyre::eyre;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use sqlx::query;
use sqlx::query_as;
use tracing::error;
use std::mem::replace; use std::mem::replace;
use std::path::PathBuf; use std::path::PathBuf;
@ -14,60 +17,61 @@ pub struct Video {
pub looping: bool, pub looping: bool,
} }
impl Model<Video> {} impl Model<Video> {
pub fn load_from_db(&mut self) {
impl Modeling for Model<Video> { let rt = tokio::runtime::Runtime::new().unwrap();
type Item = Video; rt.block_on(async {
let result = query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!" from videos"#).fetch_all(&mut self.db).await;
fn add_item(&mut self, item: Self::Item) -> Result<()> { match result {
self.items.push(item); Ok(v) => {
Ok(()) for video in v.into_iter() {
} let _ = self.add_item(video);
}
fn add_to_db(&mut self, _item: Self::Item) -> Result<()> { }
todo!() Err(e) => error!("There was an error in converting songs: {e}"),
} }
});
fn update_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()> {
if let Some(current_item) = self.items.get_mut(index as usize)
{
let _old_song = replace(current_item, item);
Ok(())
} else {
Err(eyre!(
"Song doesn't exist in model. Id was {}",
index
))
}
}
fn get_item(&self, index: i32) -> Option<&Self::Item> {
self.items.get(index as usize)
}
fn remove_item(&mut self, index: i32) -> Result<()> {
self.items.remove(index as usize);
Ok(())
}
fn insert_item(
&mut self,
item: Self::Item,
index: i32,
) -> Result<()> {
self.items.insert(index as usize, item);
Ok(())
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
fn test_video(title: String) -> Video {
Video {
title,
path: PathBuf::from("~/vids/camprules2024.mp4"),
..Default::default()
}
}
#[test] #[test]
pub fn test_video() { pub fn test_db_and_model() {
assert_eq!(true, true) let mut video_model: Model<Video> = Model::default();
video_model.load_from_db();
if let Some(video) = video_model.get_item(3) {
let test_video = test_video("Getting started with Tokio. The ultimate starter guide to writing async Rust.".into());
assert_eq!(test_video.title, video.title);
} else {
assert!(false);
}
}
#[test]
pub fn test_add_video() {
let video = test_video("A new video".into());
let mut video_model: Model<Video> = Model::default();
let result = video_model.add_item(video.clone());
let new_video = test_video("A newer video".into());
match result {
Ok(_) => {
assert_eq!(&video, video_model.get_item(0).unwrap());
assert_ne!(&new_video, video_model.get_item(0).unwrap());
}
Err(e) => assert!(false, "There was an error adding the video: {:?}", e),
}
} }
} }