Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DDD and mongoengine #2816

Open
JaktensTid opened this issue Apr 30, 2024 · 0 comments
Open

DDD and mongoengine #2816

JaktensTid opened this issue Apr 30, 2024 · 0 comments

Comments

@JaktensTid
Copy link

JaktensTid commented Apr 30, 2024

Hi,

I am trying to create a python project with DDD, but do not distinguish ORM classes and DDD classes
The problem is that using custom types for the documents is really cumbersome

For example I am trying to call .delete, there was an error that I cannot
cannot encode object: ExperimentId(value=UUID('dd9ee71c-d47b-4126-a3de-e66f2e0d87db'))

Ok, I added def delete where I override such values which is a dirty hack

class Experiment(Document, Entity):
    id: ExperimentId = ExperimentId.Field(db_field='_id', primary_key=True, required=True)
    name: ExperimentName = ExperimentName.Field(required=True)
    created_at: datetime.datetime = DateTimeField(default=datetime.datetime.utcnow)

    def __init__(self, id: ExperimentId, name: ExperimentName, created_at: datetime.datetime | None = None, *args, **kwargs):
        if not id:
            raise NoLabsException('Experiment id is empty', ErrorCodes.invalid_experiment_id)

        if not name:
            raise NoLabsException('Experiment name is empty', ErrorCodes.invalid_experiment_name)

        created_at = created_at if created_at else datetime.datetime.now(tz=datetime.timezone.utc)

        super().__init__(id=id, name=name, created_at=created_at, *args, **kwargs)

    def set_name(self, name: ExperimentName):
        if not name:
            raise NoLabsException('Name cannot be empty', ErrorCodes.invalid_experiment_name)

        self.name = name

    def delete(self, signal_kwargs=None, **write_concern):
        self.__class__.objects.filter(id=self.id.value).delete()

Another problem arises when I try to dereference ListField(ReferenceField)

class LocalisationJob(Job):
    amino_acids: List[AminoAcid] = ListField(ReferenceField(AminoAcid, required=False, reverse_delete_rule=PULL))
    probabilities: List[LocalisationJobResult] = EmbeddedDocumentListField(LocalisationJobResult)

    def __init__(self, id: JobId, name: JobName, experiment: Experiment, *args, **kwargs):
        if not id:
            raise NoLabsException('Job id is invalid', ErrorCodes.invalid_job_id)
        if not name:
            raise NoLabsException('Job name is invalid', ErrorCodes.invalid_job_name)
        if not experiment:
            raise NoLabsException('Job must be in experiment', ErrorCodes.invalid_experiment_id)

        super().__init__(id=id, name=name, experiment=experiment, *args, **kwargs)

when I do

aa = job.amino_acids

it throws me

cannot encode object: AminoAcidId(value=UUID('dd9ee71c-d47b-4126-a3de-e66f2e0d87db')), of type: <class 'nolabs.refined.domain.models.common.AminoAcidId'>"

So the question - is there a way to defined custom types to be treated as primitivies once and ever in mongodb?

def to_python and to_mongo help only while saving the entities, but all the queries and delete operations do not work

For example AminoAcidId will ever must be convertible to UUID, ExperimentName to str

Example of AminoAcidId

@dataclass
class AminoAcidId(ValueObjectUUID):
    def __post_init__(self):
        if not self.value:
            NoLabsException.throw(ErrorCodes.invalid_aa_id)

    def __hash__(self):
        return hash(self.value)

    def __eq__(self, other):
        if not isinstance(other, AminoAcidId):
            return False

        return self.value == other.value

    class Field(fields.BaseField):
        def to_mongo(self, value):
            if isinstance(value, AminoAcidId):
                return value.value
            else:
                return value

        def to_python(self, value):
            if isinstance(value, UUID):
                return AminoAcidId(value)
            return value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant