Alex Mikhalev
4 years ago
23 changed files with 156 additions and 129 deletions
@ -1,5 +1,6 @@ |
|||||||
[workspace] |
[workspace] |
||||||
|
|
||||||
members = [ |
members = [ |
||||||
|
"sprinklers_core", |
||||||
"sprinklers_rs" |
"sprinklers_rs" |
||||||
] |
] |
@ -0,0 +1,16 @@ |
|||||||
|
[package] |
||||||
|
name = "sprinklers_core" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["Alex Mikhalev <alexmikhalevalex@gmail.com>"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
chrono = { version = "0.4.15" } |
||||||
|
serde = { version = "1.0.116", features = ["derive"] } |
||||||
|
im = "15.0.0" |
||||||
|
tracing = { version = "0.1.19" } |
||||||
|
|
||||||
|
[dev-dependencies] |
||||||
|
serde_json = "1.0.57" |
@ -0,0 +1,4 @@ |
|||||||
|
pub mod model; |
||||||
|
pub mod schedule; |
||||||
|
pub mod serde; |
||||||
|
pub mod section_interface; |
@ -0,0 +1,30 @@ |
|||||||
|
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_secs")] |
||||||
|
pub duration: Duration, |
||||||
|
} |
||||||
|
|
||||||
|
pub type ProgramSequence = Vec<ProgramItem>; |
||||||
|
|
||||||
|
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, |
||||||
|
} |
||||||
|
|
||||||
|
pub type ProgramRef = Arc<Program>; |
||||||
|
|
||||||
|
pub type Programs = im::OrdMap<ProgramId, ProgramRef>; |
@ -1,6 +1,6 @@ |
|||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
||||||
|
|
||||||
pub mod duration { |
pub mod duration_secs { |
||||||
use super::*; |
use super::*; |
||||||
use std::time::Duration; |
use std::time::Duration; |
||||||
|
|
@ -0,0 +1,46 @@ |
|||||||
|
use sprinklers_core::{ |
||||||
|
model::{Program, ProgramSequence}, |
||||||
|
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>; |
||||||
|
|
||||||
|
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(), |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
use sprinklers_core::model::Section; |
||||||
|
|
||||||
|
use rusqlite::{Error as SqlError, Row as SqlRow, ToSql}; |
||||||
|
|
||||||
|
pub fn from_sql<'a>(row: &SqlRow<'a>) -> Result<Section, SqlError> { |
||||||
|
Ok(Section { |
||||||
|
id: row.get(0)?, |
||||||
|
name: row.get(1)?, |
||||||
|
interface_id: row.get(2)?, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub fn as_sql(section: &Section) -> Vec<&dyn ToSql> { |
||||||
|
vec![§ion.id, §ion.name, §ion.interface_id] |
||||||
|
} |
@ -1,78 +0,0 @@ |
|||||||
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<ProgramItem>; |
|
||||||
|
|
||||||
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>(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>; |
|
Loading…
Reference in new issue