Browse Source

Implement updating program

master
Alex Mikhalev 4 years ago
parent
commit
89d7b01a76
  1. 37
      sprinklers_database/src/lib.rs
  2. 104
      sprinklers_database/src/program.rs

37
sprinklers_database/src/lib.rs

@ -8,10 +8,10 @@ pub use migrations::create_migrations;
pub use rusqlite::Connection as DbConn; pub use rusqlite::Connection as DbConn;
use sprinklers_core::model::{Programs, Sections}; use sprinklers_core::model::{Program, Programs, Sections};
use eyre::Result; use eyre::Result;
use rusqlite::NO_PARAMS; use rusqlite::{params, NO_PARAMS};
pub fn setup_db() -> Result<DbConn> { pub fn setup_db() -> Result<DbConn> {
// let conn = DbConn::open_in_memory()?; // 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> { pub fn query_programs(conn: &DbConn) -> Result<Programs> {
let mut statement = conn.prepare_cached( 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 FROM programs AS p
INNER JOIN program_sequences AS ps INNER JOIN program_sequences AS ps
ON ps.program_id = p.id;", ON ps.program_id = p.id;",
@ -53,3 +53,34 @@ pub fn query_programs(conn: &DbConn) -> Result<Programs> {
} }
Ok(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(&params)?;
}
drop(insert_prog_seq);
trans.commit()?;
Ok(())
}

104
sprinklers_database/src/program.rs

@ -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))
}

Loading…
Cancel
Save