Improve tag endpoint
This commit is contained in:
		
							parent
							
								
									8215461e0d
								
							
						
					
					
						commit
						bb76e3db4d
					
				
					 7 changed files with 147 additions and 12 deletions
				
			
		
							
								
								
									
										29
									
								
								api.v1.yaml
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								api.v1.yaml
									
										
									
									
									
								
							| 
						 | 
					@ -443,6 +443,10 @@ paths:
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        '201':
 | 
					        '201':
 | 
				
			||||||
          description: Created
 | 
					          description: Created
 | 
				
			||||||
 | 
					          content:
 | 
				
			||||||
 | 
					            application/json:
 | 
				
			||||||
 | 
					              schema:
 | 
				
			||||||
 | 
					                $ref: '#/components/schemas/tag_full'
 | 
				
			||||||
        '400':
 | 
					        '400':
 | 
				
			||||||
          description: Bad Request
 | 
					          description: Bad Request
 | 
				
			||||||
      requestBody:
 | 
					      requestBody:
 | 
				
			||||||
| 
						 | 
					@ -474,16 +478,7 @@ paths:
 | 
				
			||||||
          content:
 | 
					          content:
 | 
				
			||||||
            application/json:
 | 
					            application/json:
 | 
				
			||||||
              schema:
 | 
					              schema:
 | 
				
			||||||
                type: object
 | 
					                $ref: '#/components/schemas/tag_full'
 | 
				
			||||||
                properties:
 | 
					 | 
				
			||||||
                  relays:
 | 
					 | 
				
			||||||
                    type: array
 | 
					 | 
				
			||||||
                    items:
 | 
					 | 
				
			||||||
                      $ref: '#/components/schemas/relay'
 | 
					 | 
				
			||||||
                  schedules:
 | 
					 | 
				
			||||||
                    type: array
 | 
					 | 
				
			||||||
                    items:
 | 
					 | 
				
			||||||
                      $ref: '#/components/schemas/schedule'
 | 
					 | 
				
			||||||
        '404':
 | 
					        '404':
 | 
				
			||||||
          description: Not Found
 | 
					          description: Not Found
 | 
				
			||||||
      operationId: get-tags-tag
 | 
					      operationId: get-tags-tag
 | 
				
			||||||
| 
						 | 
					@ -822,6 +817,20 @@ components:
 | 
				
			||||||
      type: string
 | 
					      type: string
 | 
				
			||||||
      title: tag
 | 
					      title: tag
 | 
				
			||||||
      example: sprinkler
 | 
					      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:
 | 
					    schedule_id:
 | 
				
			||||||
      type: string
 | 
					      type: string
 | 
				
			||||||
      title: schedule_id
 | 
					      title: schedule_id
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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::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};
 | 
					use sqlx::{Pool, Sqlite};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[get("/api/v1/tags")]
 | 
					#[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))
 | 
						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))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,6 +85,9 @@ async fn main() -> Result<(), std::io::Error> {
 | 
				
			||||||
			.service(handlers::v1::schedules::update)
 | 
								.service(handlers::v1::schedules::update)
 | 
				
			||||||
			.service(handlers::v1::schedules::delete)
 | 
								.service(handlers::v1::schedules::delete)
 | 
				
			||||||
			.service(handlers::v1::tags::index)
 | 
								.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)
 | 
								.service(handlers::v1::ws::ws_controllers)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	.listen(listener)?
 | 
						.listen(listener)?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,4 +63,25 @@ impl DbTag {
 | 
				
			||||||
			.await
 | 
								.await
 | 
				
			||||||
			.map_err(DatabaseError::from)
 | 
								.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(()),
 | 
				
			||||||
 | 
								})?
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,14 @@
 | 
				
			||||||
mod controller;
 | 
					mod controller;
 | 
				
			||||||
mod relay;
 | 
					mod relay;
 | 
				
			||||||
mod schedule;
 | 
					mod schedule;
 | 
				
			||||||
 | 
					mod tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use controller::Controller;
 | 
					pub use controller::Controller;
 | 
				
			||||||
pub use relay::Relay;
 | 
					pub use relay::Relay;
 | 
				
			||||||
pub use schedule::Schedule;
 | 
					pub use schedule::Schedule;
 | 
				
			||||||
use sqlx::pool::PoolConnection;
 | 
					use sqlx::pool::PoolConnection;
 | 
				
			||||||
use sqlx::Sqlite;
 | 
					use sqlx::Sqlite;
 | 
				
			||||||
 | 
					pub use tag::Tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::errors::DatabaseError;
 | 
					use crate::errors::DatabaseError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								emgauwa-lib/src/models/tag.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								emgauwa-lib/src/models/tag.rs
									
										
									
									
									
										Normal 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,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,11 @@ pub struct RequestUpdateController {
 | 
				
			||||||
	pub name: String,
 | 
						pub name: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct RequestCreateTag {
 | 
				
			||||||
 | 
						pub tag: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl RequestScheduleId {
 | 
					impl RequestScheduleId {
 | 
				
			||||||
	pub async fn get_schedule(
 | 
						pub async fn get_schedule(
 | 
				
			||||||
		&self,
 | 
							&self,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue