Skip to content

Commit

Permalink
feat(module): ✨ added muscles module
Browse files Browse the repository at this point in the history
-  create Muscle Endpoint

- retrive all Muscles endpoint
  • Loading branch information
cyberboyanmol committed Aug 23, 2024
1 parent 7d07049 commit 4d0f63e
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 7 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@eslint/js": "^9.9.0",
"@types/bun": "latest",
"@types/ioredis": "^5.0.0",
"@types/mongoose": "^5.11.97",
"@types/node": "^22.5.0",
"@typescript-eslint/parser": "^8.2.0",
"@vitest/ui": "^2.0.5",
Expand Down
2 changes: 1 addition & 1 deletion src/common/types/use-case.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ interface Obj {
[key: string]: any
}

export interface IUseCase<T extends Obj | string = any, TRes = any> {
export interface IUseCase<T extends Obj | string | void = any, TRes = any> {
execute: (params: T) => Promise<TRes>
}
7 changes: 4 additions & 3 deletions src/infra/mongodb/models/muscles/muscle.entity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Document, Model } from 'mongoose'

import mongoose, { Document, Model } from 'mongoose'
export interface IMuscle {
name: string
}
export interface IMuscleDoc extends IMuscle, Document {}
export type IMuscleModel = Model<IMuscleDoc>
export interface IMuscleModel extends Model<IMuscleDoc> {
isMuscleExist(name: string, excludeMuscleId?: mongoose.ObjectId): Promise<boolean>
}
20 changes: 19 additions & 1 deletion src/infra/mongodb/models/muscles/muscle.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,26 @@ const muscleSchema = new mongoose.Schema<IMuscleDoc, IMuscleModel>(
timestamps: true
}
)

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

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

muscleSchema.static(
'isMuscleExist',
async function (name: string, excludeMuscleId: mongoose.ObjectId): Promise<boolean> {
const muscle = await this.findOne({
name,
_id: { $ne: excludeMuscleId }
})
return !!muscle
}
)

const Muscle = mongoose.model<IMuscleDoc, IMuscleModel>('Muscle', muscleSchema)

export default Muscle
Empty file.
122 changes: 122 additions & 0 deletions src/modules/muscle/controllers/muscle.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 { MuscleModel } from '../models/muscle.model'
import { MuscleService } from '../services'
import Muscle from '#infra/mongodb/models/muscles/muscle.schema.js'

export class MuscleController implements Routes {
public controller: OpenAPIHono
private readonly muscleService: MuscleService
constructor() {
this.controller = new OpenAPIHono()
this.muscleService = new MuscleService(Muscle)
}

public initRoutes() {
this.controller.openapi(
createRoute({
method: 'post',
path: '/muscles',
tags: ['Muscles'],
summary: 'Add a new muscle to the database',
description: 'This route is used to add a new muscle name to the database.',
operationId: 'createMuscle',
request: {
body: {
content: {
'application/json': {
schema: z.object({
name: z.string().openapi({
title: 'Muscle Name',
description: 'The name of the muscle to be added',
type: 'string',
example: 'Biceps Brachii'
})
})
}
}
}
},
responses: {
201: {
description: 'Muscle 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(MuscleModel).openapi({
title: 'Added Muscle',
description: 'The newly added muscle data'
})
})
}
}
},
400: {
description: 'Bad request - Invalid input data',
content: {
'application/json': {
schema: z.object({
success: z.boolean(),
error: z.string()
})
}
}
},
409: {
description: 'Conflict - Muscle name already exists'
},
500: {
description: 'Internal server error'
}
}
}),
async (ctx) => {
const body = await ctx.req.json()
const response = await this.muscleService.createMuscle(body)
return ctx.json({ success: true, data: response })
}
)
this.controller.openapi(
createRoute({
method: 'get',
path: '/muscles',
tags: ['Muscles'],
summary: 'Retrive all muscles.',
description: 'Retrive list of all the muscles.',
operationId: 'getMuscles',
responses: {
200: {
description: 'Successful response with list of all muscles.',
content: {
'application/json': {
schema: z.object({
success: z.boolean().openapi({
description: 'Indicates whether the request was successful',
type: 'boolean',
example: true
}),
data: z.array(MuscleModel).openapi({
description: 'Array of Muslces.'
})
})
}
}
},
500: {
description: 'Internal server error'
}
}
}),
async (ctx) => {
const response = await this.muscleService.getMuscles()
return ctx.json({ success: true, data: response })
}
)
}
}
5 changes: 5 additions & 0 deletions src/modules/muscle/models/muscle.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from 'zod'

export const MuscleModel = z.object({
name: z.string()
})
1 change: 1 addition & 0 deletions src/modules/muscle/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './muscle.service'
21 changes: 21 additions & 0 deletions src/modules/muscle/services/muscle.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IMuscleModel } from '#infra/mongodb/models/muscles/muscle.entity.js'
import { CreateMuscleArgs, CreateMuscleUseCase } from '../use-cases/create-muscle'
import { GetMusclesUseCase } from '../use-cases/get-muscles'

export class MuscleService {
private readonly createMuscleUseCase: CreateMuscleUseCase
private readonly getMuscleUseCase: GetMusclesUseCase

constructor(private readonly muscleModel: IMuscleModel) {
this.createMuscleUseCase = new CreateMuscleUseCase(muscleModel)
this.getMuscleUseCase = new GetMusclesUseCase(muscleModel)
}

createMuscle = (args: CreateMuscleArgs) => {
return this.createMuscleUseCase.execute(args)
}

getMuscles = () => {
return this.getMuscleUseCase.execute()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IUseCase } from '#common/types/use-case.type.js'
import { IMuscleDoc, IMuscleModel } from '#infra/mongodb/models/muscles/muscle.entity.js'
import { HTTPException } from 'hono/http-exception'

export interface CreateMuscleArgs {
name: string
}

export class CreateMuscleUseCase implements IUseCase<CreateMuscleArgs, IMuscleDoc> {
constructor(private readonly muscleModel: IMuscleModel) {}

async execute({ name }: CreateMuscleArgs): Promise<IMuscleDoc> {
await this.checkIfMuscleExists(name)
return this.createMuscle(name)
}

private async checkIfMuscleExists(name: string): Promise<void> {
if (await this.muscleModel.isMuscleExist(name)) {
throw new HTTPException(409, { message: 'Muscle name already exists' })
}
}

private async createMuscle(name: string): Promise<IMuscleDoc> {
return this.muscleModel.create({ name })
}
}
1 change: 1 addition & 0 deletions src/modules/muscle/use-cases/create-muscle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './create-muscle.use-case'
10 changes: 10 additions & 0 deletions src/modules/muscle/use-cases/get-muscles/get-muscle.usecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IUseCase } from '#common/types/use-case.type.js'
import { IMuscleDoc, IMuscleModel } from '#infra/mongodb/models/muscles/muscle.entity.js'

export class GetMusclesUseCase implements IUseCase<void, IMuscleDoc[]> {
constructor(private readonly muscleModel: IMuscleModel) {}

async execute(): Promise<IMuscleDoc[]> {
return this.muscleModel.find({})
}
}
1 change: 1 addition & 0 deletions src/modules/muscle/use-cases/get-muscles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './get-muscle.usecase'
5 changes: 3 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DalService } from '#infra/mongodb/dal.service.js'
import { MuscleController } from '#modules/muscle/controllers/muscle.controller.js'
import { App } from './app'

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

export default app

0 comments on commit 4d0f63e

Please sign in to comment.