Coverage for backend / app / data_tables / schemas.py: 100%
157 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"""Schemas for the JAM database
2Create schemas should be used to create entries in the database.
3Out schemas should be used to return data to the user.
4Min schemas should be used to return minimal data to the user (enough to display the entry as a badge) and should not
5contain reference to other tables.
6Update schemas should be used to update existing entries in the database."""
8from datetime import datetime
10from pydantic import BaseModel, field_validator
12from app.base_schemas import OwnedOut, EmailField, serialise_relationships
15# ------------------------------------------------------- KEYWORD ------------------------------------------------------
18class KeywordCreate(BaseModel):
19 """Keyword create schema"""
21 name: str
24class KeywordOut(KeywordCreate, OwnedOut):
25 """Keyword output schema with full job data"""
27 jobs: list[OwnedOut] = []
30class KeywordUpdate(KeywordCreate):
31 """Keyword update schema"""
33 name: str | None = None
36# ----------------------------------------------------- AGGREGATOR -----------------------------------------------------
39class AggregatorCreate(BaseModel):
40 """Aggregator create schema"""
42 name: str
43 url: str | None = None
46class AggregatorOut(AggregatorCreate, OwnedOut):
47 """Aggregator output schema with full job data and job applications"""
49 jobs: list[OwnedOut] = []
50 job_applications: list[OwnedOut] = []
53class AggregatorUpdate(AggregatorCreate):
54 """Aggregator update schema"""
56 name: str | None = None
59# ------------------------------------------------------- COMPANY ------------------------------------------------------
62class CompanyCreate(BaseModel):
63 """Company create schema"""
65 name: str
66 description: str | None = None
67 url: str | None = None
70class CompanyOut(CompanyCreate, OwnedOut):
71 """Company output schema with job data and individuals"""
73 jobs: list[OwnedOut] = []
74 persons: list[OwnedOut] = []
75 recruited_jobs: list[OwnedOut] = []
78class CompanyUpdate(CompanyCreate):
79 """Company update schema"""
81 name: str | None = None
84# ------------------------------------------------------ GEOLOCATION ------------------------------------------------------
87class GeolocationOut(BaseModel):
88 """Geolocation output schema"""
90 query: str
91 latitude: float | None = None
92 longitude: float | None = None
93 postcode: str | None = None
94 city: str | None = None
95 country: str | None = None
96 formatted_address: str | None = None
99# ------------------------------------------------------ LOCATION ------------------------------------------------------
102class LocationCreate(BaseModel):
103 """Location create schema"""
105 postcode: str | None = None
106 city: str | None = None
107 country: str | None = None
110class LocationOut(LocationCreate, OwnedOut):
111 """Location output schema with job and interview data"""
113 name: str | None = None
114 geolocation: GeolocationOut | None = None
115 jobs: list[OwnedOut] = []
116 interviews: list[OwnedOut] = []
119class LocationUpdate(LocationCreate):
120 """Location update schema"""
122 pass
125# -------------------------------------------------------- FILES -------------------------------------------------------
128class FileCreate(BaseModel):
129 """File create schema"""
131 filename: str
132 type: str
133 content: str
134 size: int
137class FileOut(FileCreate, OwnedOut):
138 """File output schema"""
140 pass
143class FileUpdate(FileCreate):
144 """File update schema"""
146 filename: str | None = None
147 type: str | None = None
148 content: str | None = None
149 size: int | None = None
152# ------------------------------------------------------- PERSON -------------------------------------------------------
155class PersonCreate(BaseModel):
156 """Person create schema"""
158 first_name: str
159 last_name: str
160 email: EmailField | None = None
161 phone: str | None = None
162 linkedin_url: str | None = None
163 role: str | None = None
164 is_recruiter: bool = False
166 # Foreign keys
167 company_id: int | None = None
170class PersonOut(PersonCreate, OwnedOut):
171 """Person out schema with job data and bare interview data"""
173 interviews: list[OwnedOut] = []
174 jobs: list[OwnedOut] = []
175 recruited_jobs: list[OwnedOut] = []
176 name: str | None = None
179class PersonUpdate(PersonCreate):
180 """Person update schema"""
182 first_name: str | None = None
183 last_name: str | None = None
186# --------------------------------------------------------- JOB --------------------------------------------------------
189class JobCreate(BaseModel):
190 """Job create schema"""
192 title: str
193 description: str | None = None
194 salary_min: float | None = None
195 salary_max: float | None = None
196 salary_currency: str | None = None
197 personal_rating: int | None = None
198 url: str | None = None
199 deadline: datetime | None = None
200 note: str | None = None
201 attendance_type: str | None = None
202 application_date: datetime | None = None
203 application_url: str | None = None
204 application_status: str | None = None
205 application_note: str | None = None
206 applied_via: str | None = None
207 source_type: str | None = None
208 followup_snooze_datetime: datetime | None = None
210 # Foreign keys
211 company_id: int | None = None
212 location_id: int | None = None
213 duplicate_id: int | None = None
214 source_aggregator_id: int | None = None
215 application_aggregator_id: int | None = None
216 recruiter_id: int | None = None
217 recruitment_company_id: int | None = None
218 cv_id: int | None = None
219 cover_letter_id: int | None = None
220 keywords: list[int] = []
221 contacts: list[int] = []
224class JobOut(JobCreate, OwnedOut):
225 """Job output schema with IDs of related entities"""
227 keywords: list[int] = []
228 contacts: list[int] = []
229 interviews: list[OwnedOut] = []
230 updates: list[OwnedOut] = []
232 @field_validator("keywords", "contacts", mode="before")
233 @classmethod
234 def serialize_relationships(cls, value) -> list[int]:
235 """Serialize relationships to list of IDs"""
236 return serialise_relationships(value)
239class JobUpdate(JobCreate):
240 """Job update schema"""
242 title: str | None = None
245# ------------------------------------------------------ INTERVIEW -----------------------------------------------------
248class InterviewCreate(BaseModel):
249 """Interview create schema"""
251 date: datetime
252 type: str
253 job_id: int
254 attendance_type: str | None = None
255 location_id: int | None = None
256 note: str | None = None
257 interviewers: list[int] | None = None
260class InterviewOut(InterviewCreate, OwnedOut):
261 """Interview output with bare location and person data, and job data"""
263 interviewers: list[int] = []
265 @field_validator("interviewers", mode="before")
266 @classmethod
267 def serialize_relationships(cls, value) -> list[int]:
268 """Serialize relationships to list of IDs"""
269 return serialise_relationships(value)
272class InterviewUpdate(InterviewCreate):
273 """Interview update schema"""
275 date: datetime | None = None
276 type: str | None = None
277 job_id: int | None = None
280# ----------------------------------------------- JOB APPLICATION UPDATE -----------------------------------------------
283class JobApplicationUpdateCreate(BaseModel):
284 """Job Application Update create schema"""
286 date: datetime
287 type: str
288 job_id: int
289 note: str | None = None
292class JobApplicationUpdateOut(JobApplicationUpdateCreate, OwnedOut):
293 """Job Application Update output schema with job data"""
295 pass
298class JobApplicationUpdateUpdate(JobApplicationUpdateCreate):
299 """Job Application Update update schema"""
301 date: datetime | None = None
302 type: str | None = None
303 job_id: int | None = None
306# ----------------------------------------------- SPECULATIVE APPLICATION ----------------------------------------------
309class SpeculativeApplicationCreate(BaseModel):
310 """Speculative application create schema"""
312 date: datetime | None = None
313 note: str | None = None
314 contact_email: str | None = None
316 # Foreign keys
317 company_id: int
318 contacts: list[int] = []
321class SpeculativeApplicationOut(SpeculativeApplicationCreate, OwnedOut):
322 """Speculative application output schema"""
324 @field_validator("contacts", mode="before")
325 @classmethod
326 def serialize_relationships(cls, value) -> list[int]:
327 """Serialize relationships to list of IDs"""
328 return serialise_relationships(value)
331class SpeculativeApplicationUpdate(SpeculativeApplicationCreate):
332 """Speculative application update schema"""
334 company_id: int | None = None