Implement updating program
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
cc1a5bb09d
commit
89d7b01a76
@ -8,10 +8,10 @@ pub use migrations::create_migrations;
|
||||
|
||||
pub use rusqlite::Connection as DbConn;
|
||||
|
||||
use sprinklers_core::model::{Programs, Sections};
|
||||
use sprinklers_core::model::{Program, Programs, Sections};
|
||||
|
||||
use eyre::Result;
|
||||
use rusqlite::NO_PARAMS;
|
||||
use rusqlite::{params, NO_PARAMS};
|
||||
|
||||
pub fn setup_db() -> Result<DbConn> {
|
||||
// let conn = DbConn::open_in_memory()?;
|
||||
@ -40,7 +40,7 @@ pub fn query_sections(conn: &DbConn) -> Result<Sections> {
|
||||
pub fn query_programs(conn: &DbConn) -> Result<Programs> {
|
||||
let mut statement = conn.prepare_cached(
|
||||
"
|
||||
SELECT p.id, p.name, ps.sequence, p.enabled, p.schedule
|
||||
SELECT p.id, p.name, p.enabled, p.schedule, ps.sequence
|
||||
FROM programs AS p
|
||||
INNER JOIN program_sequences AS ps
|
||||
ON ps.program_id = p.id;",
|
||||
@ -53,3 +53,34 @@ pub fn query_programs(conn: &DbConn) -> Result<Programs> {
|
||||
}
|
||||
Ok(programs)
|
||||
}
|
||||
|
||||
pub fn update_program(conn: &mut DbConn, prog: &Program) -> Result<()> {
|
||||
let trans = conn.transaction()?;
|
||||
trans
|
||||
.prepare_cached(
|
||||
"
|
||||
UPDATE programs
|
||||
SET (name, enabled, schedule) = (?2, ?3, ?4)
|
||||
WHERE id = ?1;",
|
||||
)?
|
||||
.execute(&program::as_sql(prog))?;
|
||||
trans
|
||||
.prepare_cached(
|
||||
"
|
||||
DELETE FROM program_sequence_items AS psi
|
||||
WHERE psi.program_id = ?1;",
|
||||
)?
|
||||
.execute(params![prog.id])?;
|
||||
let mut insert_prog_seq = trans.prepare_cached(
|
||||
"
|
||||
INSERT INTO program_sequence_items
|
||||
(program_id, seq_num, section_id, duration)
|
||||
VALUES (?1, ?2, ?3, ?4);",
|
||||
)?;
|
||||
for params in program::sequence_as_sql(prog) {
|
||||
insert_prog_seq.execute(¶ms)?;
|
||||
}
|
||||
drop(insert_prog_seq);
|
||||
trans.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
use sprinklers_core::{
|
||||
model::{Program, ProgramSequence},
|
||||
model::{Program, ProgramId, ProgramItem, ProgramSequence, SectionId},
|
||||
schedule::Schedule,
|
||||
};
|
||||
|
||||
use rusqlite::{
|
||||
types::{FromSql, FromSqlError, FromSqlResult, ValueRef},
|
||||
Result as SqlResult, Row as SqlRow,
|
||||
types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, Value, ValueRef},
|
||||
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> {
|
||||
fn into_inner(self) -> T {
|
||||
pub fn into_inner(self) -> T {
|
||||
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 SqlSchedule = SqlJson<Schedule>;
|
||||
|
||||
@ -39,8 +50,83 @@ pub fn from_sql<'a>(row: &SqlRow<'a>) -> SqlResult<Program> {
|
||||
Ok(Program {
|
||||
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(),
|
||||
enabled: row.get(2)?,
|
||||
schedule: row.get::<_, SqlSchedule>(3)?.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))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user