updating the core for actual builds and working tests

This commit is contained in:
Chris Cochrun 2024-11-12 13:10:12 -06:00
parent e82a9c161b
commit a94ad65914
10 changed files with 219 additions and 86 deletions

View file

@ -1,11 +1,13 @@
use super::model::Model; use super::model::Model;
use miette::{Result, miette, IntoDiagnostic}; use miette::{miette, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query_as, SqliteConnection}; use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Image { pub struct Image {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -26,12 +28,17 @@ impl Model<Image> {
let _ = self.add_item(image); let _ = self.add_item(image);
} }
} }
Err(e) => error!("There was an error in converting images: {e}"), Err(e) => {
error!("There was an error in converting images: {e}")
}
}; };
} }
} }
pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> { pub async fn get_image_from_db(
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Image> {
Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?) Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
} }
@ -52,7 +59,7 @@ mod test {
pub async fn test_db_and_model() { pub async fn test_db_and_model() {
let mut image_model: Model<Image> = Model { let mut image_model: Model<Image> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
image_model.load_from_db().await; image_model.load_from_db().await;
dbg!(&image_model.items); dbg!(&image_model.items);
@ -70,16 +77,26 @@ mod test {
let image = test_image("A new image".into()); let image = test_image("A new image".into());
let mut image_model: Model<Image> = Model { let mut image_model: Model<Image> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
let result = image_model.add_item(image.clone()); let result = image_model.add_item(image.clone());
let new_image = test_image("A newer image".into()); let new_image = test_image("A newer image".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap()); assert_eq!(
assert_ne!(&new_image, image_model.find(|i| i.id == 0).unwrap()); &image,
image_model.find(|i| i.id == 0).unwrap()
);
assert_ne!(
&new_image,
image_model.find(|i| i.id == 0).unwrap()
);
} }
Err(e) => assert!(false, "There was an error adding the image: {:?}", e), Err(e) => assert!(
false,
"There was an error adding the image: {:?}",
e
),
} }
} }
} }

View file

