Files
openstack-api-simulator/app/openstack/db_docs.py
T
inecs 6033967e6a Initial commit: stateful OpenStack API laboratory simulator.
Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm
packaging, API contract packs, and pytest/Pulumi coverage labs.
2026-07-18 04:26:48 +03:00

106 lines
2.7 KiB
Python

"""Read JSON documents stored in ``os_api_objects`` (discovery, schemas, catalog)."""
from __future__ import annotations
import json
from typing import Any
from asyncpg import Connection
from app.openstack.errors import OpenStackError
from app.openstack.ids import oid
async def fetch_doc(
conn: Connection,
*,
service: str,
resource_type: str,
name: str = "default",
) -> dict[str, Any] | None:
row = await conn.fetchrow(
"""SELECT data FROM os_api_objects
WHERE service=$1 AND resource_type=$2 AND name=$3
ORDER BY updated_at DESC
LIMIT 1""",
service,
resource_type,
name,
)
if row is None:
return None
data = row["data"]
if isinstance(data, str):
data = json.loads(data)
return dict(data or {})
async def require_doc(
conn: Connection,
*,
service: str,
resource_type: str,
name: str = "default",
) -> dict[str, Any]:
doc = await fetch_doc(conn, service=service, resource_type=resource_type, name=name)
if doc is None:
raise OpenStackError(
"NotFound",
f"{service}/{resource_type}/{name} not seeded in database",
status_code=404,
)
return doc
async def list_docs(
conn: Connection,
*,
service: str,
resource_type: str,
) -> list[dict[str, Any]]:
rows = await conn.fetch(
"""SELECT id, name, status, data FROM os_api_objects
WHERE service=$1 AND resource_type=$2
ORDER BY created_at NULLS LAST, name""",
service,
resource_type,
)
items: list[dict[str, Any]] = []
for row in rows:
data = row["data"]
if isinstance(data, str):
data = json.loads(data)
data = dict(data or {})
data.setdefault("id", str(row["id"]))
data.setdefault("name", row["name"])
data.setdefault("status", row["status"])
items.append(data)
return items
async def upsert_doc(
conn: Connection,
*,
service: str,
resource_type: str,
name: str,
data: dict[str, Any],
project_id: Any | None = None,
status: str = "ACTIVE",
) -> None:
item_id = oid(f"doc:{service}:{resource_type}:{name}")
payload = {"id": str(item_id), "name": name, **data}
await conn.execute(
"""INSERT INTO os_api_objects(id, service, resource_type, project_id, name, status, data)
VALUES($1,$2,$3,$4,$5,$6,$7::jsonb)
ON CONFLICT (id) DO UPDATE SET
data=EXCLUDED.data, status=EXCLUDED.status, updated_at=now()""",
item_id,
service,
resource_type,
project_id,
name,
status,
json.dumps(payload),
)