diff --git a/brewman/alembic/versions/48af31eb6f3f_fp.py b/brewman/alembic/versions/48af31eb6f3f_fp.py new file mode 100644 index 00000000..eafa00e4 --- /dev/null +++ b/brewman/alembic/versions/48af31eb6f3f_fp.py @@ -0,0 +1,24 @@ +"""FP + +Revision ID: 48af31eb6f3f +Revises: 12262aadbc08 +Create Date: 2023-08-07 13:01:05.401492 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '48af31eb6f3f' +down_revision = '12262aadbc08' +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_unique_constraint(op.f('uq_fingerprints_date'), 'fingerprints', ['date', 'employee_id']) + + +def downgrade(): + op.drop_constraint(op.f('uq_fingerprints_date'), 'fingerprints', type_='unique') diff --git a/brewman/brewman/models/fingerprint.py b/brewman/brewman/models/fingerprint.py index 6f235bc2..9184e425 100644 --- a/brewman/brewman/models/fingerprint.py +++ b/brewman/brewman/models/fingerprint.py @@ -3,7 +3,7 @@ import uuid from datetime import datetime from typing import TYPE_CHECKING -from sqlalchemy import DateTime, ForeignKey, Uuid +from sqlalchemy import DateTime, ForeignKey, UniqueConstraint, Uuid from sqlalchemy.orm import Mapped, mapped_column, relationship from ..db.base_class import reg @@ -16,6 +16,7 @@ if TYPE_CHECKING: @reg.mapped_as_dataclass(unsafe_hash=True) class Fingerprint: __tablename__ = "fingerprints" + __table_args__ = (UniqueConstraint("date", "employee_id"),) id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4) employee_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("employees.id"), nullable=False) diff --git a/brewman/brewman/schemas/client.py b/brewman/brewman/schemas/client.py index f09b7d27..7d8076c4 100644 --- a/brewman/brewman/schemas/client.py +++ b/brewman/brewman/schemas/client.py @@ -44,11 +44,13 @@ class ClientList(Client): @field_validator("last_date", mode="before") @classmethod - def parse_last_date(cls, value: datetime | str) -> datetime | None: + def parse_last_date(cls, value: datetime | str | None) -> datetime | None: + if value is None or value == "": + return None if isinstance(value, datetime): return value return datetime.strptime(value, "%d-%b-%Y %H:%M") @field_serializer("last_date") - def serialize_last_date(self, value: datetime, info: FieldSerializationInfo) -> str: - return value.strftime("%d-%b-%Y %H:%M") + def serialize_last_date(self, value: datetime | None, info: FieldSerializationInfo) -> str | None: + return None if value is None else value.strftime("%d-%b-%Y %H:%M")