Add controller to database

This commit is contained in:
Tobias Reisinger 2023-11-24 22:45:44 +01:00
parent 9f64075f5a
commit d193000aec
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
34 changed files with 411 additions and 195 deletions

View file

@ -2,10 +2,11 @@
build: build:
cargo build cargo build
sqlx: build sqlx:
rm ./emgauwa-dev.sqlite
cargo sqlx database create cargo sqlx database create
cargo sqlx migrate run cargo sqlx migrate run
cargo sqlx prepare cargo sqlx prepare --workspace
build-rpi: build-rpi:
cross build --target arm-unknown-linux-gnueabihf cross build --target arm-unknown-linux-gnueabihf

View file

@ -2,8 +2,10 @@ use std::str;
use futures::{future, pin_mut, StreamExt}; use futures::{future, pin_mut, StreamExt};
use futures::channel::mpsc; use futures::channel::mpsc;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::AsyncReadExt;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use tokio_tungstenite::tungstenite::Error;
use emgauwa_lib::db;
mod settings; mod settings;
@ -11,6 +13,8 @@ mod settings;
async fn main() { async fn main() {
let settings = settings::init(); let settings = settings::init();
let _pool = db::init(&settings.database).await;
let url = format!( let url = format!(
"ws://{}:{}/api/v1/ws/controllers", "ws://{}:{}/api/v1/ws/controllers",
settings.core.host, settings.core.host,
@ -21,17 +25,11 @@ async fn main() {
tokio::spawn(read_stdin(stdin_tx)); tokio::spawn(read_stdin(stdin_tx));
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect"); let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
println!("WebSocket handshake has been successfully completed");
let (write, read) = ws_stream.split(); let (write, read) = ws_stream.split();
let stdin_to_ws = stdin_rx.map(Ok).forward(write); let stdin_to_ws = stdin_rx.map(Ok).forward(write);
let ws_to_stdout = { let ws_to_stdout = read.for_each(handle_message);
read.for_each(|message| async {
let data = message.unwrap().into_text().unwrap();
println!("{}", data);
})
};
pin_mut!(stdin_to_ws, ws_to_stdout); pin_mut!(stdin_to_ws, ws_to_stdout);
future::select(stdin_to_ws, ws_to_stdout).await; future::select(stdin_to_ws, ws_to_stdout).await;
@ -51,3 +49,10 @@ async fn read_stdin(tx: mpsc::UnboundedSender<Message>) {
tx.unbounded_send(Message::text(str::from_utf8(&buf).unwrap())).unwrap(); tx.unbounded_send(Message::text(str::from_utf8(&buf).unwrap())).unwrap();
} }
} }
pub async fn handle_message(message_result: Result<Message, Error>) {
match message_result {
Ok(message) => println!("{}", message.into_text().unwrap()),
Err(err) => println!("Error: {}", err)
}
}

View file

@ -14,13 +14,13 @@ async fn main() -> std::io::Result<()> {
let settings = settings::init(); let settings = settings::init();
let log_level: LevelFilter = LevelFilter::from_str(&settings.logging.level) let log_level: LevelFilter = LevelFilter::from_str(&settings.logging.level)
.unwrap_or_else(|_| panic!("Error parsing log level.")); .expect("Error parsing log level.");
trace!("Log level set to {:?}", log_level); trace!("Log level set to {:?}", log_level);
SimpleLogger::new() SimpleLogger::new()
.with_level(log_level) .with_level(log_level)
.init() .init()
.unwrap_or_else(|_| panic!("Error initializing logger.")); .expect("Error initializing logger.");
let pool = emgauwa_lib::db::init(&settings.database).await; let pool = emgauwa_lib::db::init(&settings.database).await;

View file

@ -0,0 +1,122 @@
use serde_derive::{Deserialize, Serialize};
use std::ops::DerefMut;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period;
use crate::db::tag::Tag;
use crate::db::types::ControllerUid;
#[derive(Debug, Serialize, Clone)]
pub struct Controller {
pub id: i64,
pub uid: ControllerUid,
pub name: String,
pub relay_count: i64,
pub active: bool,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Periods(pub Vec<Period>);
impl Controller {
pub async fn get_all(
conn: &mut PoolConnection<Sqlite>,
) -> Result<Vec<Controller>, DatabaseError> {
Ok(sqlx::query_as!(Controller, "SELECT * FROM controllers")
.fetch_all(conn.deref_mut())
.await?)
}
pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: i64,
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"SELECT * FROM controllers WHERE id = ?",
id
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: &ControllerUid,
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"SELECT * FROM controllers WHERE uid = ?",
filter_uid
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>,
tag: &Tag,
) -> Result<Vec<Controller>, DatabaseError> {
Ok(sqlx::query_as!(Controller, "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id)
.fetch_all(conn.deref_mut())
.await?)
}
pub async fn delete_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: ControllerUid,
) -> Result<(), DatabaseError> {
sqlx::query!("DELETE FROM controllers WHERE uid = ?", filter_uid)
.execute(conn.deref_mut())
.await
.map(|res| match res.rows_affected() {
0 => Err(DatabaseError::DeleteError),
_ => Ok(()),
})?
}
pub async fn create(
conn: &mut PoolConnection<Sqlite>,
new_uid: &ControllerUid,
new_name: &str,
new_relay_count: i64,
new_active: bool
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"INSERT INTO controllers (uid, name, relay_count, active) VALUES (?, ?, ?, ?) RETURNING *",
new_uid,
new_name,
new_relay_count,
new_active,
)
.fetch_optional(conn.deref_mut())
.await?
.ok_or(DatabaseError::InsertGetError)
}
pub async fn update(
&self,
conn: &mut PoolConnection<Sqlite>,
new_name: &str,
new_relay_count: i64,
new_active: bool
) -> Result<Controller, DatabaseError> {
sqlx::query!(
"UPDATE controllers SET name = ?, relay_count = ?, active = ? WHERE id = ?",
new_name,
new_relay_count,
new_active,
self.id,
)
.execute(conn.deref_mut())
.await?;
Controller::get_by_uid(conn, &self.uid).await
}
}

View file

@ -6,17 +6,18 @@ use std::str::FromStr;
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period; use crate::db::model_utils::Period;
use crate::db::types::EmgauwaUid; use crate::db::types::ScheduleUid;
// export for easier/flatter access // export for easier/flatter access
pub use crate::db::schedules::{Periods, Schedule}; pub use crate::db::schedules::{Periods, Schedule};
pub(crate) mod errors; pub mod errors;
mod model_utils; mod model_utils;
mod models; mod models;
pub(crate) mod schedules; pub mod schedules;
pub(crate) mod tag; pub mod tag;
pub mod types; pub mod types;
pub mod controllers;
static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations" static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
@ -27,7 +28,7 @@ pub async fn run_migrations(pool: &Pool<Sqlite>) {
async fn init_schedule( async fn init_schedule(
pool: &Pool<Sqlite>, pool: &Pool<Sqlite>,
uid: &EmgauwaUid, uid: &ScheduleUid,
name: &str, name: &str,
periods: Periods, periods: Periods,
) -> Result<(), DatabaseError> { ) -> Result<(), DatabaseError> {
@ -68,13 +69,13 @@ pub async fn init(db: &str) -> Pool<Sqlite> {
run_migrations(&pool).await; run_migrations(&pool).await;
init_schedule(&pool, &EmgauwaUid::Off, "Off", Periods(vec![])) init_schedule(&pool, &ScheduleUid::Off, "Off", Periods(vec![]))
.await .await
.expect("Error initializing schedule Off"); .expect("Error initializing schedule Off");
init_schedule( init_schedule(
&pool, &pool,
&EmgauwaUid::On, &ScheduleUid::On,
"On", "On",
Periods(vec![Period::new_on()]), Periods(vec![Period::new_on()]),
) )

View file

@ -8,14 +8,14 @@ use sqlx::Sqlite;
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period; use crate::db::model_utils::Period;
use crate::db::tag::Tag; use crate::db::tag::Tag;
use crate::db::types::EmgauwaUid; use crate::db::types::ScheduleUid;
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
pub struct Schedule { pub struct Schedule {
#[serde(skip)] #[serde(skip)]
pub id: i64, pub id: i64,
#[serde(rename(serialize = "id"))] #[serde(rename(serialize = "id"))]
pub uid: EmgauwaUid, pub uid: ScheduleUid,
pub name: String, pub name: String,
pub periods: Periods, pub periods: Periods,
} }
@ -32,9 +32,23 @@ impl Schedule {
.await?) .await?)
} }
pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: &i64,
) -> Result<Schedule, DatabaseError> {
sqlx::query_as!(
Schedule,
"SELECT * FROM schedules WHERE id = ?",
id
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_uid( pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
filter_uid: &EmgauwaUid, filter_uid: &ScheduleUid,
) -> Result<Schedule, DatabaseError> { ) -> Result<Schedule, DatabaseError> {
sqlx::query_as!( sqlx::query_as!(
Schedule, Schedule,
@ -57,12 +71,12 @@ impl Schedule {
pub async fn delete_by_uid( pub async fn delete_by_uid(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
filter_uid: EmgauwaUid, filter_uid: ScheduleUid,
) -> Result<(), DatabaseError> { ) -> Result<(), DatabaseError> {
let filter_uid = match filter_uid { let filter_uid = match filter_uid {
EmgauwaUid::Off => Err(DatabaseError::Protected), ScheduleUid::Off => Err(DatabaseError::Protected),
EmgauwaUid::On => Err(DatabaseError::Protected), ScheduleUid::On => Err(DatabaseError::Protected),
EmgauwaUid::Any(_) => Ok(filter_uid), ScheduleUid::Any(_) => Ok(filter_uid),
}?; }?;
sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid) sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid)
@ -79,7 +93,7 @@ impl Schedule {
new_name: &str, new_name: &str,
new_periods: &Periods, new_periods: &Periods,
) -> Result<Schedule, DatabaseError> { ) -> Result<Schedule, DatabaseError> {
let uid = EmgauwaUid::default(); let uid = ScheduleUid::default();
sqlx::query_as!( sqlx::query_as!(
Schedule, Schedule,
"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
@ -100,8 +114,8 @@ impl Schedule {
) -> Result<Schedule, DatabaseError> { ) -> Result<Schedule, DatabaseError> {
// overwrite periods on protected schedules // overwrite periods on protected schedules
let new_periods = match self.uid { let new_periods = match self.uid {
EmgauwaUid::Off | EmgauwaUid::On => self.periods.borrow(), ScheduleUid::Off | ScheduleUid::On => self.periods.borrow(),
EmgauwaUid::Any(_) => new_periods, ScheduleUid::Any(_) => new_periods,
}; };
sqlx::query!( sqlx::query!(

View file

@ -37,6 +37,16 @@ impl Tag {
} }
pub async fn get( pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: i64,
) -> Result<Tag, DatabaseError> {
sqlx::query_as!(Tag, "SELECT * FROM tags WHERE id = ?", id)
.fetch_optional(conn.deref_mut())
.await
.map(|t| t.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
target_tag: &str, target_tag: &str,
) -> Result<Tag, DatabaseError> { ) -> Result<Tag, DatabaseError> {

View file

@ -0,0 +1,62 @@
use serde::{Serialize, Serializer};
use sqlx::{Decode, Encode, Sqlite, Type};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use uuid::Uuid;
#[derive(Clone, Debug)]
pub struct ControllerUid(Uuid);
impl Serialize for ControllerUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<&ControllerUid> for String {
fn from(uid: &ControllerUid) -> String {
uid.0.as_hyphenated().to_string()
}
}
impl Type<Sqlite> for ControllerUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for ControllerUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
let uuid_val = self.0.as_bytes().to_vec();
<&Vec<u8> as Encode<Sqlite>>::encode(&uuid_val, buf)
}
}
impl<'r> Decode<'r, Sqlite> for ControllerUid {
//noinspection DuplicatedCode
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl From<&[u8]> for ControllerUid {
fn from(value: &[u8]) -> Self {
Self(Uuid::from_slice(&value).unwrap())
}
}
impl From<Vec<u8>> for ControllerUid {
fn from(value: Vec<u8>) -> Self {
Self::from(value.as_slice())
}
}

View file

@ -1,146 +0,0 @@
use std::convert::TryFrom;
use std::fmt::{Debug, Formatter};
use std::str::FromStr;
use serde::{Serialize, Serializer};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use sqlx::{Decode, Encode, Sqlite, Type};
use uuid::Uuid;
#[derive(Clone)]
pub enum EmgauwaUid {
Off,
On,
Any(Uuid),
}
impl EmgauwaUid {
const OFF_STR: &'static str = "off";
const ON_STR: &'static str = "on";
const OFF_U8: u8 = 0;
const ON_U8: u8 = 1;
const OFF_U128: u128 = 0;
const ON_U128: u128 = 1;
}
impl Default for EmgauwaUid {
fn default() -> Self {
EmgauwaUid::Any(Uuid::new_v4())
}
}
impl Debug for EmgauwaUid {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
EmgauwaUid::Off => EmgauwaUid::OFF_STR.fmt(f),
EmgauwaUid::On => EmgauwaUid::ON_STR.fmt(f),
EmgauwaUid::Any(value) => value.fmt(f),
}
}
}
impl Type<Sqlite> for EmgauwaUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for EmgauwaUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
}
}
impl<'r> Decode<'r, Sqlite> for EmgauwaUid {
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(EmgauwaUid::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl Serialize for EmgauwaUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<Uuid> for EmgauwaUid {
fn from(uid: Uuid) -> EmgauwaUid {
match uid.as_u128() {
EmgauwaUid::OFF_U128 => EmgauwaUid::Off,
EmgauwaUid::ON_U128 => EmgauwaUid::On,
_ => EmgauwaUid::Any(uid),
}
}
}
impl TryFrom<&str> for EmgauwaUid {
type Error = uuid::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
EmgauwaUid::OFF_STR => Ok(EmgauwaUid::Off),
EmgauwaUid::ON_STR => Ok(EmgauwaUid::On),
any => match Uuid::from_str(any) {
Ok(uuid) => Ok(EmgauwaUid::Any(uuid)),
Err(err) => Err(err),
},
}
}
}
impl From<&EmgauwaUid> for Uuid {
fn from(emgauwa_uid: &EmgauwaUid) -> Uuid {
match emgauwa_uid {
EmgauwaUid::Off => Uuid::from_u128(EmgauwaUid::OFF_U128),
EmgauwaUid::On => Uuid::from_u128(EmgauwaUid::ON_U128),
EmgauwaUid::Any(value) => *value,
}
}
}
impl From<&EmgauwaUid> for String {
fn from(emgauwa_uid: &EmgauwaUid) -> String {
match emgauwa_uid {
EmgauwaUid::Off => String::from(EmgauwaUid::OFF_STR),
EmgauwaUid::On => String::from(EmgauwaUid::ON_STR),
EmgauwaUid::Any(value) => value.as_hyphenated().to_string(),
}
}
}
impl From<&EmgauwaUid> for Vec<u8> {
fn from(emgauwa_uid: &EmgauwaUid) -> Vec<u8> {
match emgauwa_uid {
EmgauwaUid::Off => vec![EmgauwaUid::OFF_U8],
EmgauwaUid::On => vec![EmgauwaUid::ON_U8],
EmgauwaUid::Any(value) => value.as_bytes().to_vec(),
}
}
}
impl From<&[u8]> for EmgauwaUid {
fn from(value: &[u8]) -> Self {
match value {
[EmgauwaUid::OFF_U8] => EmgauwaUid::Off,
[EmgauwaUid::ON_U8] => EmgauwaUid::On,
value_bytes => EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap()),
}
}
}
impl From<Vec<u8>> for EmgauwaUid {
fn from(value: Vec<u8>) -> Self {
EmgauwaUid::from(value.as_slice())
}
}

View file

@ -1,2 +1,5 @@
pub mod emgauwa_uid; mod schedule_uid;
pub use emgauwa_uid::EmgauwaUid; mod controller_uid;
pub use schedule_uid::ScheduleUid;
pub use controller_uid::ControllerUid;

View file

@ -0,0 +1,147 @@
use std::convert::TryFrom;
use std::fmt::{Debug, Formatter};
use std::str::FromStr;
use serde::{Serialize, Serializer};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use sqlx::{Decode, Encode, Sqlite, Type};
use uuid::Uuid;
#[derive(Clone)]
pub enum ScheduleUid {
Off,
On,
Any(Uuid),
}
impl ScheduleUid {
const OFF_STR: &'static str = "off";
const ON_STR: &'static str = "on";
const OFF_U8: u8 = 0;
const ON_U8: u8 = 1;
const OFF_U128: u128 = 0;
const ON_U128: u128 = 1;
}
impl Default for ScheduleUid {
fn default() -> Self {
Self::Any(Uuid::new_v4())
}
}
impl Debug for ScheduleUid {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Off => Self::OFF_STR.fmt(f),
Self::On => Self::ON_STR.fmt(f),
Self::Any(value) => value.fmt(f),
}
}
}
impl Type<Sqlite> for ScheduleUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for ScheduleUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
}
}
impl<'r> Decode<'r, Sqlite> for ScheduleUid {
//noinspection DuplicatedCode
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl Serialize for ScheduleUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<Uuid> for ScheduleUid {
fn from(uid: Uuid) -> Self {
match uid.as_u128() {
Self::OFF_U128 => Self::Off,
Self::ON_U128 => Self::On,
_ => Self::Any(uid),
}
}
}
impl TryFrom<&str> for ScheduleUid {
type Error = uuid::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
Self::OFF_STR => Ok(Self::Off),
Self::ON_STR => Ok(Self::On),
any => match Uuid::from_str(any) {
Ok(uuid) => Ok(Self::Any(uuid)),
Err(err) => Err(err),
},
}
}
}
impl From<&ScheduleUid> for Uuid {
fn from(uid: &ScheduleUid) -> Uuid {
match uid {
ScheduleUid::Off => Uuid::from_u128(ScheduleUid::OFF_U128),
ScheduleUid::On => Uuid::from_u128(ScheduleUid::ON_U128),
ScheduleUid::Any(value) => *value,
}
}
}
impl From<&ScheduleUid> for String {
fn from(uid: &ScheduleUid) -> String {
match uid {
ScheduleUid::Off => String::from(ScheduleUid::OFF_STR),
ScheduleUid::On => String::from(ScheduleUid::ON_STR),
ScheduleUid::Any(value) => value.as_hyphenated().to_string(),
}
}
}
impl From<&ScheduleUid> for Vec<u8> {
fn from(uid: &ScheduleUid) -> Vec<u8> {
match uid {
ScheduleUid::Off => vec![ScheduleUid::OFF_U8],
ScheduleUid::On => vec![ScheduleUid::ON_U8],
ScheduleUid::Any(value) => value.as_bytes().to_vec(),
}
}
}
impl From<&[u8]> for ScheduleUid {
fn from(value: &[u8]) -> Self {
match value {
[Self::OFF_U8] => Self::Off,
[Self::ON_U8] => Self::On,
value_bytes => Self::Any(Uuid::from_slice(value_bytes).unwrap()),
}
}
}
impl From<Vec<u8>> for ScheduleUid {
fn from(value: Vec<u8>) -> Self {
Self::from(value.as_slice())
}
}

View file

@ -6,7 +6,7 @@ use sqlx::{Pool, Sqlite};
use crate::db::errors::DatabaseError; use crate::db::errors::DatabaseError;
use crate::db::{Periods, Schedule}; use crate::db::{Periods, Schedule};
use crate::db::tag::Tag; use crate::db::tag::Tag;
use crate::db::types::EmgauwaUid; use crate::db::types::ScheduleUid;
use crate::handlers::errors::ApiError; use crate::handlers::errors::ApiError;
use crate::return_models::ReturnSchedule; use crate::return_models::ReturnSchedule;
use crate::utils::vec_has_error; use crate::utils::vec_has_error;
@ -41,7 +41,7 @@ pub async fn tagged(
let mut pool_conn = pool.acquire().await?; let mut pool_conn = pool.acquire().await?;
let (tag,) = path.into_inner(); let (tag,) = path.into_inner();
let tag_db = Tag::get(&mut pool_conn, &tag).await?; let tag_db = Tag::get_by_tag(&mut pool_conn, &tag).await?;
let schedules = Schedule::get_by_tag(&mut pool_conn, &tag_db).await?; let schedules = Schedule::get_by_tag(&mut pool_conn, &tag_db).await?;
@ -61,9 +61,9 @@ pub async fn show(
let mut pool_conn = pool.acquire().await?; let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner(); let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &emgauwa_uid).await?; let schedule = Schedule::get_by_uid(&mut pool_conn, &uid).await?;
let mut return_schedule = ReturnSchedule::from(schedule); let mut return_schedule = ReturnSchedule::from(schedule);
return_schedule.load_tags(&mut pool_conn); return_schedule.load_tags(&mut pool_conn);
@ -148,9 +148,9 @@ pub async fn update(
let mut pool_conn = pool.acquire().await?; let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner(); let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &emgauwa_uid).await?; let schedule = Schedule::get_by_uid(&mut pool_conn, &uid).await?;
let schedule = schedule let schedule = schedule
.update(&mut pool_conn, data.name.as_str(), &data.periods) .update(&mut pool_conn, data.name.as_str(), &data.periods)
@ -173,13 +173,13 @@ pub async fn delete(
let mut pool_conn = pool.acquire().await?; let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner(); let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?; let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
match emgauwa_uid { match uid {
EmgauwaUid::Off => Err(ApiError::ProtectedSchedule), ScheduleUid::Off => Err(ApiError::ProtectedSchedule),
EmgauwaUid::On => Err(ApiError::ProtectedSchedule), ScheduleUid::On => Err(ApiError::ProtectedSchedule),
EmgauwaUid::Any(_) => { ScheduleUid::Any(_) => {
Schedule::delete_by_uid(&mut pool_conn, emgauwa_uid).await?; Schedule::delete_by_uid(&mut pool_conn, uid).await?;
Ok(HttpResponse::Ok().json("schedule got deleted")) Ok(HttpResponse::Ok().json("schedule got deleted"))
} }
} }

View file

@ -6,18 +6,15 @@ CREATE TABLE controllers
AUTOINCREMENT AUTOINCREMENT
NOT NULL, NOT NULL,
uid uid
VARCHAR(36) BLOB
NOT NULL NOT NULL
UNIQUE, UNIQUE,
name name
VARCHAR(128) VARCHAR(128)
NOT NULL, NOT NULL,
ip
VARCHAR(16),
port
INTEGER,
relay_count relay_count
INTEGER, INTEGER
NOT NULL,
active active
BOOLEAN BOOLEAN
NOT NULL NOT NULL