File size: 3,114 Bytes
969891d 05d7afb 969891d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import Dict, Any, Optional
import uuid
import datetime
from backend.core.geo_engine import get_geo_engine
from backend.core.session_store import get_session_store
router = APIRouter()
# Must match executor.py's DEFAULT_SESSION_ID
DEFAULT_SESSION_ID = "default-session"
class UserLayerRequest(BaseModel):
geojson: Dict[str, Any]
name: str = "User Draw"
description: Optional[str] = None
class UserLayerResponse(BaseModel):
id: str
name: str # The table name in DuckDB
display_name: str
# Registered with and without the trailing slash. Starlette only redirects
# "/layers/user" -> "/layers/user/" when nothing else matches, and the
# catch-all that serves the frontend matches everything — so in the deployed
# build the redirect never happened and a POST came back 405.
@router.post("", response_model=UserLayerResponse)
@router.post("/", response_model=UserLayerResponse, include_in_schema=False)
async def register_user_layer(request: UserLayerRequest):
"""
Registers a new user-drawn layer.
Saves GeoJSON to backend and makes it available for SQL querying.
"""
try:
layer_id = str(uuid.uuid4())
geo_engine = get_geo_engine()
session_store = get_session_store() # Use singleton
# Register in DuckDB
table_name = geo_engine.register_layer(layer_id, request.geojson)
# Register in Session Store
layer_metadata = {
"id": layer_id,
"name": request.name,
"table_name": table_name,
"type": "user_draw",
"timestamp": datetime.datetime.now().isoformat(),
"description": request.description
}
# Use the same session ID as executor.py
session_store.add_layer(DEFAULT_SESSION_ID, layer_metadata)
return UserLayerResponse(
id=layer_id,
name=table_name,
display_name=request.name
)
except Exception as e:
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/{layer_id}")
async def delete_user_layer(layer_id: str):
"""
Deletes a user-drawn layer from DuckDB and session store.
Frees backend resources and prevents agent from querying the layer.
"""
try:
geo_engine = get_geo_engine()
session_store = get_session_store()
# Remove from DuckDB
dropped = geo_engine.drop_layer(layer_id)
# Remove from session store
removed = session_store.remove_layer(DEFAULT_SESSION_ID, layer_id)
if not dropped and not removed:
raise HTTPException(status_code=404, detail=f"Layer {layer_id} not found")
return {"status": "deleted", "layer_id": layer_id}
except HTTPException:
raise
except Exception as e:
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
|