Skip to content

Commit dbceb75

Browse files
committed
feat: enhance project area import with created and skipped counts
1 parent 2aa4d20 commit dbceb75

2 files changed

Lines changed: 44 additions & 8 deletions

File tree

cli/cli.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,9 @@ def import_project_area_boundaries_command(
10211021
result = import_project_area_boundaries(layer_url=layer_url)
10221022
typer.echo(f"Fetched {result.fetched} feature(s).")
10231023
typer.echo(f"Matched {result.matched} group row(s).")
1024+
typer.echo(f"Created {result.created} group(s).")
10241025
typer.echo(f"Updated {result.updated} group project area(s).")
1026+
typer.echo(f"Skipped {result.skipped} unchanged group(s).")
10251027
if result.unmatched_locations:
10261028
typer.echo(
10271029
"Unmatched locations: " + ", ".join(result.unmatched_locations),

cli/project_area_import.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@ class ProjectAreaImportResult:
2525
fetched: int
2626
matched: int
2727
updated: int
28+
created: int
29+
skipped: int
2830
unmatched_locations: tuple[str, ...]
2931

3032

3133
def _normalize_name(value: str) -> str:
3234
return value.strip().lower()
3335

3436

37+
def _geoms_equal(geom1: str, geom2: str) -> bool:
38+
from shapely import wkt
39+
40+
return wkt.loads(geom1).equals(wkt.loads(geom2))
41+
42+
3543
def _geojson_to_multipolygon_wkt(geometry: dict[str, Any]) -> str:
3644
geom = shape(geometry)
3745
if isinstance(geom, Polygon):
@@ -77,13 +85,16 @@ def _fetch_project_area_features(
7785

7886
def import_project_area_boundaries(
7987
layer_url: str = PROJECT_AREA_LAYER_URL,
88+
group_type: str = "Geographic Area",
8089
) -> ProjectAreaImportResult:
8190
with httpx.Client(timeout=60.0) as client:
8291
features = _fetch_project_area_features(client, layer_url)
8392

8493
unmatched_locations: list[str] = []
8594
matched = 0
8695
updated = 0
96+
created = 0
97+
skipped = 0
8798

8899
with session_ctx() as session:
89100
for feature in features:
@@ -94,30 +105,53 @@ def import_project_area_boundaries(
94105
if not location_name or geometry is None:
95106
continue
96107

108+
normalized_name = _normalize_name(location_name)
97109
groups = session.scalars(
98110
select(Group).where(
99-
func.lower(func.trim(Group.name)) == _normalize_name(location_name)
111+
func.lower(func.trim(Group.name)) == normalized_name,
112+
Group.group_type == group_type,
100113
)
101114
).all()
102115

103-
if not groups:
104-
unmatched_locations.append(location_name)
105-
continue
106-
107-
matched += len(groups)
108116
project_area = WKTElement(
109117
_geojson_to_multipolygon_wkt(geometry),
110118
srid=4326,
111119
)
120+
121+
if not groups:
122+
new_group = Group(
123+
name=location_name,
124+
group_type=group_type,
125+
project_area=project_area,
126+
)
127+
session.add(new_group)
128+
created += 1
129+
matched += 1
130+
continue
131+
132+
matched += len(groups)
112133
for group in groups:
113-
group.project_area = project_area
114-
updated += 1
134+
old_wkt = None
135+
if group.project_area is not None:
136+
from shapely import wkb
137+
138+
old_wkt = wkb.loads(bytes(group.project_area.data)).wkt
139+
140+
new_wkt = project_area.desc
141+
142+
if old_wkt is None or not _geoms_equal(old_wkt, new_wkt):
143+
group.project_area = project_area
144+
updated += 1
145+
else:
146+
skipped += 1
115147

116148
session.commit()
117149

118150
return ProjectAreaImportResult(
119151
fetched=len(features),
120152
matched=matched,
121153
updated=updated,
154+
created=created,
155+
skipped=skipped,
122156
unmatched_locations=tuple(sorted(set(unmatched_locations))),
123157
)

0 commit comments

Comments
 (0)