Skip to content

Models

When modeling the application logic through Domain Driven Design, you usually need the following object types:

  • Value object: Any domain object that is uniquely identified by the data it holds, so it has no conceptual identity. They should be treated as immutable. We can still have complex behaviour in value objects. In fact, it's common to support operations, for example, mathematical operators.

  • Entity: An object that is not defined by it's attributes, but rather by a thread of continuity and it's identity. Unlike values, they have identity equality. We can change their values, and they are still recognizably the same thing.

Entities

The Entity class is based on the pydantic's BaseModel to enforce that they have the id_ attribute of type int, str or AnyHttpUrl, used for comparison and hashing of entities.

They also have a private model_name property with the name of the model.

If you use integer IDs (which is the default), you don't need to define the id_ at object creation. When you add the entity to the repository, it will populate it.

from repository_orm import Entity, load_repository


class Author(Entity):
    first_name: str


repo = load_repository()


author = Author(first_name="Brandon")

# Add entities
repo.add(author)
repo.commit()

# Retrieve entities by their ID
brandon = repo.get(0, Author)
assert brandon == author # noqa

!!! warning "This will only work with int ids! For the rest of the cases you need to give the id_ yourself."

Merging entities

Entities have a merge method that let's you update it's attributes with the ones of another entity.

from repository_orm import Entity


class Author(Entity):
    name: str
    is_alive: bool = True


author = Author(name="Brandon")

# Imagine a complex process here that creates an updated version of the author object
new_author = Author(name="New name", is_alive=False)

author.merge(new_author)
assert author.name == "New name"
assert not author.is_alive

# Nevertheless the default values are not merged!
author.merge(Author(name="Brandon"))
assert not author.is_alive

# Unless specified by the user
author.merge(Author(name="Brandon", is_alive=True))
assert author.is_alive # noqa

For two entities to be mergeable, they need to belong from the same model and have the same id_. The previous example worked because by default the id_ is -1 until the entity is added to the repository. If you want to check other attribute to see if the objects are mergeable, probably that attribute should be the id_ instead.

If you don't want to propagate some attributes when merging, add them to the _skip_on_merge configuration option of the model:

from datetime import datetime

from repository_orm import Entity


class Author(Entity):
    name: str
    is_alive: bool = True
    birthday: datetime
    _skip_on_merge = ["birthday"]


author = Author(name="Brandon", birthday=datetime(2020, 1, 1))
new_author = Author(name="Brandon", birthday=datetime(1900, 1, 1), is_alive=False)

author.merge(new_author)
assert author.birthday == datetime(2020, 1, 1)
assert not author.is_alive # noqa

Files

The File class is a special Entity model used to work with computer files.

It has useful attributes like:

  • path.
  • created_at.
  • updated_at.
  • owner.
  • group.
  • permissions.

And methods:

  • basename.
  • dirname.
  • extension.

Until Pydantic 1.9 is released, you need to store the content in the file using the _content attribute, to access the content, you can use content directly.


Last update: 2022-03-04