Persist map area selection exports
This commit is contained in:
@@ -16,6 +16,16 @@ router = APIRouter(prefix="/exports", tags=["exports"])
|
||||
|
||||
@router.post("/geojson", response_model=dict)
|
||||
def export_geojson(payload: GeoJsonExportRequest, db: Session = Depends(get_db)):
|
||||
if payload.export_kind == "vector_selection" and payload.dataset_id is not None and payload.bbox is not None:
|
||||
return envelope(
|
||||
ExportService.export_vector_selection_geojson(
|
||||
db,
|
||||
payload.dataset_id,
|
||||
payload.bbox.model_dump(),
|
||||
limit=payload.limit,
|
||||
name=payload.name,
|
||||
).model_dump(mode="json")
|
||||
)
|
||||
if payload.export_kind == "detection_run" and payload.analysis_run_id is not None:
|
||||
return envelope(
|
||||
ExportService.export_detection_run_geojson(db, payload.analysis_run_id, payload.name).model_dump(mode="json")
|
||||
|
||||
@@ -6,8 +6,10 @@ from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, model_validator
|
||||
|
||||
from app.schemas.operations import VectorSelectionBBox
|
||||
|
||||
ExportKind = Literal["dataset", "detection_run", "segmentation_run"]
|
||||
|
||||
ExportKind = Literal["dataset", "detection_run", "segmentation_run", "vector_selection"]
|
||||
|
||||
|
||||
class GeoJsonExportRequest(BaseModel):
|
||||
@@ -15,11 +17,18 @@ class GeoJsonExportRequest(BaseModel):
|
||||
analysis_run_id: UUID | None = None
|
||||
export_kind: ExportKind = "dataset"
|
||||
name: str | None = None
|
||||
bbox: VectorSelectionBBox | None = None
|
||||
limit: int = 250
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_target(self) -> "GeoJsonExportRequest":
|
||||
if self.export_kind == "dataset" and self.dataset_id is None:
|
||||
raise ValueError("dataset_id is required for dataset GeoJSON exports")
|
||||
if self.export_kind == "vector_selection":
|
||||
if self.dataset_id is None:
|
||||
raise ValueError("dataset_id is required for vector selection GeoJSON exports")
|
||||
if self.bbox is None:
|
||||
raise ValueError("bbox is required for vector selection GeoJSON exports")
|
||||
if self.export_kind in {"detection_run", "segmentation_run"} and self.analysis_run_id is None:
|
||||
raise ValueError("analysis_run_id is required for run GeoJSON exports")
|
||||
return self
|
||||
|
||||
@@ -16,9 +16,54 @@ from app.services.dataset_service import DatasetService
|
||||
from app.services.detection_service import DetectionService
|
||||
from app.services.segmentation_service import SegmentationService
|
||||
from app.services.storage_service import StorageService
|
||||
from app.services.vector_feature_service import VectorFeatureService
|
||||
|
||||
|
||||
class ExportService:
|
||||
@staticmethod
|
||||
def export_vector_selection_geojson(
|
||||
db: Session,
|
||||
dataset_id: uuid.UUID,
|
||||
bbox: dict[str, Any],
|
||||
limit: int = 250,
|
||||
name: str | None = None,
|
||||
) -> ExportCreateResponse:
|
||||
dataset = db.get(Dataset, dataset_id)
|
||||
if not dataset:
|
||||
raise AppError(code="DATASET_NOT_FOUND", message="Dataset not found", status_code=404)
|
||||
if dataset.dataset_type not in DatasetService.VECTOR_TYPES:
|
||||
raise AppError(
|
||||
code="INVALID_DATASET_TYPE",
|
||||
message="Vector selection export requires a vector dataset",
|
||||
details={"dataset_type": dataset.dataset_type},
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
selection = VectorFeatureService.select_features_by_bbox(db, dataset_id=dataset_id, bbox=bbox, limit=limit)
|
||||
filename = ExportService._filename(name, f"{dataset.id}-selection.geojson", ".geojson")
|
||||
export_path = StorageService.dataset_export_path(str(dataset.project_id), str(dataset.id), filename)
|
||||
metadata = {
|
||||
"source": "vector_selection",
|
||||
"project_id": str(dataset.project_id),
|
||||
"dataset_id": str(dataset.id),
|
||||
"dataset_type": dataset.dataset_type,
|
||||
"selection_bbox": selection["selection_bbox"],
|
||||
"feature_count": selection["feature_count"],
|
||||
"limit": selection["limit"],
|
||||
"truncated": selection["truncated"],
|
||||
"source_table": "vector_features",
|
||||
}
|
||||
export = ExportService._write_json_export(
|
||||
db,
|
||||
project_id=dataset.project_id,
|
||||
analysis_run_id=None,
|
||||
export_type="vector_selection_geojson",
|
||||
storage_path=export_path,
|
||||
content=selection["geojson"],
|
||||
metadata=metadata,
|
||||
)
|
||||
return ExportService._create_response(export)
|
||||
|
||||
@staticmethod
|
||||
def export_dataset_geojson(db: Session, dataset_id: uuid.UUID, name: str | None = None) -> ExportCreateResponse:
|
||||
dataset = db.get(Dataset, dataset_id)
|
||||
|
||||
Reference in New Issue
Block a user