Skip to content

Commit

Permalink
feat(modules): ✨ added bodyPart module
Browse files Browse the repository at this point in the history
add create bodypart endpoint

 add get all bodyparts
  • Loading branch information
cyberboyanmol committed Aug 23, 2024
1 parent 7c1cda1 commit 84a556f
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 4 deletions.
6 changes: 4 additions & 2 deletions src/infra/mongodb/models/bodyparts/bodypart.entity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Document, Model } from 'mongoose'
import mongoose, { Document, Model } from 'mongoose'

export interface IBodyPart {
name: string
}
export interface IBodyPartDoc extends IBodyPart, Document {}
export type IBodyPartModel = Model<IBodyPartDoc>
export interface IBodyPartModel extends Model<IBodyPartDoc> {
isBodyPartExist(name: string, excludeBodyPartId?: mongoose.ObjectId): Promise<boolean>
}
18 changes: 18 additions & 0 deletions src/infra/mongodb/models/bodyparts/bodypart.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,25 @@ const bodyPartSchema = new mongoose.Schema<IBodyPartDoc, IBodyPartModel>(
}
)

// add plugin that converts mongoose to json
bodyPartSchema.plugin(toJSON)

/**
* check if the similar bodyPart name already exists
* @param {string} name
*@returns {Promise<boolean>}
*/

bodyPartSchema.static(
'isBodyPartExist',
async function (name: string, excludeBodyPartId: mongoose.ObjectId): Promise<boolean> {
const bodyPart = await this.findOne({
name,
_id: { $ne: excludeBodyPartId }
})
return !!bodyPart
}
)
const BodyPart = mongoose.model<IBodyPartDoc, IBodyPartModel>('BodyPart', bodyPartSchema)

export default BodyPart
122 changes: 122 additions & 0 deletions src/modules/bodyparts/controllers/bodyPart.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Routes } from '#common/types/route.type.js'
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { z } from 'zod'
import { BodyPartService } from '../services'
import BodyPart from '#infra/mongodb/models/bodyparts/bodypart.schema.js'
import { BodyPartModel } from '../models/bodyPart.model'

export class BodyPartController implements Routes {
public controller: OpenAPIHono
private readonly bodyPartService: BodyPartService
constructor() {
this.controller = new OpenAPIHono()
this.bodyPartService = new BodyPartService(BodyPart)
}

public initRoutes() {
this.controller.openapi(
createRoute({
method: 'post',
path: '/bodyparts',
tags: ['BodyParts'],
summary: 'Add a new bodyPart to the database',
description: 'This route is used to add a new bodyPart name to the database.',
operationId: 'createbodyPart',
request: {
body: {
content: {
'application/json': {
schema: z.object({
name: z.string().openapi({
title: 'BodyPart Name',
description: 'The name of the bodyPart to be added',
type: 'string',
example: 'waist'
})
})
}
}
}
},
responses: {
201: {
description: 'bodyPart successfully added to the database',
content: {
'application/json': {
schema: z.object({
success: z.boolean().openapi({
description: 'Indicates whether the request was successful',
type: 'boolean',
example: true
}),
data: z.array(BodyPartModel).openapi({
title: 'Added bodyPart',
description: 'The newly added bodyPart data'
})
})
}
}
},
400: {
description: 'Bad request - Invalid input data',
content: {
'application/json': {
schema: z.object({
success: z.boolean(),
error: z.string()
})
}
}
},
409: {
description: 'Conflict - bodyPart name already exists'
},
500: {
description: 'Internal server error'
}
}
}),
async (ctx) => {
const body = await ctx.req.json()
const response = await this.bodyPartService.createBodyPart(body)
return ctx.json({ success: true, data: [response] })
}
)
this.controller.openapi(
createRoute({
method: 'get',
path: '/bodyparts',
tags: ['BodyParts'],
summary: 'Retrive all bodyParts.',
description: 'Retrive list of all bodyparts.',
operationId: 'getBodyParts',
responses: {
200: {
description: 'Successful response with list of all bodyparts.',
content: {
'application/json': {
schema: z.object({
success: z.boolean().openapi({
description: 'Indicates whether the request was successful',
type: 'boolean',
example: true
}),
data: z.array(BodyPartModel).openapi({
description: 'Array of bodyparts.'
})
})
}
}
},
500: {
description: 'Internal server error'
}
}
}),
async (ctx) => {
const response = await this.bodyPartService.getBodyParts()
return ctx.json({ success: true, data: response })
}
)
}
}
1 change: 1 addition & 0 deletions src/modules/bodyparts/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './bodyPart.controller'
4 changes: 4 additions & 0 deletions src/modules/bodyparts/models/bodyPart.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { z } from 'zod'
export const BodyPartModel = z.object({
name: z.string()
})
21 changes: 21 additions & 0 deletions src/modules/bodyparts/services/body-part.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IBodyPartModel } from '#infra/mongodb/models/bodyparts/bodypart.entity.js'
import { CreateBodyPartArgs, CreateBodyPartUseCase } from '../use-cases/create-bodypart'
import { GetBodyPartsUseCase } from '../use-cases/get-bodyparts'

