Skip to content

Instantly share code, notes, and snippets.

@numberoverzero
Created July 22, 2019 12:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save numberoverzero/ed8704b7a376d036739a4e923169944f to your computer and use it in GitHub Desktop.
Save numberoverzero/ed8704b7a376d036739a4e923169944f to your computer and use it in GitHub Desktop.
# fragments from evaluating some toolkit classes to build shared models as used
# in DAT401: Advanced Design Patterns for DynamoDB
# https://www.youtube.com/watch?v=HaEPXoXVf2k
import functools
from typing import Type
from bloop.conditions import Condition, iter_columns
from bloop.models import BaseModel, Column, IMeta, bind_column
def default_hk_query(cls, engine, key=None, filter=None, projection="all", consistent=False, forward=True):
key = Condition() | key
hk = cls.Meta.hash_key
if hk not in set(iter_columns(key)):
key &= hk == hk.default()
return engine.query(
cls, key=key,
filter=filter,
projection=projection,
consistent=consistent,
forward=forward,
)
def multimodel(base: Type[BaseModel], type_name = "PK_NAME") -> Type[BaseModel]:
"""
.. code-block:: python
>>> class AbstractBase(BaseModel):
... class Meta:
... table_name = "my_application"
... _hk = Column(String, hash_key=True, dynamo_name="hk")
... _rk = Column(String, range_key=True, dynamo_name="rk")
...
>>> Base = multimodel(AbstractBase, type_name="HASH_KEY")
>>> class User(Base):
... HASH_KEY = "users"
... name = Column(String, range_key=True)
...
>>> class Order(Base):
... HASH_KEY = "orders"
... id = Column(String, range_key=True)
...
>>> engine.bind(Base)
>>> jane = User(name="Jane")
>>> new_books = Order(id="jane--2018-02-14--X712540001")
>>> engine.save(jane, new_books)
>>> jane
User(_hk="users", name="Jane")
>>> book_order = Order.Meta.q(
... engine, Order.id.begins_with("jane--")
... ).first()
>>> book_order
Order(_hk='orders', id='jane--2018-02-14--X712540001')
"""
class _SharedBase(base):
class Meta(IMeta):
table_name = base.Meta.table_name
def __init_subclass__(cls: Type["_SharedBase"], **kwargs):
super().__init_subclass__(**kwargs)
cls.Meta.table_name = base.Meta.table_name
cls.Meta.q = functools.partial(default_hk_query, cls)
hk = cls.Meta.hash_key
hk._dynamo_name = base.Meta.hash_key.dynamo_name
bind_column(cls, hk.name, hk, force=True)
default_value = getattr(cls, type_name)
hk.default = lambda: default_value
rk = cls.Meta.range_key
rk._dynamo_name = base.Meta.range_key.dynamo_name
bind_column(cls, rk.name, rk, force=True)
return _SharedBase
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment