Skip to content

Commit d9bbce7

Browse files
committed
🎨 refactor(DataMart): create AreaOfInterest abstraction
First, make the change easy.
1 parent 3a46cad commit d9bbce7

File tree

3 files changed

+52
-13
lines changed

3 files changed

+52
-13
lines changed

app/models/pydantic/datamart.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
from enum import Enum
2-
from typing import Dict, Optional
2+
from typing import Dict, Optional, Union
33
from uuid import UUID
4+
from abc import ABC, abstractmethod
45

56
from pydantic import Field
67

78
from app.models.pydantic.responses import Response
89

910
from .base import StrictBaseModel
1011

12+
class AreaOfInterest(StrictBaseModel, ABC):
13+
@abstractmethod
14+
def get_geostore_id(self) -> UUID:
15+
"""Return the unique identifier for the area of interest."""
16+
pass
17+
18+
19+
class GeostoreAreaOfInterest(AreaOfInterest):
20+
geostore_id:UUID = Field(..., title="Geostore ID")
21+
22+
def get_geostore_id(self) -> UUID:
23+
return self.geostore_id
24+
1125

1226
class AnalysisStatus(str, Enum):
1327
saved = "saved"
@@ -43,7 +57,7 @@ class DataMartResourceLinkResponse(Response):
4357

4458

4559
class TreeCoverLossByDriverIn(StrictBaseModel):
46-
geostore_id: UUID
60+
aoi: Union[GeostoreAreaOfInterest]
4761
canopy_cover: int = 30
4862
dataset_version: Dict[str, str] = {}
4963

@@ -76,3 +90,6 @@ class Config:
7690

7791
class TreeCoverLossByDriverResponse(Response):
7892
data: TreeCoverLossByDriver
93+
94+
95+

app/routes/datamart/land.py

