from sqlalchemy import or_, select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from inbox.models import Inbox from job.job_post.models import JobPosts from role.models import EnumRoles, Roles from search.serializers import ( serialize_search_candidate, serialize_search_job, serialize_search_manager, ) from users.models import Users from users.permissions import PermissionTag, has_permission JOBS_CAP = 4 CANDIDATES_CAP = 4 MANAGERS_CAP = 3 class Search: def __init__(self, session: AsyncSession): self.session = session async def fetch(self, q, limit, current_user): query = (q or "").strip() granted = current_user.get("permissions") or [] jobs = [] candidates = [] managers = [] if query: if has_permission(granted, PermissionTag.JOBS_VIEW): jobs = await self._jobs(query, min(limit, JOBS_CAP)) if has_permission(granted, PermissionTag.CANDIDATES_VIEW): candidates = await self._candidates(query, min(limit, CANDIDATES_CAP)) managers = await self._managers(query, min(limit, MANAGERS_CAP)) data = {"jobs": jobs, "candidates": candidates, "managers": managers} total = len(jobs) + len(candidates) + len(managers) return data, total async def _jobs(self, query, cap): like = f"%{query}%" statement = ( select(JobPosts) .where( JobPosts.is_deleted == False, # noqa: E712 or_( JobPosts.title.ilike(like), JobPosts.location.ilike(like), JobPosts.department.ilike(like), ), ) .order_by(JobPosts.created_at.desc()) .limit(cap) ) result = await self.session.execute(statement) return [serialize_search_job(r) for r in result.scalars().all()] async def _candidates(self, query, cap): like = f"%{query}%" statement = ( select(Users) .join(Roles, Users.role_id == Roles.id) .where( Roles.role_name == EnumRoles.CANDIDATE.value, Users.is_deleted == False, # noqa: E712 or_(Users.name.ilike(like), Users.email.ilike(like)), ) .order_by(Users.created_at.desc()) .limit(cap) ) users = list((await self.session.execute(statement)).scalars().all()) inbox_by_user = {} if users: inbox_q = ( select(Inbox.user_id, Inbox.id) .where(Inbox.user_id.in_([u.id for u in users])) .order_by(Inbox.created_at.desc()) ) for user_id, inbox_id in (await self.session.execute(inbox_q)).all(): inbox_by_user.setdefault(user_id, inbox_id) return [ serialize_search_candidate(u.id, u.name, u.email, inbox_by_user.get(u.id)) for u in users ] async def _managers(self, query, cap): like = f"%{query}%" role = await Roles.get_role_by_name(self.session, EnumRoles.HIRING_MANAGER.value) if role is None: return [] statement = ( select(Users) .options(selectinload(Users.role)) .where( Users.role_id == role.id, Users.is_deleted == False, # noqa: E712 or_(Users.name.ilike(like), Users.email.ilike(like)), ) .order_by(Users.created_at.desc()) .limit(cap) ) result = await self.session.execute(statement) return [serialize_search_manager(u) for u in result.scalars().all()]