Coverage for backend / app / job_rating / models.py: 100%
53 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-17 21:34 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-17 21:34 +0000
1"""Database models for job ratings and their service logs."""
3from sqlalchemy import (
4 Column,
5 Integer,
6 String,
7 ForeignKey,
8 Boolean,
9)
10from sqlalchemy.dialects.postgresql import ARRAY as PG_ARRAY
11from sqlalchemy.orm import relationship
12from sqlalchemy.sql import expression
14from app.base_models import Owned, CommonBase
15from app.database import Base
16from app.service_runner.models import ServiceLog
19class AiSystemPrompt(CommonBase, Base):
20 """Represents AI system prompts for job ratings.
22 Attributes:
23 -----------
24 - `prompt` (str): The AI system prompt.
26 Relationships
27 -------------
28 - `job_ratings`: JobRating that used the system prompt to rate the job"""
30 prompt = Column(String, nullable=False)
32 # Relationships
33 job_ratings = relationship("JobRating", back_populates="system_prompt")
36class AiJobPromptTemplate(CommonBase, Base):
37 """Represents AI job prompt templates for job rating
39 Attributes:
40 -----------
41 - `prompt` (str): The AI job prompt template.
43 Relationships
44 -------------
45 - `job_ratings`: JobRating that used the system prompt to rate the job"""
47 prompt = Column(String, nullable=False)
49 # Relationships
50 job_ratings = relationship("JobRating", back_populates="job_prompt_template")
53class JobRating(Owned, Base):
54 """Represents user ratings for jobs.
56 Attributes:
57 -----------
58 - `overall_score` (int): Overall score for the job.
59 - `technical_score` (int, optional): Technical score for the job.
60 - `experience_score` (int, optional): Experience score for the job.
61 - `educational_score` (int, optional): Educational score for the job.
62 - `interest_score` (int, optional): Interest score for the job.
63 - `feedback` (str, optional): Additional feedback or comments about the job rating.
64 - `is_skipped` (bool, optional): Indicates whether the rating process was skipped.
65 - `skip_reason` (str, optional): Reason for skipping the rating process.
66 - `is_success` (bool, optional): Indicates whether the rating process was successful.
67 - `error` (str, optional): Error message if the rating process failed.
68 - `job_prompt` (str, optional): Job prompt used for the rating.
69 - `llm_model` (str): LLM model used for the rating.
70 - `notes` (List[str], optional): Additional notes or comments about the rating.
72 Foreign keys:
73 -------------
74 - `scraped_job_id` (int): Identifier for the job being rated.
75 - `user_qualification_id` (int): Identifier for the user qualification entry used to rate the job
76 - `system_prompt_id` (int, optional): Identifier for the AI system prompt used to rate the job.
77 - `job_prompt_template_id` (int, optional): Identifier for the AI job prompt template used to rate the job.
79 Relationships:
80 --------------
81 - `scraped_job` (ScrapedJob): ScrapedJob object related to the rating.
82 - `use_qualification` (UserQualification): UserQualification object related to the rating.
83 - `system_prompt` (AiSystemPrompt, optional): AiSystemPrompt object related to the rating.
84 - `job_prompt_template` (AiJobPromptTemplate, optional): AiJobPromptTemplate object related to the rating."""
86 overall_score = Column(Integer, nullable=True)
87 technical_score = Column(Integer, nullable=True)
88 experience_score = Column(Integer, nullable=True)
89 educational_score = Column(Integer, nullable=True)
90 interest_score = Column(Integer, nullable=True)
91 feedback = Column(String, nullable=True)
92 is_skipped = Column(Boolean, nullable=False, server_default=expression.false())
93 skip_reason = Column(String, nullable=True)
94 is_success = Column(Boolean, nullable=True)
95 error = Column(String, nullable=True)
96 job_prompt = Column(String, nullable=True)
97 llm_model = Column(String, nullable=False)
98 notes = Column(PG_ARRAY(String), server_default="{}", nullable=False)
100 # Foreign keys
101 scraped_job_id = Column(Integer, ForeignKey("scraped_job.id", ondelete="CASCADE"), nullable=False)
102 user_qualification_id = Column(Integer, ForeignKey("user_qualification.id", ondelete="CASCADE"), nullable=False)
103 system_prompt_id = Column(Integer, ForeignKey("ai_system_prompt.id", ondelete="SET NULL"), nullable=True)
104 job_prompt_template_id = Column(
105 Integer, ForeignKey("ai_job_prompt_template.id", ondelete="SET NULL"), nullable=True
106 )
108 # Relationships
109 scraped_job = relationship("ScrapedJob", back_populates="job_rating")
110 user_qualification = relationship("UserQualification", back_populates="job_ratings")
111 system_prompt = relationship("AiSystemPrompt", back_populates="job_ratings")
112 job_prompt_template = relationship("AiJobPromptTemplate", back_populates="job_ratings")
114 def __init__(self, **kwargs) -> None:
115 """Initialise array fields with empty lists if not provided"""
117 kwargs.setdefault("notes", [])
118 super().__init__(**kwargs)
121class JobRatingServiceLog(ServiceLog, CommonBase, Base):
122 """Represents service logs for job ratings.
124 Attributes:
125 -----------
126 - `user_found_ids` (List[int]): List of user IDs that were found during the processing.
127 - `user_processed_ids` (List[int]): List of user IDs that were processed.
128 - `job_found_ids` (List[int]): List of job IDs that were found during the rating process.
129 - `job_succeeded_ids` (List[int]): List of job IDs that were successfully rated.
130 - `job_skipped_ids` (List[int]): List of job IDs that were skipped during the rating process.
131 - `job_failed_ids` (List[int]): List of job IDs that failed to be rated."""
133 user_found_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
134 user_processed_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
135 job_found_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
136 job_succeeded_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
137 job_skipped_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
138 job_failed_ids = Column(PG_ARRAY(Integer), server_default="{}", nullable=False)
140 def __init__(self, **kwargs) -> None:
141 """Initialise array fields with empty lists if not provided"""
143 kwargs.setdefault("user_found_ids", [])
144 kwargs.setdefault("user_processed_ids", [])
145 kwargs.setdefault("job_found_ids", [])
146 kwargs.setdefault("job_succeeded_ids", [])
147 kwargs.setdefault("job_skipped_ids", [])
148 kwargs.setdefault("job_failed_ids", [])
149 super().__init__(**kwargs)