Skip to content

Commit 7aa32d9

Browse files
committed
Use canonical DB helpers for local pipeline registration
1 parent 5933729 commit 7aa32d9

5 files changed

Lines changed: 108 additions & 152 deletions

File tree

computing/misc/antyodaya/pipeline.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import pandas as pd
1414
from django.conf import settings
1515

16+
from computing.utils import save_layer_info_to_db, update_layer_sync_status
1617
from utilities.pipelines import AdminScope, CSAdminSource, StandardRequest, load_config
1718
from utilities.pipelines.admin import (
1819
ADMIN_COLUMN_DESCRIPTIONS,
@@ -28,7 +29,7 @@
2829
stable_hash,
2930
utc_now_text,
3031
)
31-
from utilities.pipelines.publish import publish_gpkg_layer, register_layer
32+
from utilities.pipelines.publish import publish_gpkg_layer
3233
from utilities.pipelines.schema import (
3334
STATUS_MATCHED,
3435
STATUS_NO_DATA,
@@ -597,29 +598,6 @@ def run_antyodaya_pipeline(
597598
geoserver = asdict(geoserver_result)
598599
geoserver["ok"] = True
599600
geoserver["status"] = "published"
600-
if request.publish.register_layers:
601-
result["layer_registration"] = register_layer(
602-
dataset_name=output_config.get("dataset_name", "Antyodaya 2020"),
603-
layer_name=result_name,
604-
scope=request.scope,
605-
workspace=geoserver_workspace,
606-
geoserver_url=geoserver.get("wfs_url"),
607-
algorithm=ALGORITHM,
608-
algorithm_version=ALGORITHM_VERSION,
609-
misc={
610-
"source_csv": config["sources"]["csv"],
611-
"gpkg_path": result.get("gpkg_path"),
612-
"links_path": result.get("links_path"),
613-
"output_dir": bundle.path.as_posix(),
614-
"geoserver_layer_name": result_name,
615-
"geoserver_url": geoserver.get("wfs_url"),
616-
"rows": result.get("rows"),
617-
"matched_rows": result.get("matched_rows"),
618-
"join_coverage": result.get("join_coverage"),
619-
},
620-
overwrite=request.publish.overwrite,
621-
)
622-
result["layer_id"] = (result["layer_registration"] or {}).get("layer_id")
623601
except Exception as exc:
624602
geoserver = {
625603
"ok": False,
@@ -631,6 +609,42 @@ def run_antyodaya_pipeline(
631609
}
632610
timings["publish_geoserver_seconds"] = round(time.perf_counter() - t0, 3)
633611
result["geoserver"] = geoserver
612+
if request.publish.register_layers and geoserver and geoserver.get("ok"):
613+
state = request.scope.state_name
614+
district = request.scope.district_name
615+
block = request.scope.tehsil_name
616+
if not (state and district and block):
617+
raise ValueError(
618+
"Layer registration requires state, district, and tehsil names."
619+
)
620+
dataset_name = output_config.get("dataset_name", "Antyodaya 2020")
621+
layer_id = save_layer_info_to_db(
622+
state=state,
623+
district=district,
624+
block=block,
625+
layer_name=result_name,
626+
asset_id="not applicable: local compute GeoServer layer",
627+
dataset_name=dataset_name,
628+
algorithm=ALGORITHM,
629+
algorithm_version=ALGORITHM_VERSION,
630+
misc={"is_generated_locally": True},
631+
is_override=request.publish.overwrite,
632+
)
633+
if layer_id is None:
634+
raise RuntimeError(f"Database registration failed for layer {result_name!r}.")
635+
if update_layer_sync_status(
636+
layer_id=layer_id, sync_to_geoserver=True
637+
) is None:
638+
raise RuntimeError(
639+
f"GeoServer sync status update failed for layer ID {layer_id}."
640+
)
641+
result["layer_id"] = layer_id
642+
result["layer_registration"] = {
643+
"ok": True,
644+
"status": "registered",
645+
"dataset": dataset_name,
646+
"layer_id": layer_id,
647+
}
634648
if outputs.readme:
635649
result["readme_path"] = bundle.write_readme(
636650
_readme_lines(

computing/misc/facilities/pipeline.py

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from django.conf import settings
1717
from scipy.spatial import cKDTree
1818

19+
from computing.utils import save_layer_info_to_db, update_layer_sync_status
1920
from utilities.pipelines import AdminScope, CSAdminSource, StandardRequest, load_config
2021
from utilities.pipelines.admin import (
2122
ADMIN_COLUMN_DESCRIPTIONS,
@@ -53,7 +54,6 @@
5354
from utilities.pipelines.publish import (
5455
publish_gpkg_layer,
5556
publish_gpkg_layers,
56-
register_layer,
5757
)
5858
from utilities.pipelines.unicode import normalize_unicode_frame
5959
from nrm_app.celery import app
@@ -1134,33 +1134,48 @@ def run_facilities_pipeline(
11341134
}
11351135
).as_posix()
11361136
if request.publish.register_layers and published_layers:
1137-
common_misc = {
1138-
"source_facilities_gpkg": config["sources"]["facilities_gpkg"],
1139-
"gpkg_path": result.get("gpkg_path"),
1140-
"facility_points_gpkg_path": result.get("facility_points_gpkg_path"),
1141-
"links_path": result.get("links_path"),
1142-
"output_dir": bundle.path.as_posix(),
1143-
"village_rows": result.get("village_rows"),
1144-
"nearest_rows": result.get("nearest_rows"),
1145-
"inventory_rows": result.get("inventory_rows"),
1146-
}
1137+
state = request.scope.state_name
1138+
district = request.scope.district_name
1139+
block = request.scope.tehsil_name
1140+
if not (state and district and block):
1141+
raise ValueError(
1142+
"Layer registration requires state, district, and tehsil names."
1143+
)
11471144
registrations: dict[str, dict[str, Any]] = {}
11481145
for role, published in published_layers.items():
1149-
registrations[role] = register_layer(
1150-
dataset_name=(
1151-
output_config.get("dataset_name", "Facilities Proximity")
1152-
if role == "village_properties"
1153-
else output_config.get("points_dataset_name", "Facilities Points")
1154-
),
1146+
dataset_name = (
1147+
output_config.get("dataset_name", "Facilities Proximity")
1148+
if role == "village_properties"
1149+
else output_config.get("points_dataset_name", "Facilities Points")
1150+
)
1151+
layer_id = save_layer_info_to_db(
1152+
state=state,
1153+
district=district,
1154+
block=block,
11551155
layer_name=published["layer_name"],
1156-
scope=request.scope,
1157-
workspace=published["workspace"],
1158-
geoserver_url=published["wfs_url"],
1156+
asset_id="not applicable: local compute GeoServer layer",
1157+
dataset_name=dataset_name,
11591158
algorithm=ALGORITHM,
11601159
algorithm_version=ALGORITHM_VERSION,
1161-
misc={**common_misc, "output_role": role},
1162-
overwrite=request.publish.overwrite,
1160+
misc={"is_generated_locally": True},
1161+
is_override=request.publish.overwrite,
11631162
)
1163+
if layer_id is None:
1164+
raise RuntimeError(
1165+
f"Database registration failed for layer {published['layer_name']!r}."
1166+
)
1167+
if update_layer_sync_status(
1168+
layer_id=layer_id, sync_to_geoserver=True
1169+
) is None:
1170+
raise RuntimeError(
1171+
f"GeoServer sync status update failed for layer ID {layer_id}."
1172+
)
1173+
registrations[role] = {
1174+
"ok": True,
1175+
"status": "registered",
1176+
"dataset": dataset_name,
1177+
"layer_id": layer_id,
1178+
}
11641179
result["layer_registrations"] = registrations
11651180
result["layer_registration"] = registrations.get("village_properties")
11661181
result["layer_id"] = (result.get("layer_registration") or {}).get("layer_id")

computing/misc/livestocks/pipeline.py

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pandas as pd
1313
from django.conf import settings
1414

15+
from computing.utils import save_layer_info_to_db, update_layer_sync_status
1516
from utilities.pipelines import AdminScope, CSAdminSource, StandardRequest, load_config
1617
from utilities.pipelines.admin import (
1718
ADMIN_COLUMN_DESCRIPTIONS,
@@ -27,7 +28,7 @@
2728
stable_hash,
2829
utc_now_text,
2930
)
30-
from utilities.pipelines.publish import publish_gpkg_layer, register_layer
31+
from utilities.pipelines.publish import publish_gpkg_layer
3132
from utilities.pipelines.schema import (
3233
STATUS_MATCHED,
3334
STATUS_NO_DATA,
@@ -498,28 +499,41 @@ def run_livestocks_pipeline(
498499
timings["publish_geoserver_seconds"] = round(time.perf_counter() - t0, 3)
499500
result["geoserver"] = geoserver
500501
if request.publish.register_layers and geoserver and geoserver.get("ok"):
501-
result["layer_registration"] = register_layer(
502-
dataset_name=output_config.get("dataset_name", "Livestock Census"),
502+
state = request.scope.state_name
503+
district = request.scope.district_name
504+
block = request.scope.tehsil_name
505+
if not (state and district and block):
506+
raise ValueError(
507+
"Layer registration requires state, district, and tehsil names."
508+
)
509+
dataset_name = output_config.get("dataset_name", "Livestock Census")
510+
layer_id = save_layer_info_to_db(
511+
state=state,
512+
district=district,
513+
block=block,
503514
layer_name=layer_name,
504-
scope=request.scope,
505-
workspace=geoserver_workspace,
506-
geoserver_url=geoserver.get("wfs_url"),
515+
asset_id="not applicable: local compute GeoServer layer",
516+
dataset_name=dataset_name,
507517
algorithm=ALGORITHM,
508518
algorithm_version=ALGORITHM_VERSION,
509-
misc={
510-
"source_csv": config["sources"]["csv"],
511-
"gpkg_path": result.get("gpkg_path"),
512-
"links_path": result.get("links_path"),
513-
"output_dir": bundle.path.as_posix(),
514-
"geoserver_layer_name": layer_name,
515-
"geoserver_url": geoserver.get("wfs_url"),
516-
"rows": result.get("rows"),
517-
"matched_rows": result.get("matched_rows"),
518-
"join_coverage": result.get("join_coverage"),
519-
},
520-
overwrite=request.publish.overwrite,
519+
misc={"is_generated_locally": True},
520+
is_override=request.publish.overwrite,
521521
)
522-
result["layer_id"] = result["layer_registration"]["layer_id"]
522+
if layer_id is None:
523+
raise RuntimeError(f"Database registration failed for layer {layer_name!r}.")
524+
if update_layer_sync_status(
525+
layer_id=layer_id, sync_to_geoserver=True
526+
) is None:
527+
raise RuntimeError(
528+
f"GeoServer sync status update failed for layer ID {layer_id}."
529+
)
530+
result["layer_id"] = layer_id
531+
result["layer_registration"] = {
532+
"ok": True,
533+
"status": "registered",
534+
"dataset": dataset_name,
535+
"layer_id": layer_id,
536+
}
523537
if outputs.readme:
524538
result["readme_path"] = bundle.write_readme(
525539
_readme_lines(

utilities/pipelines/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
"""
88

99
from .admin import AdminScope, CSAdminSource
10-
from .publish import register_layer
1110
from .schema import StandardRequest, api_request_payload, load_config
1211

1312
__all__ = [
1413
"AdminScope",
1514
"CSAdminSource",
1615
"StandardRequest",
1716
"api_request_payload",
18-
"register_layer",
1917
"load_config",
2018
]

utilities/pipelines/publish.py

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -405,88 +405,3 @@ def publish_gpkg_layers(
405405
property_count=len(verification["properties"]),
406406
)
407407
return results
408-
409-
410-
def register_layer(
411-
*,
412-
dataset_name: str,
413-
layer_name: str,
414-
scope: Any,
415-
workspace: str,
416-
geoserver_url: str,
417-
algorithm: str,
418-
algorithm_version: str,
419-
misc: dict[str, Any] | None = None,
420-
overwrite: bool = False,
421-
) -> dict[str, Any]:
422-
"""Register a published layer in the Core Stack layer database.
423-
424-
The `Layer` model is keyed on state/district/block, so only tehsil-scoped runs can register;
425-
other scopes are reported as skipped rather than failing the run.
426-
427-
"""
428-
429-
level = str(getattr(scope, "level", "") or "").lower()
430-
if level not in {"tehsil", "block"}:
431-
return {"ok": False, "status": "skipped", "reason": f"layer registration needs a tehsil scope, got {level!r}"}
432-
state, district, block = scope.state_name, scope.district_name, scope.tehsil_name
433-
if not (state and district and block):
434-
return {"ok": False, "status": "skipped", "reason": "scope is missing state, district, or tehsil name"}
435-
436-
from django.db import transaction
437-
438-
from computing.models import Dataset, Layer, LayerType
439-
from geoadmin.models import DistrictSOI, StateSOI, TehsilSOI
440-
441-
with transaction.atomic():
442-
dataset, _ = Dataset.objects.get_or_create(
443-
name=dataset_name,
444-
defaults={
445-
"layer_type": LayerType.VECTOR,
446-
"workspace": workspace,
447-
"is_active": True,
448-
},
449-
)
450-
dataset.layer_type = LayerType.VECTOR
451-
dataset.workspace = workspace
452-
dataset.is_active = True
453-
dataset.save(update_fields=["layer_type", "workspace", "is_active", "updated_at"])
454-
455-
state_obj = StateSOI.objects.get(state_name__iexact=state)
456-
district_obj = DistrictSOI.objects.get(
457-
district_name__iexact=district,
458-
state=state_obj,
459-
)
460-
block_obj = TehsilSOI.objects.get(
461-
tehsil_name__iexact=block,
462-
district=district_obj,
463-
)
464-
layer, _ = Layer.objects.update_or_create(
465-
dataset=dataset,
466-
layer_name=layer_name,
467-
state=state_obj,
468-
district=district_obj,
469-
block=block_obj,
470-
layer_version="1.0",
471-
defaults={
472-
"algorithm": algorithm,
473-
"algorithm_version": algorithm_version,
474-
"is_sync_to_geoserver": True,
475-
"is_override": overwrite,
476-
"gee_asset_path": "not applicable: local compute GeoServer layer",
477-
"is_public_gee_asset": False,
478-
"misc": {
479-
"is_generated_locally": True,
480-
"source_type": "local_compute",
481-
"geoserver_workspace": workspace,
482-
"geoserver_url": geoserver_url,
483-
**(misc or {}),
484-
},
485-
},
486-
)
487-
return {
488-
"ok": True,
489-
"status": "registered",
490-
"dataset": dataset_name,
491-
"layer_id": layer.id,
492-
}

0 commit comments

Comments
 (0)