Skip to content

Commit

Permalink
Drink resource (#13)
Browse files Browse the repository at this point in the history
* drink dtos, controller and service

* swagger improvements

* more comments
  • Loading branch information
Tschonti authored May 19, 2024
1 parent 56f2d96 commit d6a5be0
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 2 deletions.
3 changes: 2 additions & 1 deletion apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { PrismaModule } from 'nestjs-prisma';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DrinksModule } from './drinks/drinks.module';
import { EventsModule } from './events/events.module';
import { UsersModule } from './users/users.module';

@Module({
imports: [PrismaModule.forRoot({ isGlobal: true }), UsersModule, EventsModule],
imports: [PrismaModule.forRoot({ isGlobal: true }), UsersModule, EventsModule, DrinksModule],
controllers: [AppController],
providers: [AppService],
})
Expand Down
38 changes: 38 additions & 0 deletions apps/backend/src/drinks/drinks.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';

import { DrinksService } from './drinks.service';
import { CreateDrinkDto } from './dto/create-drink.dto';
import { UpdateDrinkDto } from './dto/update-drink.dto';
import { Drink } from './entities/drink.entity';

@ApiTags('Drinks')
@Controller('drinks')
export class DrinksController {
constructor(private readonly drinksService: DrinksService) {}

@Post()
create(@Body() createDrinkDto: CreateDrinkDto): Promise<Drink> {
return this.drinksService.create(createDrinkDto);
}

@Get()
findAll(): Promise<Drink[]> {
return this.drinksService.findAll();
}

@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string): Promise<Drink> {
return this.drinksService.findOne(id);
}

@Patch(':id')
update(@Param('id', ParseUUIDPipe) id: string, @Body() updateDrinkDto: UpdateDrinkDto): Promise<Drink> {
return this.drinksService.update(id, updateDrinkDto);
}

@Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string): Promise<Drink> {
return this.drinksService.remove(id);
}
}
10 changes: 10 additions & 0 deletions apps/backend/src/drinks/drinks.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';

import { DrinksController } from './drinks.controller';
import { DrinksService } from './drinks.service';

@Module({
controllers: [DrinksController],
providers: [DrinksService],
})
export class DrinksModule {}
43 changes: 43 additions & 0 deletions apps/backend/src/drinks/drinks.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from 'nestjs-prisma';

import { CreateDrinkDto } from './dto/create-drink.dto';
import { UpdateDrinkDto } from './dto/update-drink.dto';
import { Drink } from './entities/drink.entity';

@Injectable()
export class DrinksService {
constructor(private prisma: PrismaService) {}

create(createDrinkDto: CreateDrinkDto): Promise<Drink> {
return this.prisma.drink.create({ data: createDrinkDto });
}

findAll(): Promise<Drink[]> {
return this.prisma.drink.findMany();
}

async findOne(id: string): Promise<Drink> {
const drink = await this.prisma.drink.findUnique({ where: { id } });
if (!drink) {
throw new NotFoundException('Drink not found');
}
return drink;
}

async update(id: string, updateDrinkDto: UpdateDrinkDto): Promise<Drink> {
try {
return this.prisma.drink.update({ where: { id }, data: updateDrinkDto });
} catch {
throw new NotFoundException('Drink not found');
}
}

async remove(id: string): Promise<Drink> {
try {
return this.prisma.drink.delete({ where: { id } });
} catch {
throw new NotFoundException('Drink not found');
}
}
}
5 changes: 5 additions & 0 deletions apps/backend/src/drinks/dto/create-drink.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { OmitType } from '@nestjs/swagger';

import { Drink } from '../entities/drink.entity';

export class CreateDrinkDto extends OmitType(Drink, ['id', 'createdAt']) {}
5 changes: 5 additions & 0 deletions apps/backend/src/drinks/dto/update-drink.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PartialType } from '@nestjs/swagger';

import { CreateDrinkDto } from './create-drink.dto';

export class UpdateDrinkDto extends PartialType(CreateDrinkDto) {}
50 changes: 50 additions & 0 deletions apps/backend/src/drinks/entities/drink.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { DrinkType } from '@prisma/client';
import { IsBoolean, IsDateString, IsEnum, IsNotEmpty, IsOptional, IsString, IsUUID, Min } from 'class-validator';
import { IsFloat } from 'src/util/is-float.validator';

export class Drink {
/**
* @example aaaaaaaa-bbbb-cccc-dddd-eeee-ff0123456789
*/
@IsUUID()
id: string;

/**
* Name of the drink
* @example 'Soproni meggy'
*/
@IsString()
@IsNotEmpty()
name: string;

/**
* Type of the drink
* @example BEER
*/
@IsEnum(DrinkType)
type: DrinkType;

/**
* Alcohol content of the drink
* @example 4.5
*/
@IsFloat()
@Min(0)
alcoholContent: number;

/**
* Whether it was created by a user
*/
@IsBoolean()
custom: boolean;

/**
* @example "A beer that doesn't really taste like beer."
*/
@IsString()
@IsOptional()
description?: string;

@IsDateString()
createdAt: Date;
}
2 changes: 1 addition & 1 deletion apps/backend/src/events/entities/event.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IsDate, IsDateString, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';

import { IsAfterDate } from '../validators/is-after-date.validator';
import { IsAfterDate } from '../../util/is-after-date.validator';

export class Event {
@IsUUID()
Expand Down
20 changes: 20 additions & 0 deletions apps/backend/src/util/is-float.validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';

export function IsFloat(validationOptions?: ValidationOptions) {
return function (object: object, propertyName: string) {
registerDecorator({
name: 'isFloat',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(value: any) {
return typeof value === 'number' && !isNaN(value);
},
defaultMessage(args: ValidationArguments) {
return `${args.property} must be a float number`;
},
},
});
};
}

0 comments on commit d6a5be0

Please sign in to comment.