Persistence Layer — ACD 0.2.0 documentation

# Persistence Layer

Every persistence service is implementing one of interface defined in this module. Interfaces are generics depends on at least Entity class (finders needs also request class).

Example: | Implementing of persistence service

    >>> from acd.domain import Entity
    ...
    >>> class Example(Entity, id_attributes=('num',)):
    ...     num: int
    ...
    >>> class ExampleInserter(Inserter[Example]):
    ...     def __init__(self, dbsession):
    ...         self._session = dbsession
    ...
    ...     def __call__(self, entity: Example) -> Example:
    ...         self._session.add(entity)
    ...         return entity

## Inserter

class `acd.persistence.` `Inserter`

  Stores entity.

  Example: | Inserter implementation

      >>> from acd.domain import Entity
      >>> class Example(Entity, id_attributes=('num',)):
      ...    num: int
      ...
      >>> class ExampleInserter(Inserter[Example]):
      ...     def __init__(self, cache: dict) -> None:
      ...         self._cache = cache
      ...
      ...     def __call__(self, entity: Example) -> Example:
      ...         if entity.entity_id in self._cache:
      ...             raise EntityDuplicateError(entity.entity_id)
      ...         self._cache[entity.entity_id] = entity
      ...         return entity
      ...
      >>> insert_example = ExampleInserter({})
      >>> insert_example(Example(num=1))
      Example(num=1)

class `acd.persistence.` `EntityDuplicateError`

  Raises when inserting duplicate of entity.

## Updater

class `acd.persistence.` `Updater`

  Updates stored entity with new entity version.

  Example: | Updater implementation

      >>> from acd.domain import Entity
      >>> class Example(Entity, id_attributes=('num',)):
      ...    num: int
      ...
      >>> class ExampleUpdater(Updater[Example]):
      ...     def __init__(self, cache: dict) -> None:
      ...         self._cache = cache
      ...
      ...     def __call__(self, entity: Example) -> Example:
      ...         if entity.entity_id not in self._cache:
      ...             raise EntityNotFoundError(entity.entity_id)
      ...         self._cache[entity.entity_id] = entity
      ...         return entity
      ...
      >>> entity = Example(num=1)
      >>> cache = {entity.entity_id: entity}
      >>> update_example = ExampleUpdater(cache)
      >>> update_example(Example(num=1))
      Example(num=1)

class `acd.persistence.` `EntityNotFoundError`

  Raises when trying to update not existing entity.

## Getter

class `acd.persistence.` `Getter`

  Gets stored entity.

  Example: | Getter implementation

      >>> from acd.domain import Entity
      >>> class Example(Entity, id_attributes=('num',)):
      ...    num: int
      ...
      >>> class ExampleGetter(Getter[Example]):
      ...     def __init__(self, cache: dict) -> None:
      ...         self._cache = cache
      ...
      ...     def __call__(self, entity_id: EntityId) -> Optional[Example]:
      ...         return self._cache.get(entity_id)
      ...
      >>> entity = Example(num=1)
      >>> cache = {entity.entity_id: entity}
      >>> get_example = ExampleGetter(cache)
      >>> get_example((1,))
      Example(num=1)

## Finder

class `acd.persistence.` `Finder`

  Finds all entities for given search request.

  Example: | Finder implementation

      >>> from acd.domain import Entity
      >>> from acd.libs.annotation import Immutable
      ...
      >>> class Example(Entity, id_attributes=('num',)):
      ...     num: int
      ...
      >>> class RangeSearchRequest(Immutable):
      ...     greater_then: int
      ...     lower_then: int
      ...
      >>> class ExampleFinder(Finder[RangeSearchRequest, Example]):
      ...     def __init__(self, cache: dict) -> None:
      ...         self._cache = cache
      ...
      ...     def __call__(self, request: RangeSearchRequest) -> List[Example]:
      ...         return [
      ...             e for e in self._cache.values()
      ...             if request.greater_then < e.num < request.lower_then
      ...         ]
      ...
      >>> entities = [
      ...     Example(num=1), Example(num=2), Example(num=3), Example(num=4),
      ... ]
      >>> cache = {e.entity_id: e for e in entities}
      >>> find_examples = ExampleFinder(cache)
      >>> request = RangeSearchRequest(greater_then=1, lower_then=4)
      >>> find_examples(request)
      [Example(num=2), Example(num=3)]