add resume

This commit is contained in:
ivankirpichnikov
2025-11-22 02:17:18 +03:00
parent a207e5a217
commit d9a3c39980
33 changed files with 1157 additions and 97 deletions
@@ -0,0 +1,38 @@
from collections.abc import Sequence
from typing import override
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from template_project.adapters.data_gateways.tables import resume_prediction_table
from template_project.application.resume.data_gateway import ResumeDataGateway, ResumePredictionDataGateway
from template_project.application.resume.entity import Resume, ResumeEmbeddingId, ResumeId, ResumePrediction
from template_project.application.resume.errors import ResumeNotFoundError
class DefaultResumeDataGateway(ResumeDataGateway):
def __init__(self, session: AsyncSession) -> None:
self._session = session
@override
async def get_suitable_resumes(self, embedding_id: ResumeEmbeddingId) -> Sequence[Resume]:
raise NotImplementedError
@override
async def load(self, resume_id: ResumeId) -> Resume:
resume = await self._session.get(Resume, resume_id)
if resume is None:
raise ResumeNotFoundError(resume_id=resume_id)
return resume
class DefaultResumePredictionDataGateway(ResumePredictionDataGateway):
def __init__(self, session: AsyncSession) -> None:
self._session = session
@override
async def load_by_resume_id(self, resume_id: ResumeId) -> ResumePrediction | None:
statement = select(ResumePrediction).where(resume_prediction_table.c.resume_id == resume_id)
result = await self._session.execute(statement)
return result.scalar()
@@ -1,10 +1,15 @@
from typing import Final
from pgvector.sqlalchemy import Vector
from sqlalchemy import (
ARRAY,
Boolean,
Column,
DateTime,
Enum,
ForeignKey,
MetaData,
Numeric,
String,
Table,
UniqueConstraint,
@@ -15,13 +20,14 @@ from sqlalchemy.orm import registry
from template_project.application.access_token.entity import AccessToken
from template_project.application.auth_identity.entity import AuthIdentity, AuthMethod
from template_project.application.notification_device.entity import NotificationDevice
from template_project.application.resume.entity import Resume, ResumeEmbedding, ResumePrediction
from template_project.application.user.entity import User
from template_project.application.user.profile.entity import Profile
meta_data = MetaData()
mapper_registry = registry()
meta_data: Final = MetaData()
mapper_registry: Final = registry()
user_table = Table(
user_table: Final = Table(
"users",
meta_data,
Column("id", UUID, primary_key=True),
@@ -29,7 +35,7 @@ user_table = Table(
Column("created_at", DateTime(timezone=True), nullable=False),
)
access_token_table = Table(
access_token_table: Final = Table(
"access_token",
meta_data,
Column("id", UUID, primary_key=True),
@@ -40,7 +46,7 @@ access_token_table = Table(
Column("created_at", DateTime(timezone=True), nullable=False),
)
auth_identity_table = Table(
auth_identity_table: Final = Table(
"auth_identities",
meta_data,
Column("id", UUID, primary_key=True),
@@ -52,7 +58,7 @@ auth_identity_table = Table(
UniqueConstraint("method", "identifier", name="uq_auth_method_identifier"),
)
profile_table = Table(
profile_table: Final = Table(
"profiles",
meta_data,
Column("id", UUID, primary_key=True),
@@ -67,7 +73,7 @@ profile_table = Table(
Column("created_at", DateTime(timezone=True), nullable=False),
)
notification_device_table = Table(
notification_device_table: Final = Table(
"notification_devices",
meta_data,
Column("id", UUID, primary_key=True),
@@ -78,8 +84,47 @@ notification_device_table = Table(
UniqueConstraint("user_id", "device_id", name="uq_user_device"),
)
resume_table: Final = Table(
"resume",
meta_data,
Column("id", UUID, primary_key=True),
Column("deleted_at", DateTime(timezone=True)),
Column("created_at", DateTime(timezone=True), nullable=False),
Column("user_id", UUID, ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
Column("position", String, nullable=False),
Column("about_me", String, nullable=False),
Column("key_skills", ARRAY(String, as_tuple=True), nullable=False),
Column("experience_type", String, nullable=False),
Column("down_resume_id", UUID, ForeignKey("resume.id", ondelete="CASCADE"), nullable=True, default=None),
)
resume_embedding_table: Final = Table(
"resume_embedding",
meta_data,
Column("id", UUID, primary_key=True),
Column("deleted_at", DateTime(timezone=True)),
Column("created_at", DateTime(timezone=True), nullable=False),
Column("resume_id", UUID, ForeignKey("resume.id", ondelete="CASCADE"), nullable=False),
Column("vector", Vector, nullable=False),
)
resume_prediction_table: Final = Table(
"resume_prediction",
meta_data,
Column("id", UUID, primary_key=True),
Column("deleted_at", DateTime(timezone=True)),
Column("created_at", DateTime(timezone=True), nullable=False),
Column("resume_id", UUID, ForeignKey("resume.id", ondelete="CASCADE"), nullable=False),
Column("from_salary", Numeric, nullable=False),
Column("to_salary", Numeric, nullable=False),
Column("recommended_skills", ARRAY(String, as_tuple=True), nullable=False),
)
mapper_registry.map_imperatively(User, user_table)
mapper_registry.map_imperatively(AccessToken, access_token_table)
mapper_registry.map_imperatively(AuthIdentity, auth_identity_table)
mapper_registry.map_imperatively(Profile, profile_table)
mapper_registry.map_imperatively(NotificationDevice, notification_device_table)
mapper_registry.map_imperatively(Resume, resume_table)
mapper_registry.map_imperatively(ResumeEmbedding, resume_embedding_table)
mapper_registry.map_imperatively(ResumePrediction, resume_prediction_table)