|
| 1 | +use std::sync::Arc; |
| 2 | + |
| 3 | +use axum::{ |
| 4 | + Router, |
| 5 | + extract::Query, |
| 6 | + response::Json, |
| 7 | + routing::get, |
| 8 | +}; |
| 9 | +use sdf_core::app_state::AppState; |
| 10 | +use sdf_extract::{ |
| 11 | + FriggStore, |
| 12 | + change_set::ChangeSetAuthorization, |
| 13 | +}; |
| 14 | +use serde::{ |
| 15 | + Deserialize, |
| 16 | + Serialize, |
| 17 | +}; |
| 18 | +use serde_json::json; |
| 19 | +use utoipa::{ |
| 20 | + self, |
| 21 | + ToSchema, |
| 22 | +}; |
| 23 | + |
| 24 | +use crate::{ |
| 25 | + extract::PosthogEventTracker, |
| 26 | + search::{ |
| 27 | + self, |
| 28 | + component::ComponentSearchResult, |
| 29 | + }, |
| 30 | + service::v1::ComponentsError, |
| 31 | +}; |
| 32 | + |
| 33 | +pub fn routes() -> Router<AppState> { |
| 34 | + Router::new().route("/", get(search)) |
| 35 | +} |
| 36 | + |
| 37 | +#[utoipa::path( |
| 38 | + post, |
| 39 | + path = "/v1/w/{workspace_id}/change-sets/{change_set_id}/search", |
| 40 | + params( |
| 41 | + ("workspace_id" = String, Path, description = "Workspace identifier"), |
| 42 | + ("change_set_id" = String, Path, description = "Change Set identifier"), |
| 43 | + ), |
| 44 | + request_body = SearchV1Request, |
| 45 | + summary = "Complex search for components", |
| 46 | + responses( |
| 47 | + (status = 200, description = "Components retrieved successfully", body = SearchV1Response), |
| 48 | + (status = 401, description = "Unauthorized - Invalid or missing token"), |
| 49 | + (status = 500, description = "Internal server error", body = crate::service::v1::common::ApiError) |
| 50 | + ) |
| 51 | +)] |
| 52 | +pub async fn search( |
| 53 | + FriggStore(ref frigg): FriggStore, |
| 54 | + ChangeSetAuthorization { |
| 55 | + workspace_id, |
| 56 | + change_set_id, |
| 57 | + .. |
| 58 | + }: ChangeSetAuthorization, |
| 59 | + tracker: PosthogEventTracker, |
| 60 | + Query(SearchV1Request { q }): Query<SearchV1Request>, |
| 61 | +) -> Result<Json<SearchV1Response>, ComponentsError> { |
| 62 | + let query = Arc::new(q.parse()?); |
| 63 | + let components = search::component::search(frigg, workspace_id, change_set_id, &query).await?; |
| 64 | + |
| 65 | + tracker.track_no_ctx( |
| 66 | + workspace_id, |
| 67 | + change_set_id, |
| 68 | + "api_search", |
| 69 | + json!({ |
| 70 | + "q": q, |
| 71 | + "components": components.len(), |
| 72 | + }), |
| 73 | + ); |
| 74 | + |
| 75 | + Ok(Json(SearchV1Response { components })) |
| 76 | +} |
| 77 | + |
| 78 | +#[derive(Deserialize, Serialize, Debug, ToSchema)] |
| 79 | +#[serde(rename_all = "camelCase")] |
| 80 | +pub struct SearchV1Request { |
| 81 | + #[schema(example = "AWS::EC2::Instance region:us-east-1")] |
| 82 | + pub q: String, |
| 83 | +} |
| 84 | + |
| 85 | +#[derive(Deserialize, Serialize, Debug, ToSchema)] |
| 86 | +#[serde(rename_all = "camelCase")] |
| 87 | +pub struct SearchV1Response { |
| 88 | + #[schema(example = json!(["01H9ZQD35JPMBGHH69BT0Q79AA", "01H9ZQD35JPMBGHH69BT0Q79BB", "01H9ZQD35JPMBGHH69BT0Q79CC"]))] |
| 89 | + pub components: Vec<ComponentSearchResult>, |
| 90 | +} |
0 commit comments