Files
edr-platform/apps/edr-hr-api/src/modules/job-titles/job-titles.repository.ts
2026-08-25 00:11:39 +03:00

71 lines
2.2 KiB
TypeScript

import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { BaseRepository } from "@edr/api-common";
import { Repository } from "typeorm";
import { JobTitle } from "./entities/job-title.entity";
@Injectable()
export class JobTitlesRepository extends BaseRepository<JobTitle> {
constructor(
@InjectRepository(JobTitle) repository: Repository<JobTitle>,
) {
super(repository);
}
findByCode(organizationId: string, code: string): Promise<JobTitle | null> {
return this.repository.findOne({ where: { organizationId, code } });
}
async findPage(
organizationId: string | null,
filters: {
search?: string;
isActive?: boolean;
page?: number;
limit?: number;
sortOrder?: "ASC" | "DESC";
},
): Promise<[JobTitle[], number]> {
const page = filters.page ?? 1;
const limit = filters.limit ?? 25;
const qb = this.repository.createQueryBuilder("title").where("1 = 1");
// `null` = every organization (super admin).
if (organizationId) {
qb.andWhere("title.organization_id = :organizationId", { organizationId });
}
if (filters.isActive !== undefined) {
qb.andWhere("title.is_active = :isActive", { isActive: filters.isActive });
}
if (filters.search) {
// Both locales of the jsonb name, plus the code.
qb.andWhere(
`(title.code ILIKE :search OR title.name->>'en' ILIKE :search OR title.name->>'am' ILIKE :search)`,
{ search: `%${filters.search}%` },
);
}
return qb
.orderBy("title.gradeLevel", filters.sortOrder ?? "ASC")
.addOrderBy("title.code", "ASC")
.skip((page - 1) * limit)
.take(limit)
.getManyAndCount();
}
/** How many profiles reference this title — the guard against deleting a
* title that salary structures and employees still point at. */
async countEmployeesUsing(jobTitleId: string): Promise<number> {
const row = await this.repository.manager.query<{ count: string }[]>(
`SELECT COUNT(*)::text AS count
FROM hr.employee_profiles
WHERE job_title_id = $1 AND deleted_at IS NULL`,
[jobTitleId],
);
return parseInt(row[0]?.count ?? "0", 10);
}
}