-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
On our path to a generic DDD repository
- Loading branch information
Showing
7 changed files
with
158 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from .base_types import ( | ||
T, UniqueIdentifier, | ||
Base, | ||
Entity, EntityModel, | ||
ValueObject, | ||
AggregateRoot, Repository) | ||
from .models import InstanceModel, ImageModel | ||
from .repositories import InstanceRepository, ImageRepository |
Empty file.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import abc | ||
import typing | ||
|
||
import sqlalchemy.orm | ||
|
||
|
||
class Base(sqlalchemy.orm.DeclarativeBase): # pylint: disable=too-few-public-methods | ||
""" | ||
Base class for database persistence | ||
""" | ||
pass | ||
|
||
|
||
class EntityModel: | ||
id: sqlalchemy.orm.Mapped[str] = sqlalchemy.orm.mapped_column(sqlalchemy.String(32), | ||
primary_key=True) | ||
|
||
def merge(self, other: 'EntityModel'): | ||
for key, value in self.__dict__.items(): | ||
if key == id: | ||
continue | ||
setattr(self, key, getattr(other, key)) | ||
|
||
|
||
T = typing.TypeVar('T', bound=EntityModel, covariant=True) | ||
UniqueIdentifier = typing.TypeVar('UniqueIdentifier', str, sqlalchemy.UUID(as_uuid=True)) | ||
|
||
|
||
class Entity(abc.ABC): | ||
pass | ||
|
||
|
||
class ValueObject(abc.ABC): | ||
pass | ||
|
||
|
||
class AggregateRoot(Entity): | ||
pass | ||
|
||
|
||
class Repository(typing.Generic[T]): | ||
|
||
def __init__(self, model: typing.Type[T], session: sqlalchemy.orm.Session) -> None: | ||
self._model = model | ||
self._session = session | ||
|
||
def get_by_id(self, uid: UniqueIdentifier) -> T: | ||
return self._session.get(self._model, str(uid)) | ||
|
||
def list(self) -> typing.Iterable[T]: | ||
return self._session.query(self._model).all() | ||
|
||
def create(self, entity: T) -> T: | ||
self._session.add(entity) | ||
self._session.commit() | ||
return entity | ||
|
||
def modify(self, update: T) -> T: | ||
current: T = self._session.get(self._model, update.id) | ||
current.merge(update) | ||
self._session.add(current) | ||
self._session.commit() | ||
return current | ||
|
||
def remove(self, uid: UniqueIdentifier) -> None: | ||
current = self._session.get(self._model, str(uid)) | ||
self._session.delete(current) | ||
self._session.commit() | ||
|
||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from sqlalchemy import String, Integer | ||
from sqlalchemy.orm import Mapped, mapped_column | ||
|
||
from .base_types import Base, EntityModel | ||
|
||
|
||
class InstanceModel(EntityModel, Base): | ||
__tablename__ = 'ddd_instances' | ||
|
||
name: Mapped[str] = mapped_column(String(64), unique=True) | ||
vcpu: Mapped[int] = mapped_column(Integer) | ||
ram: Mapped[int] = mapped_column(Integer) | ||
|
||
|
||
class ImageModel(EntityModel, Base): | ||
__tablename__ = 'ddd_images' | ||
|
||
name: Mapped[str] = mapped_column(String(64), unique=True) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from .base_types import Repository | ||
from .models import InstanceModel, ImageModel | ||
|
||
|
||
class InstanceRepository(Repository[InstanceModel]): | ||
pass | ||
|
||
|
||
class ImageRepository(Repository[ImageModel]): | ||
pass |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import uuid | ||
import sqlalchemy.orm | ||
|
||
from kaso_mashin.common.ddd import InstanceModel, ImageModel, InstanceRepository | ||
|
||
|
||
def test_model(ddd_session: sqlalchemy.orm.Session): | ||
assert ddd_session is not None | ||
for i in range(0, 16): | ||
instance_identifier = str(uuid.uuid4()) | ||
ddd_session.add(InstanceModel(id=instance_identifier, | ||
name=f"instance-{instance_identifier}", | ||
vcpu=i, | ||
ram=i)) | ||
image_identifier = str(uuid.uuid4()) | ||
ddd_session.add(ImageModel(id=image_identifier, | ||
name=f"image-{image_identifier}")) | ||
ddd_session.commit() | ||
|
||
|
||
def test_repositories(ddd_session: sqlalchemy.orm.Session): | ||
instance_repository = InstanceRepository(model=InstanceModel, session=ddd_session) | ||
instances = instance_repository.list() | ||
assert instances is not None | ||
|
||
|
||
def test_instance_model_roundtrip(ddd_session: sqlalchemy.orm): | ||
test_id = str(uuid.uuid4()) | ||
instance = InstanceModel(id=test_id, name=f'instance-{test_id}', vcpu=16, ram=32) | ||
repository = InstanceRepository(model=InstanceModel, session=ddd_session) | ||
assert instance == repository.create(instance) | ||
assert instance == repository.get_by_id(test_id) | ||
instance.name = f'instance-{test_id}-updated' | ||
instance.vcpu = 8 | ||
instance.ram = 16 | ||
assert instance == repository.modify(instance) | ||
|