use diesel::dsl::sql; use diesel::prelude::*; use std::borrow::Borrow; use crate::types::EmgauwaUid; use crate::db::errors::DatabaseError; use crate::db::models::*; use crate::db::schema::junction_tag::dsl::junction_tag; use crate::db::schema::schedules::dsl::schedules; use crate::db::schema::tags::dsl::tags; use crate::db::tag::{create_junction_tag, create_tag}; use crate::db::{get_connection, schema}; pub fn get_schedule_tags(schedule: &Schedule) -> Vec<String> { let connection = get_connection(); JunctionTag::belonging_to(schedule) .inner_join(schema::tags::dsl::tags) .select(schema::tags::tag) .load::<String>(&connection) .expect("Error loading tags") } pub fn get_schedules() -> Vec<Schedule> { let connection = get_connection(); schedules .load::<Schedule>(&connection) .expect("Error loading schedules") } pub fn get_schedule_by_uid(filter_uid: EmgauwaUid) -> Result<Schedule, DatabaseError> { let connection = get_connection(); let result = schedules .filter(schema::schedules::uid.eq(filter_uid)) .first::<Schedule>(&connection) .or(Err(DatabaseError::NotFound))?; Ok(result) } pub fn get_schedules_by_tag(tag: &Tag) -> Vec<Schedule> { let connection = get_connection(); JunctionTag::belonging_to(tag) .inner_join(schedules) .select(schema::schedules::all_columns) .load::<Schedule>(&connection) .expect("Error loading tags") } pub fn delete_schedule_by_uid(filter_uid: EmgauwaUid) -> Result<(), DatabaseError> { let filter_uid = match filter_uid { EmgauwaUid::Off => Err(DatabaseError::Protected), EmgauwaUid::On => Err(DatabaseError::Protected), EmgauwaUid::Any(_) => Ok(filter_uid), }?; let connection = get_connection(); match diesel::delete(schedules.filter(schema::schedules::uid.eq(filter_uid))) .execute(&connection) { Ok(rows) => { if rows != 0 { Ok(()) } else { Err(DatabaseError::DeleteError) } } Err(_) => Err(DatabaseError::DeleteError), } } pub fn create_schedule(new_name: &str, new_periods: &Periods) -> Result<Schedule, DatabaseError> { let connection = get_connection(); let new_schedule = NewSchedule { uid: &EmgauwaUid::default(), name: new_name, periods: new_periods, }; diesel::insert_into(schedules) .values(&new_schedule) .execute(&connection) .map_err(DatabaseError::InsertError)?; let result = schedules .find(sql("last_insert_rowid()")) .get_result::<Schedule>(&connection) .or(Err(DatabaseError::InsertGetError))?; Ok(result) } pub fn update_schedule( schedule: &Schedule, new_name: &str, new_periods: &Periods, ) -> Result<Schedule, DatabaseError> { let connection = get_connection(); let new_periods = match schedule.uid { EmgauwaUid::Off | EmgauwaUid::On => schedule.periods.borrow(), EmgauwaUid::Any(_) => new_periods, }; diesel::update(schedule) .set(( schema::schedules::name.eq(new_name), schema::schedules::periods.eq(new_periods), )) .execute(&connection) .map_err(DatabaseError::UpdateError)?; get_schedule_by_uid(schedule.uid.clone()) } pub fn set_schedule_tags(schedule: &Schedule, new_tags: &[String]) -> Result<(), DatabaseError> { let connection = get_connection(); diesel::delete(junction_tag.filter(schema::junction_tag::schedule_id.eq(schedule.id))) .execute(&connection) .or(Err(DatabaseError::DeleteError))?; let mut database_tags: Vec<Tag> = tags .filter(schema::tags::tag.eq_any(new_tags)) .load::<Tag>(&connection) .expect("Error loading tags"); let database_tags_str: Vec<String> = database_tags .iter() .map(|tag_db| tag_db.tag.clone()) .collect(); // create missing tags for new_tag in new_tags { if !database_tags_str.contains(new_tag) { database_tags.push(create_tag(new_tag).expect("Error inserting tag")); } } for database_tag in database_tags { create_junction_tag(database_tag, None, Some(schedule)) .expect("Error saving junction between tag and schedule"); } Ok(()) }