Created
November 10, 2021 23:31
-
-
Save numberoverzero/0bfa3b4c7d00f1c634a1d92670176af1 to your computer and use it in GitHub Desktop.
Small class to map multiple Bloop models onto a shared table
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# bloop 3.0.0 | |
import copy | |
from typing import Union | |
from bloop import BaseModel, Column | |
from bloop.models import subclassof, instanceof | |
from bloop.types import Type | |
__all__ = ["Mapper"] | |
class Mapper: | |
_base_model: BaseModel | |
def __init__(self, base_model: BaseModel): | |
self._base_model = base_model | |
def prefix(self, type: Type, mapped: Union[str, Column], prefix: str) -> Column: | |
new_column = self._clone_column(mapped) | |
new_column.typedef = PrefixType(type, mapped.typedef, prefix) | |
return new_column | |
def static(self, type: Type, mapped: Union[str, Column], value: str) -> Column: | |
if callable(value): | |
default = value | |
else: | |
default = lambda: value | |
new_column = self._clone_column(mapped) | |
new_column.typedef = MappedType(type, mapped.typedef) | |
new_column.default = default | |
return new_column | |
def overlay(self, type: Type, mapped: Union[str, Column]) -> Column: | |
new_column = self._clone_column(mapped) | |
new_column.typedef = MappedType(type, mapped.typedef) | |
return new_column | |
def _clone_column(self, column: Union[str, Column]) -> Column: | |
if isinstance(column, str): | |
column: Column = getattr(self._base_model, column) | |
clone = copy.copy(column) | |
clone._dynamo_name = column.dynamo_name | |
return clone | |
class MappedType(Type): | |
_upper: Type | |
_lower: Type | |
def __init__(self, upper_typedef: Type, lower_typedef: Type): | |
super().__init__() | |
upper_typedef = MappedType._instantiate(upper_typedef) | |
lower_typedef = MappedType._instantiate(lower_typedef) | |
self._upper = MappedType._instantiate(upper_typedef) | |
self._lower = MappedType._instantiate(lower_typedef) | |
self.backing_type = self._lower.backing_type | |
self.python_type = self._upper.python_type | |
def dynamo_dump(self, value, *, context, **kwargs): | |
value = self._upper.dynamo_dump(value, context=context, **kwargs) | |
return self._lower.dynamo_dump(value, context=context, **kwargs) | |
def dynamo_load(self, value, *, context, **kwargs): | |
value = self._lower.dynamo_load(value, context=context, **kwargs) | |
return self._upper.dynamo_load(value, context=context, **kwargs) | |
def _instantiate(typedef) -> Type: | |
if subclassof(typedef, Type): | |
typedef = typedef() | |
if not instanceof(typedef, Type): | |
raise TypeError(f"Expected {typedef} to be instance or subclass of Type") | |
return typedef | |
class PrefixType(MappedType): | |
def __init__(self, upper_type: Type, lower_type, prefix: str): | |
super().__init__(upper_type, lower_type) | |
self._prefix = prefix | |
def dynamo_dump(self, value, *, context, **kwargs): | |
value = super().dynamo_dump(value, context=context, **kwargs) | |
if value: | |
return f"{self._prefix}{value}" | |
def dynamo_load(self, value, *, context, **kwargs): | |
if value: | |
(*_, value) = value.split(self._prefix, 1) | |
return super().dynamo_load(value, context=context, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from bloop import BaseModel, Column, String, UUID | |
from bloop_multitable import Mapper | |
class SharedBase(BaseModel): | |
hk = Column(String, hash_key=True) | |
rk = Column(String, range_key=True) | |
b = SharedBase | |
m = Mapper(SharedBase) | |
class TenantUser(SharedBase): | |
tenant = m.prefix(UUID, b.hk, "userByTenant::") | |
id = m.overlay(UUID, b.rk) | |
# USAGE | |
from uuid import uuid4 | |
from bloop import Engine | |
from bloop.models import unpack_from_dynamodb | |
from bloop.util import dump_key | |
engine = Engine() | |
engine.bind(b, skip_table_setup=True) | |
u = TenantUser(tenant=uuid4(), id=uuid4()) | |
wire = dump_key(engine, u) | |
same = unpack_from_dynamodb( | |
attrs=wire, | |
expected=TenantUser.Meta.columns, | |
model=TenantUser, | |
engine=engine) | |
print(f"on the wire: {wire}") | |
print(f"user: {u}") | |
print(f"same: {same}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment