-
Notifications
You must be signed in to change notification settings - Fork 1
Add DELETE /api/v0/pipeline-nodes/:id with transactions, error handli… #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| use axum::{extract::Path, Json}; | ||
| use hyper::StatusCode; | ||
| use serde::{Deserialize, Serialize}; | ||
| use serde_json::json; | ||
| use tracing::info; | ||
| use uuid::Uuid; | ||
| use sqlx::Acquire; | ||
|
|
||
| use crate::{ | ||
| app_state::{Coords, DatabaseConnection}, | ||
|
|
@@ -49,6 +52,60 @@ pub struct PipelineNodeCreationParams { | |
| coords: Coords, | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize)] | ||
| struct ApiError { | ||
| error: String, | ||
| } | ||
|
|
||
| impl From<sqlx::Error> for ApiError { | ||
| fn from(err: sqlx::Error) -> Self { | ||
| ApiError { | ||
| error: err.to_string(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub async fn delete( | ||
| DatabaseConnection(mut conn): DatabaseConnection, | ||
| Path(id): Path<Uuid>, | ||
| ) -> Result<StatusCode, (StatusCode, Json<ApiError>)> { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the return type will conflict with what internal_error will return |
||
| info!("Attempting to delete pipeline node: {id}"); | ||
|
|
||
| let mut tx = conn | ||
| .begin() | ||
patchwork-body marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .await | ||
| .map_err(internal_error)?; | ||
|
|
||
| // Check if node exists | ||
| let node_exists = sqlx::query!("SELECT id FROM pipeline_nodes WHERE id = $1", id) | ||
| .fetch_optional(&mut *tx) | ||
| .await | ||
| .map_err(internal_error)? | ||
| .is_some(); | ||
|
|
||
| if !node_exists { | ||
| return Err(( | ||
| StatusCode::NOT_FOUND, | ||
| Json(ApiError { | ||
| error: "Pipeline node not found".to_string(), | ||
| }), | ||
| )); | ||
| } | ||
|
|
||
| // Delete the node (dependencies handled by ON DELETE CASCADE) | ||
| sqlx::query!("DELETE FROM pipeline_nodes WHERE id = $1", id) | ||
| .execute(&mut *tx) | ||
| .await | ||
| .map_err(internal_error)?; | ||
|
|
||
| tx.commit() | ||
| .await | ||
| .map_err(internal_error)?; | ||
|
|
||
| info!("Successfully deleted pipeline node: {id}"); | ||
| Ok(StatusCode::NO_CONTENT) | ||
| } | ||
|
|
||
| pub async fn create( | ||
| DatabaseConnection(mut conn): DatabaseConnection, | ||
| Json(payload): Json<PipelineNodeCreationParams>, | ||
|
|
@@ -163,3 +220,59 @@ pub async fn update( | |
| outputs: vec![], | ||
| })) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to erase tests for now, we'll deal with that later on |
||
| mod tests { | ||
| use super::*; | ||
| use sqlx::PgPool; | ||
|
|
||
| #[tokio::test] | ||
| async fn test_delete_pipeline_node_success() { | ||
| // Replace with your test database URL | ||
| let pool = PgPool::connect("postgres://user:pass@localhost/test_db") | ||
| .await | ||
| .unwrap(); | ||
| let mut conn = DatabaseConnection(pool.acquire().await.unwrap()); | ||
|
|
||
| // Insert test data | ||
| let id = Uuid::new_v4(); | ||
patchwork-body marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| sqlx::query!( | ||
| "INSERT INTO pipeline_nodes (id, pipeline_id, node_id, node_version, coords) VALUES ($1, $2, $3, $4, $5)", | ||
| id, | ||
| Uuid::new_v4, | ||
| Uuid::new_v4, | ||
| "1.0", | ||
| serde_json::json!({"x": 0, "y": 0}) | ||
| ) | ||
| .execute(&mut *conn.0) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| // Delete the node | ||
| let result = delete(conn, Path(id)).await; | ||
| assert!(matches!(result, Ok(StatusCode::NO_CONTENT))); | ||
|
|
||
| // Verify deletion | ||
| let exists = sqlx::query!("SELECT id FROM pipeline_nodes WHERE id = $1", id) | ||
| .fetch_optional(&mut *pool.acquire().await.unwrap()) | ||
| .await | ||
| .unwrap() | ||
| .is_none(); | ||
| assert!(exists); | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_delete_pipeline_node_not_found() { | ||
| let pool = PgPool::connect("postgres://user:pass@localhost/test_db") | ||
| .await | ||
| .unwrap(); | ||
| let conn = DatabaseConnection(pool.acquire().await.unwrap()); | ||
|
|
||
| let id = Uuid::new_v4(); | ||
| let result = delete(conn, Path(id)).await; | ||
| assert!(matches!( | ||
| result, | ||
| Err((StatusCode::NOT_FOUND, _)) | ||
| )); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused import 🤔