Improve tag endpoint

This commit is contained in:
Tobias Reisinger 2024-04-19 18:21:14 +02:00
parent 8215461e0d
commit bb76e3db4d
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
7 changed files with 147 additions and 12 deletions

View file

@ -443,6 +443,10 @@ paths:
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/tag_full'
'400':
description: Bad Request
requestBody:
@ -474,16 +478,7 @@ paths:
content:
application/json:
schema:
type: object
properties:
relays:
type: array
items:
$ref: '#/components/schemas/relay'
schedules:
type: array
items:
$ref: '#/components/schemas/schedule'
$ref: '#/components/schemas/tag_full'
'404':
description: Not Found
operationId: get-tags-tag
@ -822,6 +817,20 @@ components:
type: string
title: tag
example: sprinkler
tag_full:
title: tag (full)
type: object
properties:
tag:
$ref: '#/components/schemas/tag'
relays:
type: array
items:
$ref: '#/components/schemas/relay'
schedules:
type: array
items:
$ref: '#/components/schemas/schedule'
schedule_id:
type: string
title: schedule_id

View file

@ -1,6 +1,8 @@
use actix_web::{get, web, HttpResponse};
use actix_web::{delete, get, post, web, HttpResponse};
use emgauwa_lib::db::DbTag;
use emgauwa_lib::errors::EmgauwaError;
use emgauwa_lib::errors::{DatabaseError, EmgauwaError};
use emgauwa_lib::models::{FromDbModel, Tag};
use emgauwa_lib::types::RequestCreateTag;
use sqlx::{Pool, Sqlite};
#[get("/api/v1/tags")]
@ -13,3 +15,47 @@ pub async fn index(pool: web::Data<Pool<Sqlite>>) -> Result<HttpResponse, Emgauw
Ok(HttpResponse::Ok().json(tags))
}
#[get("/api/v1/tags/{tag_name}")]
pub async fn show(
pool: web::Data<Pool<Sqlite>>,
path: web::Path<(String,)>,
) -> Result<HttpResponse, EmgauwaError> {
let mut pool_conn = pool.acquire().await?;
let (tag_name,) = path.into_inner();
let tag = DbTag::get_by_tag(&mut pool_conn, &tag_name)
.await?
.ok_or(DatabaseError::NotFound)?;
let return_tag = Tag::from_db_model(&mut pool_conn, tag)?;
Ok(HttpResponse::Ok().json(return_tag))
}
#[delete("/api/v1/tags/{tag_name}")]
pub async fn delete(
pool: web::Data<Pool<Sqlite>>,
path: web::Path<(String,)>,
) -> Result<HttpResponse, EmgauwaError> {
let mut pool_conn = pool.acquire().await?;
let (tag_name,) = path.into_inner();
DbTag::delete_by_tag(&mut pool_conn, &tag_name).await?;
Ok(HttpResponse::Ok().json("tag got deleted"))
}
#[post("/api/v1/tags")]
pub async fn add(
pool: web::Data<Pool<Sqlite>>,
data: web::Json<RequestCreateTag>,
) -> Result<HttpResponse, EmgauwaError> {
let mut pool_conn = pool.acquire().await?;
let new_tag = DbTag::create(&mut pool_conn, &data.tag).await?;
let cache = (Vec::new(), Vec::new()); // a new tag can't have any relays or schedules
let return_tag = Tag::from_db_model_cache(&mut pool_conn, new_tag, cache)?;
Ok(HttpResponse::Created().json(return_tag))
}

View file

@ -85,6 +85,9 @@ async fn main() -> Result<(), std::io::Error> {
.service(handlers::v1::schedules::update)
.service(handlers::v1::schedules::delete)
.service(handlers::v1::tags::index)
.service(handlers::v1::tags::show)
.service(handlers::v1::tags::delete)
.service(handlers::v1::tags::add)
.service(handlers::v1::ws::ws_controllers)
})
.listen(listener)?

View file

@ -63,4 +63,25 @@ impl DbTag {
.await
.map_err(DatabaseError::from)
}
pub async fn delete_by_tag(
conn: &mut PoolConnection<Sqlite>,
filter_tag: &str,
) -> Result<(), DatabaseError> {
if sqlx::query_scalar!("SELECT 1 FROM tags WHERE tag = ?", filter_tag)
.fetch_optional(conn.deref_mut())
.await?
.is_none()
{
return Err(DatabaseError::NotFound);
}
sqlx::query!("DELETE FROM tags WHERE tag = ?", filter_tag)
.execute(conn.deref_mut())
.await
.map(|res| match res.rows_affected() {
0 => Err(DatabaseError::DeleteError),
_ => Ok(()),
})?
}
}

View file

@ -1,12 +1,14 @@
mod controller;
mod relay;
mod schedule;
mod tag;
pub use controller::Controller;
pub use relay::Relay;
pub use schedule::Schedule;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
pub use tag::Tag;
use crate::errors::DatabaseError;

View file

@ -0,0 +1,49 @@
use actix::MessageResponse;
use futures::executor::block_on;
use serde_derive::{Deserialize, Serialize};
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use crate::db::{DbRelay, DbSchedule, DbTag};
use crate::errors::DatabaseError;
use crate::models::{convert_db_list, FromDbModel, Relay, Schedule};
#[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)]
pub struct Tag {
pub tag: String,
pub relays: Vec<Relay>,
pub schedules: Vec<Schedule>,
}
impl FromDbModel for Tag {
type DbModel = DbTag;
type DbModelCache = (Vec<Relay>, Vec<Schedule>);
fn from_db_model(
conn: &mut PoolConnection<Sqlite>,
db_model: Self::DbModel,
) -> Result<Self, DatabaseError> {
let db_schedules = block_on(DbSchedule::get_by_tag(conn, &db_model))?;
let schedules: Vec<Schedule> = convert_db_list(conn, db_schedules)?;
let db_relays = block_on(DbRelay::get_by_tag(conn, &db_model))?;
let relays: Vec<Relay> = convert_db_list(conn, db_relays)?;
let cache = (relays, schedules);
Self::from_db_model_cache(conn, db_model, cache)
}
fn from_db_model_cache(
_conn: &mut PoolConnection<Sqlite>,
db_model: Self::DbModel,
cache: Self::DbModelCache,
) -> Result<Self, DatabaseError> {
let tag = db_model.tag.clone();
let (relays, schedules) = cache;
Ok(Tag {
tag,
relays,
schedules,
})
}
}

View file

@ -38,6 +38,11 @@ pub struct RequestUpdateController {
pub name: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RequestCreateTag {
pub tag: String,
}
impl RequestScheduleId {
pub async fn get_schedule(
&self,