ก็ทำเหมือนกันกับ Employee repository เลย
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
เราจะมาสร้าง interface หรือ type กันก่อน เพื่อให้เห็นภาพรวมก่อนว่าเราจะต้องทำอะไรบ้าง
1import type { Branded, EmployeeSchema, OvertimeSchema, OvertimeWithRelationsSchema } from "../../schema/index.js"2 3export type OvertimeRepository = {4 create: (data: OvertimeSchema.CreateOvertime) => Promise<OvertimeSchema.Overtime>5 findById: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null>6 findByIdWithRelations: (id: Branded.OvertimeId) => Promise<OvertimeWithRelationsSchema.OvertimeWithRelations | null>7 findMany: () => Promise<OvertimeSchema.OvertimeArray>8 findManyWithRelations: () => Promise<OvertimeWithRelationsSchema.OvertimeWithRelationsArray>9 findByDeparmentName: (departmentName: EmployeeSchema.Employee["department"]) => Promise<OvertimeWithRelationsSchema.OvertimeWithRelationsArray>10 summaryByEmployeeId: (filters: { employeeId: Branded.EmployeeId, dateRange: { start: Date, end: Date } }) => Promise<{ hoursWorked: number }>11 summaryByDepartment: (filters: { department: EmployeeSchema.Employee["department"], dateRange: { start: Date, end: Date } }) => Promise<{ hoursWorked: number }>12 update: (id: Branded.OvertimeId, data: OvertimeSchema.UpdateOvertime) => Promise<OvertimeSchema.Overtime | null>13 updatePartial: (id: Branded.OvertimeId, data: Partial<OvertimeSchema.UpdateOvertime>) => Promise<OvertimeSchema.Overtime | null>14 remove: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null>15 hardRemove: (id: Branded.OvertimeId) => Promise<OvertimeSchema.Overtime | null>16}
1import type { PrismaClient } from "@prisma/client"2import type { OvertimeRepository } from "../../types/repositories/overtime.js"3import { Helpers, OvertimeSchema } from "../../schema/index.js"4 5export function create(prismaClient: PrismaClient): OvertimeRepository["create"] {6 return async (data) => {7 const overtime = await prismaClient.overtime.create({8 data,9 })10 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime)11 }12}
เราจะยังทำเหมือนเดิม ทำ Dependency Injection
เขียน find functions ต้องอย่าลืมว่าเราจะไม่เอาตัวที่ถูกทำ soft deleted ไปแล้วนะ
1import type { PrismaClient } from "@prisma/client"2import type { OvertimeRepository } from "../../types/repositories/overtime.js"3import { Helpers, OvertimeSchema, OvertimeWithRelationsSchema } from "../../schema/index.js"4 5export function findById(prismaClient: PrismaClient): OvertimeRepository["findById"] {6 return async (id) => {7 const overtime = await prismaClient.overtime.findUnique({8 where: {9 deletedAt: null,10 id,11 },12 })13 if (overtime === null)14 return null15 16 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime)17 }18}19 20export function findByIdWithRelations(prismaClient: PrismaClient): OvertimeRepository["findByIdWithRelations"] {21 return async (id) => {22 const overtime = await prismaClient.overtime.findUnique({23 include: {24 employee: true,25 },26 where: {27 deletedAt: null,28 id,29 },30 })31 if (overtime === null)32 return null33 return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.Schema)(overtime)34 }35}36 37export function findMany(prismaClient: PrismaClient): OvertimeRepository["findMany"] {38 return async () => {39 const overtimes = await prismaClient.overtime.findMany({40 where: {41 deletedAt: null,42 },43 })44 return Helpers.fromObjectToSchema(OvertimeSchema.SchemaArray)(overtimes)45 }46}47 48export function findManyWithRelations(prismaClient: PrismaClient): OvertimeRepository["findManyWithRelations"] {49 return async () => {50 const overtimes = await prismaClient.overtime.findMany({51 include: {52 employee: true,53 },54 where: {55 deletedAt: null,56 },57 })58 return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.SchemaArray)(overtimes)59 }60}61 62export function findByDeparmentName(prismaClient: PrismaClient): OvertimeRepository["findByDeparmentName"] {63 return async (departmentName) => {64 const overtimes = await prismaClient.overtime.findMany({65 include: {66 employee: true,67 },68 where: {69 deletedAt: null,70 employee: {71 department: departmentName,72 },73 },74 })75 return Helpers.fromObjectToSchema(OvertimeWithRelationsSchema.SchemaArray)(overtimes)76 }77}78 79export function summaryByEmployeeId(prismaClient: PrismaClient): OvertimeRepository["summaryByEmployeeId"] {80 return async (filters) => {81 const agg = await prismaClient.overtime.aggregate({82 _sum: {83 hoursWorked: true,84 },85 where: {86 date: {87 gte: filters.dateRange.start,88 lt: filters.dateRange.end,89 },90 employee: {91 id: filters.employeeId,92 },93 },94 })95 if (agg._sum.hoursWorked === null) {96 return {97 hoursWorked: 0,98 }99 }100 return {101 hoursWorked: agg._sum.hoursWorked,102 }103 }104}105 106export function summaryByDepartment(prismaClient: PrismaClient): OvertimeRepository["summaryByDepartment"] {107 return async (filters) => {108 const agg = await prismaClient.overtime.aggregate({109 _sum: {110 hoursWorked: true,111 },112 where: {113 date: {114 gte: filters.dateRange.start,115 lt: filters.dateRange.end,116 },117 employee: {118 department: filters.department,119 },120 },121 })122 if (agg._sum.hoursWorked === null) {123 return {124 hoursWorked: 0,125 }126 }127 return {128 hoursWorked: agg._sum.hoursWorked,129 }130 }131}
จากด้านบนเรามีการทำการ find แบบปกติ แต่ที่เพิ่มมาคือการทำ aggregate จาก function summaryByEmployeeId(), summaryByDepartment()
summaryByEmployeeId()
summaryByDepartment()
1import type { PrismaClient } from "@prisma/client"2import type { OvertimeRepository } from "../../types/repositories/overtime.js"3import { Helpers, OvertimeSchema } from "../../schema/index.js"4 5export function update(prismaClient: PrismaClient): OvertimeRepository["update"] {6 return async (id, data) => {7 const overtime = await prismaClient.overtime.update({8 data,9 where: {10 id,11 },12 })13 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime)14 }15}16 17export function updatePartial(prismaClient: PrismaClient): OvertimeRepository["updatePartial"] {18 return async (id, data) => {19 const overtime = await prismaClient.overtime.update({20 data,21 where: {22 id,23 },24 })25 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(overtime)26 }27}
1import type { PrismaClient } from "@prisma/client"2import type { OvertimeRepository } from "../../types/repositories/overtime.js"3import { Helpers, OvertimeSchema } from "../../schema/index.js"4 5export function removeById(prismaClient: PrismaClient): OvertimeRepository["remove"] {6 return async (id) => {7 const data = await prismaClient.overtime.update({8 data: {9 deletedAt: new Date(),10 },11 where: {12 id,13 },14 })15 16 if (data === null)17 return null18 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(data)19 }20}21 22export function hardRemoveById(prismaClient: PrismaClient): OvertimeRepository["hardRemove"] {23 return async (id) => {24 const data = await prismaClient.overtime.delete({25 where: {26 id,27 },28 })29 30 if (data === null)31 return null32 return Helpers.fromObjectToSchema(OvertimeSchema.Schema)(data)33 }34}