export class BodyPartService {
private readonly createBodyPartUseCase: CreateBodyPartUseCase
private readonly getBodyPartsUseCase: GetBodyPartsUseCase

constructor(private readonly bodyPartModel: IBodyPartModel) {
this.createBodyPartUseCase = new CreateBodyPartUseCase(bodyPartModel)
this.getBodyPartsUseCase = new GetBodyPartsUseCase(bodyPartModel)
}

createBodyPart = (args: CreateBodyPartArgs) => {
return this.createBodyPartUseCase.execute(args)
}

getBodyParts = () => {
return this.getBodyPartsUseCase.execute()
}
}
1 change: 1 addition & 0 deletions src/modules/bodyparts/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './body-part.service'
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IUseCase } from '#common/types/use-case.type.js'
import { IBodyPartDoc, IBodyPartModel } from '#infra/mongodb/models/bodyparts/bodypart.entity.js'
import { HTTPException } from 'hono/http-exception'

export interface CreateBodyPartArgs {
name: string
}

export class CreateBodyPartUseCase implements IUseCase<CreateBodyPartArgs, IBodyPartDoc> {
constructor(private readonly bodyPartModel: IBodyPartModel) {}

async execute({ name }: CreateBodyPartArgs): Promise<IBodyPartDoc> {
await this.checkIfBodyPartExists(name)
return this.createBodyPart(name)
}

private async checkIfBodyPartExists(name: string): Promise<void> {
if (await this.bodyPartModel.isBodyPartExist(name)) {
throw new HTTPException(409, { message: 'BodyPart name already exists' })
}
}

private async createBodyPart(name: string): Promise<IBodyPartDoc> {
return this.bodyPartModel.create({ name })
}
}
1 change: 1 addition & 0 deletions src/modules/bodyparts/use-cases/create-bodypart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './create-bodypart.use-case'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IUseCase } from '#common/types/use-case.type.js'
import { IBodyPartDoc, IBodyPartModel } from '#infra/mongodb/models/bodyparts/bodypart.entity.js'

export class GetBodyPartsUseCase implements IUseCase<void, IBodyPartDoc[]> {
constructor(private readonly bodyPartModel: IBodyPartModel) {}

async execute(): Promise<IBodyPartDoc[]> {
return this.bodyPartModel.find({})
}
}
1 change: 1 addition & 0 deletions src/modules/bodyparts/use-cases/get-bodyparts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './get-bodypart.usecase'
1 change: 0 additions & 1 deletion src/modules/equipments/controllers/equipment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { z } from 'zod'
import { EquipmentModel } from '../models/equipment.model'
import { EquipmentService } from '../services'
import Muscle from '#infra/mongodb/models/muscles/muscle.schema.js'
import Equipment from '#infra/mongodb/models/equipments/equipment.schema.js'

export class EquipmentController implements Routes {
Expand Down
3 changes: 2 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { DalService } from '#infra/mongodb/dal.service.js'
import { BodyPartController } from '#modules/bodyparts/controllers/bodyPart.controller.js'
import { EquipmentController } from '#modules/equipments/controllers/equipment.controller.js'
import { MuscleController } from '#modules/muscle/controllers'
import { App } from './app'

const dalService = new DalService()
const app = new App([new MuscleController(), new EquipmentController()]).getApp()
const app = new App([new MuscleController(), new EquipmentController(), new BodyPartController()]).getApp()
await dalService.connectDB()

export default app

0 comments on commit 84a556f

Please sign in to comment.