|
|
@ -1,18 +1,18 @@ |
|
|
|
use sprinklers_core::{ |
|
|
|
use sprinklers_core::{ |
|
|
|
model::{Program, ProgramSequence}, |
|
|
|
model::{Program, ProgramId, ProgramItem, ProgramSequence, SectionId}, |
|
|
|
schedule::Schedule, |
|
|
|
schedule::Schedule, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
use rusqlite::{ |
|
|
|
use rusqlite::{ |
|
|
|
types::{FromSql, FromSqlError, FromSqlResult, ValueRef}, |
|
|
|
types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, Value, ValueRef}, |
|
|
|
Result as SqlResult, Row as SqlRow, |
|
|
|
Error as SqlError, Result as SqlResult, Row as SqlRow, ToSql, |
|
|
|
}; |
|
|
|
}; |
|
|
|
use serde::Deserialize; |
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
|
|
|
|
|
|
|
struct SqlJson<T>(T); |
|
|
|
pub struct SqlJson<T>(T); |
|
|
|
|
|
|
|
|
|
|
|
impl<T> SqlJson<T> { |
|
|
|
impl<T> SqlJson<T> { |
|
|
|
fn into_inner(self) -> T { |
|
|
|
pub fn into_inner(self) -> T { |
|
|
|
self.0 |
|
|
|
self.0 |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -32,6 +32,17 @@ where |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T> ToSql for SqlJson<T> |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
T: Serialize, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
fn to_sql(&self) -> SqlResult<ToSqlOutput<'_>> { |
|
|
|
|
|
|
|
serde_json::to_string(&self.0) |
|
|
|
|
|
|
|
.map(|serialized| ToSqlOutput::Owned(Value::Text(serialized))) |
|
|
|
|
|
|
|
.map_err(|err| SqlError::ToSqlConversionFailure(Box::new(err))) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type SqlProgramSequence = SqlJson<ProgramSequence>; |
|
|
|
type SqlProgramSequence = SqlJson<ProgramSequence>; |
|
|
|
type SqlSchedule = SqlJson<Schedule>; |
|
|
|
type SqlSchedule = SqlJson<Schedule>; |
|
|
|
|
|
|
|
|
|
|
@ -39,8 +50,83 @@ pub fn from_sql<'a>(row: &SqlRow<'a>) -> SqlResult<Program> { |
|
|
|
Ok(Program { |
|
|
|
Ok(Program { |
|
|
|
id: row.get(0)?, |
|
|
|
id: row.get(0)?, |
|
|
|
name: row.get(1)?, |
|
|
|
name: row.get(1)?, |
|
|
|
sequence: row.get::<_, SqlProgramSequence>(2)?.into_inner(), |
|
|
|
enabled: row.get(2)?, |
|
|
|
enabled: row.get(3)?, |
|
|
|
schedule: row.get::<_, SqlSchedule>(3)?.into_inner(), |
|
|
|
schedule: row.get::<_, SqlSchedule>(4)?.into_inner(), |
|
|
|
sequence: row.get::<_, SqlProgramSequence>(4)?.into_inner(), |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct SqlProgram<'a> { |
|
|
|
|
|
|
|
id: ProgramId, |
|
|
|
|
|
|
|
name: &'a String, |
|
|
|
|
|
|
|
enabled: bool, |
|
|
|
|
|
|
|
schedule: SqlJson<&'a Schedule>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> IntoIterator for &'a SqlProgram<'a> { |
|
|
|
|
|
|
|
type Item = &'a dyn ToSql; |
|
|
|
|
|
|
|
type IntoIter = std::vec::IntoIter<Self::Item>; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter { |
|
|
|
|
|
|
|
vec![ |
|
|
|
|
|
|
|
&self.id as &dyn ToSql, |
|
|
|
|
|
|
|
self.name, |
|
|
|
|
|
|
|
&self.enabled, |
|
|
|
|
|
|
|
&self.schedule, |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn as_sql(program: &Program) -> SqlProgram { |
|
|
|
|
|
|
|
SqlProgram { |
|
|
|
|
|
|
|
id: program.id, |
|
|
|
|
|
|
|
name: &program.name, |
|
|
|
|
|
|
|
enabled: program.enabled, |
|
|
|
|
|
|
|
schedule: SqlJson(&program.schedule), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct SqlProgramItem { |
|
|
|
|
|
|
|
program_id: ProgramId, |
|
|
|
|
|
|
|
seq_num: isize, |
|
|
|
|
|
|
|
section_id: SectionId, |
|
|
|
|
|
|
|
duration: f64, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> IntoIterator for &'a SqlProgramItem { |
|
|
|
|
|
|
|
type Item = &'a dyn ToSql; |
|
|
|
|
|
|
|
type IntoIter = std::vec::IntoIter<Self::Item>; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter { |
|
|
|
|
|
|
|
vec![ |
|
|
|
|
|
|
|
&self.program_id as &dyn ToSql, |
|
|
|
|
|
|
|
&self.seq_num, |
|
|
|
|
|
|
|
&self.section_id, |
|
|
|
|
|
|
|
&self.duration, |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn item_as_sql( |
|
|
|
|
|
|
|
program_item: &ProgramItem, |
|
|
|
|
|
|
|
program_id: ProgramId, |
|
|
|
|
|
|
|
seq_num: usize, |
|
|
|
|
|
|
|
) -> SqlProgramItem { |
|
|
|
|
|
|
|
SqlProgramItem { |
|
|
|
|
|
|
|
program_id, |
|
|
|
|
|
|
|
seq_num: (seq_num + 1) as isize, |
|
|
|
|
|
|
|
section_id: program_item.section_id, |
|
|
|
|
|
|
|
duration: program_item.duration.as_secs_f64(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn sequence_as_sql<'a>(program: &'a Program) -> impl Iterator<Item = SqlProgramItem> + 'a { |
|
|
|
|
|
|
|
let program_id = program.id; |
|
|
|
|
|
|
|
program |
|
|
|
|
|
|
|
.sequence |
|
|
|
|
|
|
|
.iter() |
|
|
|
|
|
|
|
.enumerate() |
|
|
|
|
|
|
|
.map(move |(seq_num, item)| item_as_sql(item, program_id, seq_num)) |
|
|
|
|
|
|
|
} |
|
|
|