add optimistic concurrency guards via expected scheme version id protect draft editor, pricing snapshot, remap and publish flows from stale mutations protect version creation from stale current version state keep backward compatibility with optional query guards verify 409 conflict behavior for stale clients and 200 for valid flows
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
from fastapi import HTTPException, status
|
|
|
|
from app.repositories.scheme_versions import get_current_scheme_version
|
|
from app.repositories.schemes import get_scheme_record_by_scheme_id
|
|
|
|
|
|
def ensure_expected_scheme_version_id(
|
|
*,
|
|
actual_scheme_version_id: str,
|
|
expected_scheme_version_id: str | None,
|
|
) -> None:
|
|
if expected_scheme_version_id is None:
|
|
return
|
|
|
|
if expected_scheme_version_id != actual_scheme_version_id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail={
|
|
"code": "stale_draft_version",
|
|
"message": "Draft scheme version is stale. Reload current draft state before applying mutation.",
|
|
"expected_scheme_version_id": expected_scheme_version_id,
|
|
"actual_scheme_version_id": actual_scheme_version_id,
|
|
},
|
|
)
|
|
|
|
|
|
async def get_current_draft_context(
|
|
scheme_id: str,
|
|
expected_scheme_version_id: str | None = None,
|
|
):
|
|
scheme = await get_scheme_record_by_scheme_id(scheme_id)
|
|
version = await get_current_scheme_version(
|
|
scheme_id=scheme.scheme_id,
|
|
current_version_number=scheme.current_version_number,
|
|
)
|
|
|
|
if version.status != "draft" or scheme.status != "draft":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Current scheme version is not editable because it is not in draft state",
|
|
)
|
|
|
|
ensure_expected_scheme_version_id(
|
|
actual_scheme_version_id=version.scheme_version_id,
|
|
expected_scheme_version_id=expected_scheme_version_id,
|
|
)
|
|
|
|
return scheme, version
|