16. Implement Overtime Repository
Let’s create interface for Overtime Repository
ก็ทำเหมือนกันกับ Employee repository เลย
Files and Folders
src18 collapsed lines
├── configure│ └── openapi│ ├── setup-openapi.ts│ └── setup-scalar-docs.ts├── controllers│ ├── employees│ │ ├── delete.ts│ │ ├── get.ts│ │ ├── index.ts│ │ ├── post.ts│ │ └── put.ts│ ├── healthz.ts│ └── overtimes│ ├── get.ts│ ├── index.ts│ └── post.ts├── global.d.ts├── index.ts├── repositories6 collapsed lines
│ ├── employees│ │ ├── creates.ts│ │ ├── finds.ts│ │ ├── index.ts│ │ ├── removes.ts│ │ └── updates.ts│ ├── overtimes│ │ ├── creates.ts│ │ ├── finds.ts│ │ ├── index.ts│ │ ├── removes.ts│ │ └── updates.ts23 collapsed lines
│ └── prisma.ts├── schema│ ├── branded.ts│ ├── employee.ts│ ├── employeeWithRelations.ts│ ├── general.ts│ ├── helpers.ts│ ├── index.ts│ ├── overtime.ts│ └── overtimeWithRelations.ts├── services│ ├── employee│ │ ├── create.ts│ │ ├── finds.ts│ │ ├── index.ts│ │ ├── removes.ts│ │ └── updates.ts│ └── overtime│ ├── creates.ts│ ├── finds.ts│ ├── index.ts│ ├── removes.ts│ └── updates.ts└── types ├── repositories │ ├── employee.ts │ └── overtime.ts3 collapsed lines
└── services ├── employee.ts └── overtime.ts
Overtime Interface
เราจะมาสร้าง interface หรือ type กันก่อน เพื่อให้เห็นภาพรวมก่อนว่าเราจะต้องทำอะไรบ้าง
types/repositories/overtime.ts
import type { Branded, EmployeeSchema, OvertimeSchema, OvertimeWithRelationsSchema } from "../../schema/index.js"
export type OvertimeRepository = { create: (data: OvertimeSchema.CreateOvertime) => Promise<OvertimeSchema.Overtime> findById: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null> findByIdWithRelations: (id: Branded.OvertimeId) => Promise<OvertimeWithRelationsSchema.OvertimeWithRelations | null> findMany: () => Promise<OvertimeSchema.OvertimeArray> findManyWithRelations: () => Promise<OvertimeWithRelationsSchema.OvertimeWithRelationsArray> findByDeparmentName: (departmentName: EmployeeSchema.Employee["department"]) => Promise<OvertimeWithRelationsSchema.OvertimeWithRelationsArray> summaryByEmployeeId: (filters: { employeeId: Branded.EmployeeId, dateRange: { start: Date, end: Date } }) => Promise<{ hoursWorked: number }> summaryByDepartment: (filters: { department: EmployeeSchema.Employee["department"], dateRange: { start: Date, end: Date } }) => Promise<{ hoursWorked: number }> update: (id: Branded.OvertimeId, data: OvertimeSchema.UpdateOvertime) => Promise<OvertimeSchema.Overtime | null> updatePartial: (id: Branded.OvertimeId, data: Partial<OvertimeSchema.UpdateOvertime>) => Promise<OvertimeSchema.Overtime | null> remove: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null> hardRemove: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null>}
Overtime Repository functions
repositories/overtimes/creates.ts
import type { PrismaClient } from "@prisma/client"import type { OvertimeRepository } from "../../types/repositories/overtime.js"import { Helpers, OvertimeSchema } from "../../schema/index.js"
export function create(prismaClient: PrismaClient): OvertimeRepository["create"] { return async (data) => { const overtime = await prismaClient.overtime.create({ data, }) return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime) }}
Finding Overtime Repository functions
เราจะยังทำเหมือนเดิม ทำ Dependency Injection
เขียน find functions ต้องอย่าลืมว่าเราจะไม่เอาตัวที่ถูกทำ soft deleted ไปแล้วนะ
repositories/overtimes/finds.ts
import type { PrismaClient } from "@prisma/client"import type { OvertimeRepository } from "../../types/repositories/overtime.js"import { Helpers, OvertimeSchema, OvertimeWithRelationsSchema } from "../../schema/index.js"
export function findById(prismaClient: PrismaClient): OvertimeRepository["findById"] { return async (id) => { const overtime = await prismaClient.overtime.findUnique({ where: { deletedAt: null, id, }, }) if (overtime === null) return null
return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime) }}
export function findByIdWithRelations(prismaClient: PrismaClient): OvertimeRepository["findByIdWithRelations"] { return async (id) => { const overtime = await prismaClient.overtime.findUnique({ include: { employee: true, }, where: { deletedAt: null, id, }, }) if (overtime === null) return null return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.Schema)(overtime) }}
export function findMany(prismaClient: PrismaClient): OvertimeRepository["findMany"] { return async () => { const overtimes = await prismaClient.overtime.findMany({ where: { deletedAt: null, }, }) return Helpers.fromObjectToSchema(OvertimeSchema.SchemaArray)(overtimes) }}
export function findManyWithRelations(prismaClient: PrismaClient): OvertimeRepository["findManyWithRelations"] { return async () => { const overtimes = await prismaClient.overtime.findMany({ include: { employee: true, }, where: { deletedAt: null, }, }) return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.SchemaArray)(overtimes) }}
export function findByDeparmentName(prismaClient: PrismaClient): OvertimeRepository["findByDeparmentName"] { return async (departmentName) => { const overtimes = await prismaClient.overtime.findMany({ include: { employee: true, }, where: { deletedAt: null, employee: { department: departmentName, }, }, }) return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.SchemaArray)(overtimes) }}
export function summaryByEmployeeId(prismaClient: PrismaClient): OvertimeRepository["summaryByEmployeeId"] { return async (filters) => { const agg = await prismaClient.overtime.aggregate({ _sum: { hoursWorked: true, }, where: { date: { gte: filters.dateRange.start, lt: filters.dateRange.end, }, employee: { id: filters.employeeId, }, }, }) if (agg._sum.hoursWorked === null) { return { hoursWorked: 0, } } return { hoursWorked: agg._sum.hoursWorked, } }}
export function summaryByDepartment(prismaClient: PrismaClient): OvertimeRepository["summaryByDepartment"] { return async (filters) => { const agg = await prismaClient.overtime.aggregate({ _sum: { hoursWorked: true, }, where: { date: { gte: filters.dateRange.start, lt: filters.dateRange.end, }, employee: { department: filters.department, }, }, }) if (agg._sum.hoursWorked === null) { return { hoursWorked: 0, } } return { hoursWorked: agg._sum.hoursWorked, } }}
จากด้านบนเรามีการทำการ find แบบปกติ
แต่ที่เพิ่มมาคือการทำ aggregate จาก function summaryByEmployeeId()
, summaryByDepartment()
Updating Overtime Repository functions
repositories/overtimes/updates.ts
import type { PrismaClient } from "@prisma/client"import type { OvertimeRepository } from "../../types/repositories/overtime.js"import { Helpers, OvertimeSchema } from "../../schema/index.js"
export function update(prismaClient: PrismaClient): OvertimeRepository["update"] { return async (id, data) => { const overtime = await prismaClient.overtime.update({ data, where: { id, }, }) return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime) }}
export function updatePartial(prismaClient: PrismaClient): OvertimeRepository["updatePartial"] { return async (id, data) => { const overtime = await prismaClient.overtime.update({ data, where: { id, }, }) return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime) }}
Remove Overtime functions
repositories/overtimes/removes.ts
import type { PrismaClient } from "@prisma/client"import type { OvertimeRepository } from "../../types/repositories/overtime.js"import { Helpers, OvertimeSchema } from "../../schema/index.js"
export function removeById(prismaClient: PrismaClient): OvertimeRepository["remove"] { return async (id) => { const data = await prismaClient.overtime.update({ data: { deletedAt: new Date(), }, where: { id, }, })
if (data === null) return null return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(data) }}
export function hardRemoveById(prismaClient: PrismaClient): OvertimeRepository["hardRemove"] { return async (id) => { const data = await prismaClient.overtime.delete({ where: { id, }, })
if (data === null) return null return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(data) }}