generated from coulomb/repo-seed
Add guide-board pilot ingestion
This commit is contained in:
@@ -33,6 +33,7 @@ from artifactstore.dataplane.spi import DataPlane, IngestHints
|
||||
from artifactstore.db.schema import (
|
||||
artifact_files,
|
||||
artifact_packages,
|
||||
metadata_schemas,
|
||||
retention_classes,
|
||||
retention_state,
|
||||
storage_locations,
|
||||
@@ -70,6 +71,7 @@ __all__ = [
|
||||
"FileNotFoundError",
|
||||
"FileRecord",
|
||||
"IllegalPackageStateError",
|
||||
"MetadataSchemaRecord",
|
||||
"PackageNotFoundError",
|
||||
"PackageRecord",
|
||||
"Registry",
|
||||
@@ -100,6 +102,16 @@ class RetentionStateError(ValueError):
|
||||
"""Raised when a retention lifecycle operation is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class MetadataSchemaRecord:
|
||||
"""Registered package metadata schema."""
|
||||
|
||||
id: UUID
|
||||
slug: str
|
||||
json_schema: dict[str, Any]
|
||||
created_at: datetime | None
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class PackageRecord:
|
||||
"""Materialised package row projected into the registry API."""
|
||||
@@ -208,9 +220,15 @@ class Registry:
|
||||
retention_class: str,
|
||||
actor: str,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
metadata_schema_slug: str | None = None,
|
||||
) -> UUID:
|
||||
"""Create a new package; returns its ``UUID``."""
|
||||
retention_class_row = await self._get_retention_class(retention_class)
|
||||
package_metadata = metadata or {}
|
||||
metadata_schema_id = await self._validate_metadata_schema(
|
||||
metadata_schema_slug,
|
||||
package_metadata,
|
||||
)
|
||||
package_id = uuid.uuid4()
|
||||
payload = cbor2.dumps(
|
||||
{
|
||||
@@ -218,7 +236,8 @@ class Registry:
|
||||
"producer": producer,
|
||||
"subject": subject,
|
||||
"retention_class": retention_class,
|
||||
"metadata": metadata or {},
|
||||
"metadata": package_metadata,
|
||||
"metadata_schema_id": str(metadata_schema_id) if metadata_schema_id else None,
|
||||
},
|
||||
canonical=True,
|
||||
)
|
||||
@@ -513,6 +532,48 @@ class Registry:
|
||||
for r in rows
|
||||
]
|
||||
|
||||
async def register_metadata_schema(
|
||||
self,
|
||||
*,
|
||||
slug: str,
|
||||
json_schema: dict[str, Any],
|
||||
) -> UUID:
|
||||
"""Register a package metadata JSON Schema, idempotent by slug."""
|
||||
schema_id = uuid.uuid4()
|
||||
async with self._engine.begin() as conn:
|
||||
existing = (
|
||||
await conn.execute(
|
||||
select(metadata_schemas.c.id).where(metadata_schemas.c.slug == slug)
|
||||
)
|
||||
).first()
|
||||
if existing is not None:
|
||||
return UUID(str(existing.id))
|
||||
await conn.execute(
|
||||
metadata_schemas.insert().values(
|
||||
id=schema_id,
|
||||
slug=slug,
|
||||
json_schema=json_schema,
|
||||
)
|
||||
)
|
||||
return schema_id
|
||||
|
||||
async def get_metadata_schema(self, slug: str) -> MetadataSchemaRecord:
|
||||
"""Return one registered metadata schema by slug."""
|
||||
async with self._engine.connect() as conn:
|
||||
row = (
|
||||
await conn.execute(
|
||||
select(metadata_schemas).where(metadata_schemas.c.slug == slug)
|
||||
)
|
||||
).first()
|
||||
if row is None:
|
||||
raise KeyError(f"metadata schema not found: {slug}")
|
||||
return MetadataSchemaRecord(
|
||||
id=row.id,
|
||||
slug=row.slug,
|
||||
json_schema=dict(row.json_schema),
|
||||
created_at=row.created_at,
|
||||
)
|
||||
|
||||
async def get_retention_state(self, package_id: UUID) -> RetentionStateRecord:
|
||||
"""Return the retention materialised view for one package."""
|
||||
async with self._engine.connect() as conn:
|
||||
@@ -902,6 +963,25 @@ class Registry:
|
||||
deletion_strategy=row.deletion_strategy,
|
||||
)
|
||||
|
||||
async def _validate_metadata_schema(
|
||||
self,
|
||||
slug: str | None,
|
||||
metadata: dict[str, Any],
|
||||
) -> UUID | None:
|
||||
if slug is None:
|
||||
return None
|
||||
try:
|
||||
schema = await self.get_metadata_schema(slug)
|
||||
except KeyError as exc:
|
||||
raise ValueError(str(exc)) from exc
|
||||
required = schema.json_schema.get("required", [])
|
||||
if not isinstance(required, list):
|
||||
raise ValueError(f"metadata schema {slug!r} has invalid required list")
|
||||
missing = [key for key in required if isinstance(key, str) and key not in metadata]
|
||||
if missing:
|
||||
raise ValueError(f"metadata missing required schema keys: {', '.join(missing)}")
|
||||
return schema.id
|
||||
|
||||
|
||||
def _iso(value: datetime | None) -> str | None:
|
||||
if value is None:
|
||||
|
||||
Reference in New Issue
Block a user