Coverage for src/lexigram/admin/mapping/mapper.py: 0%
21 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 23:18 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-24 23:18 +0800
1"""AdminObjectMapper — registry-based object-to-object mapper for lexigram-admin.
3Implements :class:`lexigram.contracts.mapping.ObjectMapperProtocol` so the mapper
4can be resolved by any consumer that depends on the contract.
5"""
7from __future__ import annotations
9from typing import TYPE_CHECKING, Any
11from lexigram.logging import get_logger
13if TYPE_CHECKING:
14 from lexigram.contracts.mapping import ObjectMapperProtocol
16logger = get_logger(__name__)
19class AdminObjectMapper:
20 """Registry-based mapper for admin domain objects.
22 Satisfies :class:`~lexigram.contracts.mapping.ObjectMapperProtocol`.
24 Example::
26 mapper = AdminObjectMapper()
27 mapper.register(AdminUserEntity, AdminUserRecord, lambda e: e.to_user())
28 record = mapper.map(entity, AdminUserRecord)
29 """
31 def __init__(self) -> None:
32 self._registry: dict[tuple[type, type], Any] = {}
34 def register(
35 self,
36 source_type: type[Any],
37 dest_type: type[Any],
38 mapper_func: Any,
39 ) -> None:
40 """Register a mapping function from *source_type* to *dest_type*.
42 Args:
43 source_type: The type to map from.
44 dest_type: The target type to produce.
45 mapper_func: Callable that accepts a source instance and returns a dest
46 instance.
47 """
48 self._registry[(source_type, dest_type)] = mapper_func
49 logger.debug(
50 "admin_mapper_registered",
51 source=source_type.__name__,
52 dest=dest_type.__name__,
53 )
55 def map(
56 self,
57 source: Any,
58 dest_type: type[Any],
59 *,
60 validate: bool = False,
61 validator: Any | None = None,
62 ) -> Any:
63 """Map *source* to an instance of *dest_type*.
65 Args:
66 source: The source object to transform.
67 dest_type: The target type to produce.
68 validate: Whether to validate the result after mapping (unused by
69 default; pass a *validator* to enable).
70 validator: Optional callable ``validator(result) -> None`` that raises
71 on invalid data.
73 Returns:
74 A new instance of *dest_type*.
76 Raises:
77 KeyError: If no mapping is registered for this type pair.
78 """
79 key = (type(source), dest_type)
80 mapper_func = self._registry.get(key)
81 if mapper_func is None:
82 raise KeyError(
83 f"No mapping registered from {type(source).__name__!r} "
84 f"to {dest_type.__name__!r}"
85 )
86 result = mapper_func(source)
87 if validate and validator is not None:
88 validator(result)
89 return result
92# Ensure the class satisfies the protocol at import time (structural check).
93_: ObjectMapperProtocol = AdminObjectMapper()
95__all__ = ["AdminObjectMapper"]