|
|
|
@ -1,13 +1,38 @@
@@ -1,13 +1,38 @@
|
|
|
|
|
use std::{time::Duration, sync::Arc}; |
|
|
|
|
use super::section::SectionId; |
|
|
|
|
use crate::schedule::Schedule; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use std::{sync::Arc, time::Duration}; |
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)] |
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)] |
|
|
|
|
pub struct ProgramItem { |
|
|
|
|
pub section_id: SectionId, |
|
|
|
|
#[serde(
|
|
|
|
|
serialize_with = "ser::serialize_duration", |
|
|
|
|
deserialize_with = "ser::deserialize_duration" |
|
|
|
|
)] |
|
|
|
|
pub duration: Duration, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
mod ser { |
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
|
|
|
|
use std::time::Duration; |
|
|
|
|
|
|
|
|
|
pub fn serialize_duration<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error> |
|
|
|
|
where |
|
|
|
|
S: Serializer, |
|
|
|
|
{ |
|
|
|
|
duration.as_secs_f64().serialize(serializer) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error> |
|
|
|
|
where |
|
|
|
|
D: Deserializer<'de>, |
|
|
|
|
{ |
|
|
|
|
let secs: f64 = Deserialize::deserialize(deserializer)?; |
|
|
|
|
Ok(Duration::from_secs_f64(secs)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub type ProgramSequence = Vec<ProgramItem>; |
|
|
|
|
|
|
|
|
|
pub type ProgramId = u32; |
|
|
|
@ -21,6 +46,54 @@ pub struct Program {
@@ -21,6 +46,54 @@ pub struct Program {
|
|
|
|
|
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>(T); |
|
|
|
|
|
|
|
|
|
impl<T> SqlJson<T> { |
|
|
|
|
fn into_inner(self) -> T { |
|
|
|
|
self.0 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<T> FromSql for SqlJson<T> |
|
|
|
|
where |
|
|
|
|
for<'de> T: Deserialize<'de>, |
|
|
|
|
{ |
|
|
|
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { |
|
|
|
|
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<ProgramSequence>; |
|
|
|
|
type SqlSchedule = SqlJson<Schedule>; |
|
|
|
|
|
|
|
|
|
impl Program { |
|
|
|
|
pub fn from_sql<'a>(row: &SqlRow<'a>) -> SqlResult<Self> { |
|
|
|
|
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<Program>; |
|
|
|
|
|
|
|
|
|
pub type Programs = im::OrdMap<ProgramId, ProgramRef>; |
|
|
|
|