+28-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
DataMartResourceLinkResponse,
2929
TreeCoverLossByDriver,
3030
TreeCoverLossByDriverIn,
31-
TreeCoverLossByDriverResponse,
31+
TreeCoverLossByDriverResponse, AreaOfInterest, GeostoreAreaOfInterest,
3232
)
3333
from app.settings.globals import API_URL
3434
from app.tasks.datamart.land import (
@@ -61,6 +61,11 @@ def _parse_dataset_versions(request: Request) -> Dict[str, str]:
6161
# Merge dataset version overrides with default dataset versions
6262
return DEFAULT_LAND_DATASET_VERSIONS | dataset_versions
6363

64+
65+
def _parse_area_of_interest(request: Request) -> AreaOfInterest:
66+
aoi_info = request.query_params.getlist('aoi[geostore_id]');
67+
return GeostoreAreaOfInterest(geostore_id=aoi_info[0])
68+
6469
@router.get(
6570
"/tree_cover_loss_by_driver",
6671
response_class=ORJSONResponse,
@@ -69,6 +74,23 @@ def _parse_dataset_versions(request: Request) -> Dict[str, str]:
6974
status_code=200,
7075
openapi_extra={
7176
"parameters": [
77+
{
78+
"name": "aoi",
79+
"in": "query",
80+
"required": True,
81+
"style": "deepObject",
82+
"explode": True,
83+
"example": {
84+
"geostore_id": "637d378f-93a9-4364-bfa8-95b6afd28c3a",
85+
},
86+
"description": "The Area of Interest",
87+
"schema": {
88+
"oneOf": [
89+
{"$ref": "#/components/schemas/GeostoreAreaOfInterest"},
90+
{"$ref": "#/components/schemas/WdpaAreaOfInterest"},
91+
]
92+
}
93+
},
7294
{
7395
"name": "dataset_version",
7496
"in": "query",
@@ -92,14 +114,14 @@ def _parse_dataset_versions(request: Request) -> Dict[str, str]:
92114
)
93115
async def tree_cover_loss_by_driver_search(
94116
*,
95-
geostore_id: UUID = Query(..., title="Geostore ID"),
117+
aoi: AreaOfInterest = Depends(_parse_area_of_interest),
96118
canopy_cover: int = Query(30, alias="canopy_cover", title="Canopy cover percent"),
97119
dataset_versions: Optional[Dict[str, str]] = Depends(_parse_dataset_versions),
98120
api_key: APIKey = Depends(get_api_key),
99121
):
100122
"""Search if a resource exists for a given geostore and canopy cover."""
101123
resource_id = _get_resource_id(
102-
"tree_cover_loss_by_driver", geostore_id, canopy_cover, dataset_versions
124+
"tree_cover_loss_by_driver", aoi.get_geostore_id(), canopy_cover, dataset_versions
103125
)
104126

105127
# check if it exists
@@ -155,7 +177,7 @@ async def tree_cover_loss_by_driver_post(
155177

156178
# check geostore is valid
157179
try:
158-
await get_geostore(data.geostore_id, GeostoreOrigin.rw)
180+
await get_geostore(data.aoi.get_geostore_id(), GeostoreOrigin.rw)
159181
except HTTPException:
160182
raise HTTPException(
161183
status_code=422,
@@ -168,7 +190,7 @@ async def tree_cover_loss_by_driver_post(
168190
dataset_version = DEFAULT_LAND_DATASET_VERSIONS | data.dataset_version
169191
resource_id = _get_resource_id(
170192
"tree_cover_loss_by_driver",
171-
data.geostore_id,
193+
data.aoi.get_geostore_id(),
172194
data.canopy_cover,
173195
dataset_version,
174196
)
@@ -178,7 +200,7 @@ async def tree_cover_loss_by_driver_post(
178200
background_tasks.add_task(
179201
compute_tree_cover_loss_by_driver,
180202
resource_id,
181-
data.geostore_id,
203+
data.aoi.get_geostore_id(),
182204
data.canopy_cover,
183205
dataset_version,
184206
)

tests_v2/unit/app/routes/datamart/test_land.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async def test_get_tree_cover_loss_by_drivers_not_found(
3232
origin = payload["domains"][0]
3333

3434
headers = {"origin": origin}
35-
params = {"x-api-key": api_key, "geostore_id": geostore, "canopy_cover": 30}
35+
params = {"x-api-key": api_key, "aoi[geostore_id]": geostore, "canopy_cover": 30}
3636

3737
response = await async_client.get(
3838
"/v0/land/tree_cover_loss_by_driver", headers=headers, params=params
@@ -59,7 +59,7 @@ async def test_get_tree_cover_loss_by_drivers_found(
5959
origin = payload["domains"][0]
6060

6161
headers = {"origin": origin}
62-
params = {"x-api-key": api_key, "geostore_id": geostore, "canopy_cover": 30}
62+
params = {"x-api-key": api_key, "aoi[geostore_id]": geostore, "canopy_cover": 30}
6363
resource_id = _get_resource_id(
6464
"tree_cover_loss_by_driver", geostore, 30, DEFAULT_LAND_DATASET_VERSIONS
6565
)
@@ -94,7 +94,7 @@ async def test_get_tree_cover_loss_by_drivers_with_overrides(
9494
origin = payload["domains"][0]
9595

9696
headers = {"origin": origin}
97-
params = {"x-api-key": api_key, "geostore_id": geostore, "canopy_cover": 30}
97+
params = {"x-api-key": api_key, "aoi[geostore_id]": geostore, "canopy_cover": 30}
9898
resource_id = _get_resource_id(
9999
"tree_cover_loss_by_driver",
100100
geostore,
@@ -143,7 +143,7 @@ async def test_get_tree_cover_loss_by_drivers_with_malformed_overrides(
143143
params = {"x-api-key": api_key, "geostore_id": geostore, "canopy_cover": 30}
144144

145145
response = await async_client.get(
146-
"/v0/land/tree_cover_loss_by_driver?x-api-key={api_key}&geostore_id={geostore_id}&canopy_cover=30&dataset_version[umd_tree_cover_loss]]=v1.8&dataset_version[umd_tree_cover_density_2000]=v1.6",
146+
f"/v0/land/tree_cover_loss_by_driver?x-api-key={api_key}&aoi[geostore_id]={geostore}&canopy_cover=30&dataset_version[umd_tree_cover_loss]]=v1.8&dataset_version[umd_tree_cover_density_2000]=v1.6",
147147
headers=headers,
148148
params=params,
149149
)
@@ -166,7 +166,7 @@ async def test_post_tree_cover_loss_by_drivers(
166166

167167
headers = {"origin": origin, "x-api-key": api_key}
168168
payload = {
169-
"geostore_id": geostore,
169+
"aoi": {"geostore_id": geostore},
170170
"canopy_cover": 30,
171171
"dataset_version": {"umd_tree_cover_loss": "v1.8"},
172172
}

0 commit comments

Comments
 (0)