Screenshot 2023-03-17 at 1.33.35 AM.png

class Person{

    private String name;
    private String surname;
    private String email;
    private String phone;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Person(String name, String surname, String email, String phone) {
        this.name = name;
        this.surname = surname;
        this.email = email;
        this.phone = phone;
    }

    @java.lang.Override
    public java.lang.String toString() {
        return "Person{" +
                "name='" + name + '\\'' +
                ", surname='" + surname + '\\'' +
                ", email='" + email + '\\'' +
                ", phone='" + phone + '\\'' +
                '}';
    }

    public boolean equals(Object object) {
        if (this == object) return true;
        if (!(object instanceof Person)) return false;
        if (!super.equals(object)) return false;
        Person person = (Person) object;
        return getName().equals(person.getName()) && getSurname().equals(person.getSurname()) && getEmail().equals(person.getEmail()) && getPhone().equals(person.getPhone());
    }

    public int hashCode() {
        return Objects.hash(super.hashCode(), getName(), getSurname(), getEmail(), getPhone());
    }
}
from dataclasses import dataclass

@dataclass
class Person:
    name: str
    surname: str
    age: int
    email: str
    phone: str

    # NOTE:: dataclasses implements __init__,  __repr__ methods and __eq__  for you. 
    # But this is a list of the builtins available for you to implement.
    def __str__(self):
        return f'{self.name} {self.surname}'

    def __repr__(self):
        return f'{self.name} {self.surname}'

    def __eq__(self, other):
        return self.name == other.name and self.surname == other.surname

    def __hash__(self):
        return hash(self.name + self.surname)

    def __lt__(self, other):
        return self.name < other.name

    def __add__(self, other):
        return self.age + other.age

    def __sub__(self, other):
        return self.age - other.age

    def __mul__(self, other):
        return self.age * other.age

    def __truediv__(self, other):
        return self.age / other.age

    def __floordiv__(self, other):
        return self.age // other.age

    def __mod__(self, other):
        return self.age % other.age

    def __pow__(self, other):
        return self.age ** other.age

    def __and__(self, other):
        return self.age & other.age

    def __or__(self, other):
        return self.age | other.age

    def __xor__(self, other):
        return self.age ^ other.age

    def __lshift__(self, other):
        return self.age << other.age

    def __rshift__(self, other):
        return self.age >> other.age

    def __neg__(self):
        return -self.age

    def __pos__(self):
        return +self.age

    def __abs__(self):
        return abs(self.age)

    def __invert__(self):
        return ~self.age

    def __complex__(self):
        return complex(self.age)

    def __int__(self):
        return int(self.age)

    def __float__(self):
        return float(self.age)

    def __round__(self, n):
        return round(self.age, n)

    def __index__(self):
        return self.age.__index__()

    def __len__(self):
        return len(self.name)

    def __contains__(self, item):
        return item in self.name

    def __getitem__(self, item):
        return self.name[item]

    def __setitem__(self, key, value):
        self.name[key] = value

    def __delitem__(self, key):
        del self.name[key]

    def __iter__(self):
        return iter(self.name)

    def __reversed__(self):
        return reversed(self.name)

    def __call__(self, *args, **kwargs):
        return self.name(*args, **kwargs)

    def __getattribute__(self, item):
        return getattr(self, item)

    def __setattr__(self, key, value):
        return setattr(self, key, value)

    def __delattr__(self, item):
        return delattr(self, item)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return self

    def __format__(self, format_spec):
        return format(self.name, format_spec)

    def __sizeof__(self):
        return self.name.__sizeof__()

    def __dir__(self):
        return dir(self.name)

    def __get__(self, instance, owner):
        return self.name.__get__(instance, owner)

    def __set__(self, instance, value):
        return self.name.__set__(instance, value)

    def __delete__(self, instance):
        return self.name.__delete__(instance)

    def __getnewargs__(self):
        return self.name.__getnewargs__()

    def __getnewargs_ex__(self):
        return self.name.__getnewargs_ex__()

    def __getinitargs__(self):
        return self.name.__getinitargs__()

    def __getstate__(self):
        return self.name.__getstate__()

    def __setstate__(self, state):
        return self.name.__setstate__(state)

    def __reduce__(self):
        return self.name.__reduce__()

    def __reduce_ex__(self, protocol):
        return self.name.__reduce_ex__(protocol)

person_repository.py

import abc
from typing import List

from app.domain.person import Person

class PersonRepository(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def add(self, person: Person) -> Person:
        raise NotImplementedError

    @abc.abstractmethod
    def all(self) -> List[Person]:
        raise NotImplementedError

    @abc.abstractmethod
    def total(self) -> int:
        raise NotImplementedError

Note how we import a PersonRepository looks like a Java Interface to me, code right above this comment, and then we set the person_id attribute, which is a UUID that then gets passed into the hash dunder overridden method to when called looks like it will generate a super unique int or string or whatever type it is that it generates, cause I can’t remember, and person_id value is generated in the app layer and not the DB layer for the POPO using the uuid4() method in uuid for the DB record’s surrogate key/primary key.

person.py

import uuid
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    # This is necessary to prevent circular imports
    from app.adapter.person_repository import PersonRepository

@dataclass
class Person:
    name: str
    surname: str
    age: int
    email: str
    phone: str

    person_id: str = field(default_factory=lambda: str(uuid.uuid4()))

    def __str__(self):
        return f'{self.name} {self.surname} {self.age} {self.email} {self.phone}'

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

    def save(self, person_repository:'PersonRepository'):
        return person_repository.add(self)