use super::section::SectionId; use crate::schedule::Schedule; use serde::{Deserialize, Serialize}; use std::{sync::Arc, time::Duration}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProgramItem { pub section_id: SectionId, #[serde(with = "crate::serde::duration")] pub duration: Duration, } pub type ProgramSequence = Vec; pub type ProgramId = u32; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Program { pub id: ProgramId, pub name: String, pub sequence: ProgramSequence, pub enabled: bool, pub schedule: Schedule, } mod sql { use super::{Program, ProgramSequence}; use crate::schedule::Schedule; use rusqlite::{ types::{FromSql, FromSqlError, FromSqlResult, ValueRef}, Result as SqlResult, Row as SqlRow, }; use serde::Deserialize; struct SqlJson(T); impl SqlJson { fn into_inner(self) -> T { self.0 } } impl FromSql for SqlJson where for<'de> T: Deserialize<'de>, { fn column_result(value: ValueRef<'_>) -> FromSqlResult { if let ValueRef::Text(text) = value { let deser_value: T = serde_json::from_slice(text) .map_err(|err| FromSqlError::Other(Box::new(err)))?; Ok(SqlJson(deser_value)) } else { Err(FromSqlError::InvalidType) } } } type SqlProgramSequence = SqlJson; type SqlSchedule = SqlJson; impl Program { pub fn from_sql<'a>(row: &SqlRow<'a>) -> SqlResult { Ok(Self { id: row.get(0)?, name: row.get(1)?, sequence: row.get::<_, SqlProgramSequence>(2)?.into_inner(), enabled: row.get(3)?, schedule: row.get::<_, SqlSchedule>(4)?.into_inner(), }) } } } pub type ProgramRef = Arc; pub type Programs = im::OrdMap;