feat: enhance import functionality with commit results and summary models for projects and scenarios

This commit is contained in:
2025-11-10 09:20:41 +01:00
parent 3bc124c11f
commit eaef99f0ac
3 changed files with 422 additions and 1 deletions

View File

@@ -135,6 +135,19 @@ class StagedImportView(Generic[TImportRow]):
rows: tuple[StagedRowView[TImportRow], ...]
@dataclass(slots=True, frozen=True)
class ImportCommitSummary:
created: int
updated: int
@dataclass(slots=True, frozen=True)
class ImportCommitResult(Generic[TImportRow]):
token: str
rows: tuple[StagedRowView[TImportRow], ...]
summary: ImportCommitSummary
UnitOfWorkFactory = Callable[[], UnitOfWork]
@@ -402,6 +415,136 @@ class ImportIngestionService:
def clear_staged_scenarios(self, token: str) -> bool:
return self._scenario_stage.pop(token, None) is not None
def commit_project_import(self, token: str) -> ImportCommitResult[ProjectImportRow]:
staged = self._project_stage.get(token)
if not staged:
raise ValueError(f"Unknown project import token: {token}")
staged_view = _build_staged_view(staged)
created = updated = 0
with self._uow_factory() as uow:
if not uow.projects:
raise RuntimeError("Project repository is unavailable")
for row in staged.rows:
mode = row.context.get("mode")
data = row.parsed.data
if mode == "create":
project = Project(
name=data.name,
location=data.location,
operation_type=data.operation_type,
description=data.description,
)
if data.created_at:
project.created_at = data.created_at
if data.updated_at:
project.updated_at = data.updated_at
uow.projects.create(project)
created += 1
elif mode == "update":
project_id = row.context.get("project_id")
if not project_id:
raise ValueError(
"Staged project update is missing project_id context"
)
project = uow.projects.get(project_id)
project.name = data.name
project.location = data.location
project.operation_type = data.operation_type
project.description = data.description
if data.created_at:
project.created_at = data.created_at
if data.updated_at:
project.updated_at = data.updated_at
updated += 1
else:
raise ValueError(
f"Unsupported staged project mode: {mode!r}")
self._project_stage.pop(token, None)
return ImportCommitResult(
token=token,
rows=staged_view.rows,
summary=ImportCommitSummary(created=created, updated=updated),
)
def commit_scenario_import(self, token: str) -> ImportCommitResult[ScenarioImportRow]:
staged = self._scenario_stage.get(token)
if not staged:
raise ValueError(f"Unknown scenario import token: {token}")
staged_view = _build_staged_view(staged)
created = updated = 0
with self._uow_factory() as uow:
if not uow.scenarios or not uow.projects:
raise RuntimeError("Scenario repositories are unavailable")
for row in staged.rows:
mode = row.context.get("mode")
data = row.parsed.data
project_id = row.context.get("project_id")
if not project_id:
raise ValueError(
"Staged scenario row is missing project_id context"
)
project = uow.projects.get(project_id)
if mode == "create":
scenario = Scenario(
project_id=project.id,
name=data.name,
status=data.status,
start_date=data.start_date,
end_date=data.end_date,
discount_rate=data.discount_rate,
currency=data.currency,
primary_resource=data.primary_resource,
description=data.description,
)
if data.created_at:
scenario.created_at = data.created_at
if data.updated_at:
scenario.updated_at = data.updated_at
uow.scenarios.create(scenario)
created += 1
elif mode == "update":
scenario_id = row.context.get("scenario_id")
if not scenario_id:
raise ValueError(
"Staged scenario update is missing scenario_id context"
)
scenario = uow.scenarios.get(scenario_id)
scenario.project_id = project.id
scenario.name = data.name
scenario.status = data.status
scenario.start_date = data.start_date
scenario.end_date = data.end_date
scenario.discount_rate = data.discount_rate
scenario.currency = data.currency
scenario.primary_resource = data.primary_resource
scenario.description = data.description
if data.created_at:
scenario.created_at = data.created_at
if data.updated_at:
scenario.updated_at = data.updated_at
updated += 1
else:
raise ValueError(
f"Unsupported staged scenario mode: {mode!r}")
self._scenario_stage.pop(token, None)
return ImportCommitResult(
token=token,
rows=staged_view.rows,
summary=ImportCommitSummary(created=created, updated=updated),
)
def _store_project_stage(
self, rows: list[StagedRow[ProjectImportRow]]
) -> str: