Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Indroic/HexCore/llms.txt

Use this file to discover all available pages before exploring further.

BaseEntity is the foundation every entity in your domain inherits from. It ships with a UUID primary key, UTC timestamps, a soft-delete flag, and a private event queue that lets the entity record domain events for later dispatch. Configuration is handled through Pydantic’s model_config, giving you ORM compatibility (from_attributes=True) and field-level re-validation (validate_assignment=True) out of the box. Also included in hexcore.domain.base is AbstractModelMeta, a thin compatibility shim that resolves the metaclass conflict between Pydantic and Python’s abc.ABCMeta.

Class definition

from hexcore.domain.base import BaseEntity
class BaseEntity(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,
        validate_assignment=True,
        frozen=False,
    )

Fields

id
UUID
default:"uuid4()"
Unique universal identifier for the entity. Auto-generated with uuid4() when not provided.
created_at
datetime
UTC timestamp set at creation time via datetime.now(UTC). Never updated after the entity is first saved.
updated_at
datetime
UTC timestamp updated every time the entity is modified. Defaults to datetime.now(UTC) on instantiation.
is_active
bool | None
default:"True"
Soft-delete flag. Set to False by calling deactivate() instead of issuing a hard DELETE against the data store.

Methods

register_event

def register_event(self, event: DomainEvent) -> None
Appends a DomainEvent to the entity’s internal event queue. Call this inside domain methods whenever a significant state change has occurred. The event is held in memory until either pull_domain_events() or clear_domain_events() is called.
event
DomainEvent
required
The domain event instance to enqueue.

pull_domain_events

def pull_domain_events(self) -> List[DomainEvent]
Returns a copy of all enqueued events and then clears the internal queue. The Unit of Work uses this method when collecting events for dispatch after a successful commit.
events
List[DomainEvent]
All domain events that were registered since the last call to pull_domain_events() or clear_domain_events().

clear_domain_events

def clear_domain_events(self) -> None
Empties the internal event queue without returning the events. Useful when an operation is aborted and you want to discard any events that were registered during it.

deactivate

async def deactivate(self) -> None
Sets is_active = False, implementing logical (soft) deletion. The entity record is preserved in the data store; it simply stops appearing in active queries. Because validate_assignment=True is set, Pydantic re-validates the field on assignment.

AbstractModelMeta

from hexcore.domain.base import AbstractModelMeta
AbstractModelMeta is a convenience base class that combines BaseEntity and abc.ABC in a single type. Its sole purpose is to resolve the metaclass conflict that arises when a class tries to inherit from both a Pydantic BaseModel (which uses ModelMetaclass) and an abstract base class (which uses ABCMeta).
You should inherit from AbstractModelMeta whenever you need to mark methods as @abstractmethod on a class that also inherits BaseEntity. Never try to set metaclass=... manually on a Pydantic model.
import abc
from hexcore.domain.base import AbstractModelMeta

class AbstractAuditableEntity(AbstractModelMeta):
    @abc.abstractmethod
    def audit_label(self) -> str:
        ...

Usage example

from uuid import UUID
from hexcore.domain.base import BaseEntity
from hexcore.domain.events import EntityCreatedEvent

class Product(BaseEntity):
    name: str
    price: float
    stock: int

    @classmethod
    def create(cls, name: str, price: float, stock: int) -> "Product":
        product = cls(name=name, price=price, stock=stock)
        product.register_event(
            EntityCreatedEvent(entity_id=product.id, entity_data=product)
        )
        return product
Because frozen=False, you can mutate entity fields directly and Pydantic will re-validate them. If you need truly immutable value objects, create a separate BaseModel subclass with frozen=True rather than inheriting BaseEntity.

Build docs developers (and LLMs) love