@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
use super::presentations::PresKind; use super::presentations::PresKind;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum ServiceItemKind { pub enum ServiceItemKind {
#[default] #[default]
Song, Song,
@ -22,7 +24,9 @@ impl std::fmt::Display for ServiceItemKind {
Self::Video => "video".to_owned(), Self::Video => "video".to_owned(),
Self::Presentation(PresKind::Html) => "html".to_owned(), Self::Presentation(PresKind::Html) => "html".to_owned(),
Self::Presentation(PresKind::Pdf) => "pdf".to_owned(), Self::Presentation(PresKind::Pdf) => "pdf".to_owned(),
Self::Presentation(PresKind::Generic) => "presentation".to_owned(), Self::Presentation(PresKind::Generic) => {
"presentation".to_owned()
}
Self::Content => "content".to_owned(), Self::Content => "content".to_owned(),
}; };
write!(f, "{s}") write!(f, "{s}")
@ -36,7 +40,9 @@ impl TryFrom<String> for ServiceItemKind {
"song" => Ok(Self::Song), "song" => Ok(Self::Song),
"image" => Ok(Self::Image), "image" => Ok(Self::Image),
"video" => Ok(Self::Video), "video" => Ok(Self::Video),
"presentation" => Ok(Self::Presentation(PresKind::Generic)), "presentation" => {
Ok(Self::Presentation(PresKind::Generic))
}
"html" => Ok(Self::Presentation(PresKind::Html)), "html" => Ok(Self::Presentation(PresKind::Html)),
"pdf" => Ok(Self::Presentation(PresKind::Pdf)), "pdf" => Ok(Self::Presentation(PresKind::Pdf)),
"content" => Ok(Self::Content), "content" => Ok(Self::Content),
@ -51,7 +57,9 @@ impl From<ServiceItemKind> for String {
ServiceItemKind::Song => "song".to_owned(), ServiceItemKind::Song => "song".to_owned(),
ServiceItemKind::Video => "video".to_owned(), ServiceItemKind::Video => "video".to_owned(),
ServiceItemKind::Image => "image".to_owned(), ServiceItemKind::Image => "image".to_owned(),
ServiceItemKind::Presentation(_) => "presentation".to_owned(), ServiceItemKind::Presentation(_) => {
"presentation".to_owned()
}
ServiceItemKind::Content => "content".to_owned(), ServiceItemKind::Content => "content".to_owned(),
} }
} }
@ -65,7 +73,10 @@ pub enum ParseError {
impl Error for ParseError {} impl Error for ParseError {}
impl Display for ParseError { impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let message = match self { let message = match self {
Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'", Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
}; };

View file

@ -142,9 +142,11 @@ mod test {
#[test] #[test]
fn test_list() { fn test_list() {
let lisp = read_to_string("./test_presentation.lisp").expect("oops"); let lisp =
read_to_string("./test_presentation.lisp").expect("oops");
println!("{lisp}"); println!("{lisp}");
let mut parser = Parser::from_str_custom(&lisp, Options::elisp()); let mut parser =
Parser::from_str_custom(&lisp, Options::elisp());
for atom in parser.value_iter() { for atom in parser.value_iter() {
match atom { match atom {
Ok(atom) => { Ok(atom) => {

View file

@ -1,9 +1,9 @@
pub mod images; pub mod images;
pub mod kinds; pub mod kinds;
pub mod lisp; pub mod lisp;
pub mod model;
pub mod presentations; pub mod presentations;
pub mod service_items; pub mod service_items;
pub mod slide; pub mod slide;
pub mod songs; pub mod songs;
pub mod videos; pub mod videos;
pub mod model;

View file

@ -71,9 +71,7 @@ pub async fn get_db() -> SqliteConnection {
data.push("library-db.sqlite3"); data.push("library-db.sqlite3");
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
} }
pub trait Modeling { pub trait Modeling {

View file

@ -1,12 +1,16 @@
use miette::{miette, Result, IntoDiagnostic}; use miette::{miette, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection}; use sqlx::{
prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection,
};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
use super::model::Model; use super::model::Model;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum PresKind { pub enum PresKind {
Html, Html,
#[default] #[default]
@ -14,7 +18,9 @@ pub enum PresKind {
Generic, Generic,
} }
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Presentation { pub struct Presentation {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -75,7 +81,9 @@ impl Model<Presentation> {
}); });
} }
} }
Err(e) => error!("There was an error in converting presentations: {e}"), Err(e) => error!(
"There was an error in converting presentations: {e}"
),
} }
} }
} }
@ -114,10 +122,12 @@ mod test {
async fn test_db_and_model() { async fn test_db_and_model() {
let mut presentation_model: Model<Presentation> = Model { let mut presentation_model: Model<Presentation> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
presentation_model.load_from_db().await; presentation_model.load_from_db().await;
if let Some(presentation) = presentation_model.find(|p| p.id == 54) { if let Some(presentation) =
presentation_model.find(|p| p.id == 54)
{
let test_presentation = test_presentation(); let test_presentation = test_presentation();
assert_eq!(&test_presentation, presentation); assert_eq!(&test_presentation, presentation);
} else { } else {

View file

@ -52,7 +52,9 @@ impl From<&Image> for ServiceItem {
impl From<&Presentation> for ServiceItem { impl From<&Presentation> for ServiceItem {
fn from(presentation: &Presentation) -> Self { fn from(presentation: &Presentation) -> Self {
Self { Self {
kind: ServiceItemKind::Presentation(presentation.kind.clone()), kind: ServiceItemKind::Presentation(
presentation.kind.clone(),
),
database_id: presentation.id, database_id: presentation.id,
..Default::default() ..Default::default()
} }
@ -60,7 +62,10 @@ impl From<&Presentation> for ServiceItem {
} }
impl ServiceItemModel { impl ServiceItemModel {
fn add_item(&mut self, item: impl Into<ServiceItem>) -> Result<()> { fn add_item(
&mut self,
item: impl Into<ServiceItem>,
) -> Result<()> {
let service_item: ServiceItem = item.into(); let service_item: ServiceItem = item.into();
self.items.push(service_item); self.items.push(service_item);
Ok(()) Ok(())
@ -103,7 +108,10 @@ mod test {
let mut service_model = ServiceItemModel::default(); let mut service_model = ServiceItemModel::default();
match service_model.add_item(&song) { match service_model.add_item(&song) {
Ok(_) => { Ok(_) => {
assert_eq!(ServiceItemKind::Song, service_model.items[0].kind); assert_eq!(
ServiceItemKind::Song,
service_model.items[0].kind
);
assert_eq!( assert_eq!(
ServiceItemKind::Presentation(PresKind::Html), ServiceItemKind::Presentation(PresKind::Html),
pres_item.kind pres_item.kind

View file

@ -15,7 +15,9 @@ use crate::core::lisp::Symbol;
use super::lisp::get_lists; use super::lisp::get_lists;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum TextAlignment { pub enum TextAlignment {
TopLeft, TopLeft,
TopCenter, TopCenter,
@ -39,7 +41,9 @@ impl From<Value> for TextAlignment {
} }
} }
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Background { pub struct Background {
pub path: PathBuf, pub path: PathBuf,
pub kind: BackgroundKind, pub kind: BackgroundKind,
@ -113,16 +117,23 @@ pub enum ParseError {
impl std::error::Error for ParseError {} impl std::error::Error for ParseError {}
impl Display for ParseError { impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let message = match self { let message = match self {
Self::NonBackgroundFile => "The file is not a recognized image or video type", Self::NonBackgroundFile => {
"The file is not a recognized image or video type"
}
Self::DoesNotExist => "This file doesn't exist", Self::DoesNotExist => "This file doesn't exist",
}; };
write!(f, "Error: {message}") write!(f, "Error: {message}")
} }
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum BackgroundKind { pub enum BackgroundKind {
#[default] #[default]
Image, Image,
@ -139,7 +150,9 @@ impl From<String> for BackgroundKind {
} }
} }
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Slide { pub struct Slide {
id: i32, id: i32,
background: Background, background: Background,
@ -170,7 +183,9 @@ impl Slide {
} }
} }
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct SlideBuilder { pub struct SlideBuilder {
background: Option<Background>, background: Option<Background>,
text: Option<String>, text: Option<String>,
@ -187,7 +202,10 @@ impl SlideBuilder {
Self::default() Self::default()
} }
pub(crate) fn background(mut self, background: PathBuf) -> Result<Self, ParseError> { pub(crate) fn background(
mut self,
background: PathBuf,
) -> Result<Self, ParseError> {
let background = Background::try_from(background)?; let background = Background::try_from(background)?;
let _ = self.background.insert(background); let _ = self.background.insert(background);
Ok(self) Ok(self)
@ -208,7 +226,10 @@ impl SlideBuilder {
self self
} }
pub(crate) fn text_alignment(mut self, text_alignment: TextAlignment) -> Self { pub(crate) fn text_alignment(
mut self,
text_alignment: TextAlignment,
) -> Self {
let _ = self.text_alignment.insert(text_alignment); let _ = self.text_alignment.insert(text_alignment);
self self
} }
@ -218,12 +239,18 @@ impl SlideBuilder {
self self
} }
pub(crate) fn video_start_time(mut self, video_start_time: f32) -> Self { pub(crate) fn video_start_time(
mut self,
video_start_time: f32,
) -> Self {
let _ = self.video_start_time.insert(video_start_time); let _ = self.video_start_time.insert(video_start_time);
self self
} }
pub(crate) fn video_end_time(mut self, video_end_time: f32) -> Self { pub(crate) fn video_end_time(
mut self,
video_end_time: f32,
) -> Self {
let _ = self.video_end_time.insert(video_end_time); let _ = self.video_end_time.insert(video_end_time);
self self
} }
@ -281,7 +308,11 @@ impl Image {
} }
} }
fn build_image_bg(atom: &Value, image_map: &mut HashMap<String, String>, map_index: usize) { fn build_image_bg(
atom: &Value,
image_map: &mut HashMap<String, String>,
map_index: usize,
) {
// This needs to be the cons that contains (image . ...) // This needs to be the cons that contains (image . ...)
// the image is a symbol and the rest are keywords and other maps // the image is a symbol and the rest are keywords and other maps
if atom.is_symbol() { if atom.is_symbol() {
@ -289,7 +320,9 @@ fn build_image_bg(atom: &Value, image_map: &mut HashMap<String, String>, map_ind
return; return;
} }
for atom in atom.list_iter().unwrap().map(|a| a.as_cons().unwrap()) { for atom in
atom.list_iter().unwrap().map(|a| a.as_cons().unwrap())
{
if atom.car() == &Value::Symbol("image".into()) { if atom.car() == &Value::Symbol("image".into()) {
build_image_bg(atom.cdr(), image_map, map_index); build_image_bg(atom.cdr(), image_map, map_index);
} else { } else {
@ -345,7 +378,11 @@ fn build_slides(
dbg!(&current_symbol); dbg!(&current_symbol);
match value { match value {
Value::Cons(v) => { Value::Cons(v) => {
slide_builder = build_slides(&v, current_symbol.clone(), slide_builder); slide_builder = build_slides(
&v,
current_symbol.clone(),
slide_builder,
);
} }
Value::Nil => { Value::Nil => {
dbg!(Value::Nil); dbg!(Value::Nil);
@ -361,7 +398,8 @@ fn build_slides(
} }
Value::Symbol(symbol) => { Value::Symbol(symbol) => {
dbg!(symbol); dbg!(symbol);
current_symbol = Symbol::from_str(symbol).unwrap_or_default(); current_symbol =
Symbol::from_str(symbol).unwrap_or_default();
} }
Value::Keyword(keyword) => { Value::Keyword(keyword) => {
dbg!(keyword); dbg!(keyword);
@ -399,16 +437,19 @@ mod test {
#[test] #[test]
fn test_lexp_serialize() { fn test_lexp_serialize() {
let lisp = read_to_string("./test_presentation.lisp").expect("oops"); let lisp =
read_to_string("./test_presentation.lisp").expect("oops");
println!("{lisp}"); println!("{lisp}");
let mut parser = Parser::from_str_custom(&lisp, Options::elisp()); let mut parser =
Parser::from_str_custom(&lisp, Options::elisp());
for atom in parser.value_iter() { for atom in parser.value_iter() {
match atom { match atom {
Ok(atom) => { Ok(atom) => {
let symbol = Symbol::None; let symbol = Symbol::None;
let slide_builder = SlideBuilder::new(); let slide_builder = SlideBuilder::new();
atom.as_cons() atom.as_cons().map(|c| {
.map(|c| build_slides(c, symbol, slide_builder)); build_slides(c, symbol, slide_builder)
});
} }
Err(e) => { Err(e) => {
dbg!(e); dbg!(e);
@ -432,7 +473,8 @@ mod test {
#[test] #[test]
fn test_ron_deserialize() { fn test_ron_deserialize() {
let slide = read_to_string("./test_presentation.ron").expect("Problem getting file read"); let slide = read_to_string("./test_presentation.ron")
.expect("Problem getting file read");
match ron::from_str::<Vec<Slide>>(&slide) { match ron::from_str::<Vec<Slide>>(&slide) {
Ok(s) => { Ok(s) => {
dbg!(s); dbg!(s);

View file

@ -3,15 +3,20 @@ use std::{collections::HashMap, path::PathBuf};
use cosmic::{executor, iced::Executor}; use cosmic::{executor, iced::Executor};
use miette::{miette, IntoDiagnostic, Result}; use miette::{miette, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection}; use sqlx::{
query, query_as, sqlite::SqliteRow, FromRow, Row,
SqliteConnection,
};
use tracing::{debug, error}; use tracing::{debug, error};
use super::{ use super::{
model::{Model}, model::Model,
slide::{Background, TextAlignment}, slide::{Background, TextAlignment},
}; };
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Song { pub struct Song {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -27,9 +32,11 @@ pub struct Song {
} }
const VERSE_KEYWORDS: [&str; 24] = [ const VERSE_KEYWORDS: [&str; 24] = [
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", "Verse 7", "Verse 8", "Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6",
"Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", "Verse 7", "Verse 8", "Chorus 1", "Chorus 2", "Chorus 3",
"Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1", "Other 2", "Other 3", "Other 4", "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
"Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1",
"Other 2", "Other 3", "Other 4",
]; ];
impl FromRow<'_, SqliteRow> for Song { impl FromRow<'_, SqliteRow> for Song {
@ -54,7 +61,6 @@ impl FromRow<'_, SqliteRow> for Song {
Ok(background) => Some(background), Ok(background) => Some(background),
Err(_) => None, Err(_) => None,
} }
}, },
text_alignment: Some({ text_alignment: Some({
let horizontal_alignment: String = row.try_get(3)?; let horizontal_alignment: String = row.try_get(3)?;
@ -67,8 +73,12 @@ impl FromRow<'_, SqliteRow> for Song {
("left", "center") => TextAlignment::MiddleLeft, ("left", "center") => TextAlignment::MiddleLeft,
("left", "bottom") => TextAlignment::BottomLeft, ("left", "bottom") => TextAlignment::BottomLeft,
("center", "top") => TextAlignment::TopCenter, ("center", "top") => TextAlignment::TopCenter,
("center", "center") => TextAlignment::MiddleCenter, ("center", "center") => {
("center", "bottom") => TextAlignment::BottomCenter, TextAlignment::MiddleCenter
}
("center", "bottom") => {
TextAlignment::BottomCenter
}
("right", "top") => TextAlignment::TopRight, ("right", "top") => TextAlignment::TopRight,
("right", "center") => TextAlignment::MiddleRight, ("right", "center") => TextAlignment::MiddleRight,
("right", "bottom") => TextAlignment::BottomRight, ("right", "bottom") => TextAlignment::BottomRight,
@ -81,7 +91,10 @@ impl FromRow<'_, SqliteRow> for Song {
} }
} }
pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> { pub async fn get_song_from_db(
index: i32,
db: &mut SqliteConnection,
) -> Result<Song> {
let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await.into_diagnostic()?; let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await.into_diagnostic()?;
Ok(Song::from_row(&row).into_diagnostic()?) Ok(Song::from_row(&row).into_diagnostic()?)
} }
@ -96,14 +109,16 @@ impl Model<Song> {
match Song::from_row(&song) { match Song::from_row(&song) {
Ok(song) => { Ok(song) => {
let _ = self.add_item(song); let _ = self.add_item(song);
}, }
Err(e) => error!("Could not convert song: {e}"), Err(e) => {
error!("Could not convert song: {e}")
}
}; };
}; }
}, }
Err(e) => { Err(e) => {
error!("There was an error in converting songs: {e}"); error!("There was an error in converting songs: {e}");
}, }
} }
} }
} }
@ -115,7 +130,11 @@ impl Song {
return Err(miette!("There is no lyrics here")); return Err(miette!("There is no lyrics here"));
} else if self.verse_order.is_none() { } else if self.verse_order.is_none() {
return Err(miette!("There is no verse_order here")); return Err(miette!("There is no verse_order here"));
} else if self.verse_order.clone().is_some_and(|v| v.is_empty()) { } else if self
.verse_order
.clone()
.is_some_and(|v| v.is_empty())
{
return Err(miette!("There is no verse_order here")); return Err(miette!("There is no verse_order here"));
} }
if let Some(raw_lyrics) = self.lyrics.clone() { if let Some(raw_lyrics) = self.lyrics.clone() {
@ -145,16 +164,21 @@ impl Song {
let mut verse_name = ""; let mut verse_name = "";
debug!(verse = verse); debug!(verse = verse);
for word in VERSE_KEYWORDS { for word in VERSE_KEYWORDS {
let end_verse = verse.get(1..2).unwrap_or_default(); let end_verse =
let beg_verse = verse.get(0..1).unwrap_or_default(); verse.get(1..2).unwrap_or_default();
if word.starts_with(beg_verse) && word.ends_with(end_verse) { let beg_verse =
verse.get(0..1).unwrap_or_default();
if word.starts_with(beg_verse)
&& word.ends_with(end_verse)
{
verse_name = word; verse_name = word;
continue; continue;
} }
} }
if let Some(lyric) = lyric_map.get(verse_name) { if let Some(lyric) = lyric_map.get(verse_name) {
if lyric.contains("\n\n") { if lyric.contains("\n\n") {
let split_lyrics: Vec<&str> = lyric.split("\n\n").collect(); let split_lyrics: Vec<&str> =
lyric.split("\n\n").collect();
for lyric in split_lyrics { for lyric in split_lyrics {
if lyric.is_empty() { if lyric.is_empty() {
continue; continue;
@ -246,11 +270,12 @@ From the day
You saved my soul" You saved my soul"
.to_string(), .to_string(),
); );
song.verse_order = "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" song.verse_order =
.to_string() "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
.split(' ') .to_string()
.map(|s| Some(s.to_string())) .split(' ')
.collect(); .map(|s| Some(s.to_string()))
.collect();
let lyrics = song.get_lyrics(); let lyrics = song.get_lyrics();
match lyrics { match lyrics {
Ok(lyrics) => { Ok(lyrics) => {
@ -265,7 +290,7 @@ You saved my soul"
async fn model() -> Model<Song> { async fn model() -> Model<Song> {
let song_model: Model<Song> = Model { let song_model: Model<Song> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
song_model song_model
} }
@ -302,7 +327,10 @@ You saved my soul"
song_model.load_from_db().await; song_model.load_from_db().await;
match song_model.update_item(song, 2) { match song_model.update_item(song, 2) {
Ok(()) => assert_eq!(&cloned_song, song_model.find(|s| s.id == 7).unwrap()), Ok(()) => assert_eq!(
&cloned_song,
song_model.find(|s| s.id == 7).unwrap()
),
Err(e) => assert!(false, "{e}"), Err(e) => assert!(false, "{e}"),
} }
} }

View file

@ -1,12 +1,14 @@
use super::model::Model; use super::model::Model;
use cosmic::{executor, iced::Executor}; use cosmic::{executor, iced::Executor};
use miette::{Result, miette, IntoDiagnostic}; use miette::{miette, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query_as, SqliteConnection}; use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Video { pub struct Video {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -25,12 +27,17 @@ impl Model<Video> {
let _ = self.add_item(video); let _ = self.add_item(video);
} }
} }
Err(e) => error!("There was an error in converting videos: {e}"), Err(e) => {
error!("There was an error in converting videos: {e}")
}
}; };
} }
} }
pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> { pub async fn get_video_from_db(
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Video> {
Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?) Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
} }
@ -51,7 +58,7 @@ mod test {
async fn test_db_and_model() { async fn test_db_and_model() {
let mut video_model: Model<Video> = Model { let mut video_model: Model<Video> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
video_model.load_from_db().await; video_model.load_from_db().await;
if let Some(video) = video_model.find(|v| v.id == 73) { if let Some(video) = video_model.find(|v| v.id == 73) {
@ -70,16 +77,26 @@ mod test {
let video = test_video("A new video".into()); let video = test_video("A new video".into());
let mut video_model: Model<Video> = Model { let mut video_model: Model<Video> = Model {
items: vec![], items: vec![],
db: crate::core::model::get_db().await db: crate::core::model::get_db().await,
}; };
let result = video_model.add_item(video.clone()); let result = video_model.add_item(video.clone());
let new_video = test_video("A newer video".into()); let new_video = test_video("A newer video".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap()); assert_eq!(
assert_ne!(&new_video, video_model.find(|v| v.id == 0).unwrap()); &video,
video_model.find(|v| v.id == 0).unwrap()
);
assert_ne!(
&new_video,
video_model.find(|v| v.id == 0).unwrap()
);
} }
Err(e) => assert!(false, "There was an error adding the video: {:?}", e), Err(e) => assert!(
false,
"There was an error adding the video: {:?}",
e
),
} }
} }
} }