feat: add import execution api

This commit is contained in:
2026-06-24 09:55:47 +08:00
parent a770070b34
commit e5d95c0598
9 changed files with 584 additions and 13 deletions

View File

@@ -3,13 +3,14 @@ use axum::Json;
use serde::Serialize;
use crate::error::{ApiError, ApiResult};
use crate::import_templates::validate_import_payload;
use crate::import_templates::{execute_import_payload, validate_import_payload};
use crate::models::{
AreaScore, AreaScoreSummary, CreateDataSource, CreateIngestionRun, CreateRawArtifact,
CreateWatchlistItem, DataSource, FinishIngestionRun, ImportValidationRequest,
ImportValidationResponse, IngestionRun, IngestionRunQuery, MarketOverview, MonthQuery,
Neighborhood, NeighborhoodQuery, NeighborhoodScore, NeighborhoodScoreQuery, RawArtifact,
RawArtifactQuery, UpdateWatchlistItem, WatchlistItem,
CreateWatchlistItem, DataSource, FinishIngestionRun, ImportExecutionRequest,
ImportExecutionResponse, ImportValidationRequest, ImportValidationResponse, IngestionRun,
IngestionRunQuery, MarketOverview, MonthQuery, Neighborhood, NeighborhoodQuery,
NeighborhoodScore, NeighborhoodScoreQuery, RawArtifact, RawArtifactQuery, UpdateWatchlistItem,
WatchlistItem,
};
use crate::state::AppState;
@@ -41,6 +42,54 @@ pub async fn validate_import(
Ok(Json(result))
}
pub async fn execute_import(
State(state): State<AppState>,
Json(payload): Json<ImportExecutionRequest>,
) -> ApiResult<Json<ImportExecutionResponse>> {
let mut tx = state.pool.begin().await?;
let result = execute_import_payload(&mut tx, &payload).await;
match result {
Ok(response) => {
sqlx::query(
r#"
UPDATE audit.ingestion_runs
SET status = 'succeeded',
finished_at = now(),
row_count = $2,
raw_artifact_id = $3,
error_message = NULL
WHERE run_id = $1
"#,
)
.bind(payload.run_id)
.bind(response.row_count as i32)
.bind(payload.raw_artifact_id)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(response))
}
Err(message) => {
tx.rollback().await?;
sqlx::query(
r#"
UPDATE audit.ingestion_runs
SET status = 'failed',
finished_at = now(),
error_message = $2
WHERE run_id = $1
"#,
)
.bind(payload.run_id)
.bind(message.clone())
.execute(&state.pool)
.await?;
Err(ApiError::BadRequest(message))
}
}
}
pub async fn list_area_scores(
State(state): State<AppState>,
Query(query): Query<MonthQuery>,