Skip to content

Commit

Permalink
Merge pull request #12 from wang-bam-bbang/building
Browse files Browse the repository at this point in the history
feat: add building module and apply to post module
  • Loading branch information
Kimcheolhui authored Dec 9, 2024
2 parents c567dfb + 539afb0 commit 5115459
Show file tree
Hide file tree
Showing 20 changed files with 589 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Warnings:
- You are about to drop the column `location` on the `post` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "post" DROP COLUMN "location";

-- CreateTable
CREATE TABLE "building" (
"id" SERIAL NOT NULL,
"name" VARCHAR(255) NOT NULL,
"enName" VARCHAR(255) NOT NULL,
"gps" VARCHAR(255) NOT NULL,
"code" VARCHAR(50) NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "building_pkey" PRIMARY KEY ("id")
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:
- A unique constraint covering the columns `[name]` on the table `building` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "building_name_key" ON "building"("name");
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Warnings:
- You are about to alter the column `name` on the `building` table. The data in that column could be lost. The data in that column will be cast from `VarChar(255)` to `VarChar(20)`.
- You are about to alter the column `enName` on the `building` table. The data in that column could be lost. The data in that column will be cast from `VarChar(255)` to `VarChar(20)`.
- You are about to alter the column `gps` on the `building` table. The data in that column could be lost. The data in that column will be cast from `VarChar(255)` to `VarChar(30)`.
- You are about to alter the column `code` on the `building` table. The data in that column could be lost. The data in that column will be cast from `VarChar(50)` to `VarChar(4)`.
*/
-- AlterTable
ALTER TABLE "building" ALTER COLUMN "name" SET DATA TYPE VARCHAR(20),
ALTER COLUMN "enName" SET DATA TYPE VARCHAR(20),
ALTER COLUMN "gps" SET DATA TYPE VARCHAR(30),
ALTER COLUMN "code" SET DATA TYPE VARCHAR(4);

-- AlterTable
ALTER TABLE "post" ADD COLUMN "buildingId" INTEGER NOT NULL DEFAULT 2,
ADD COLUMN "locationDetail" TEXT;

-- AddForeignKey
ALTER TABLE "post" ADD CONSTRAINT "post_buildingId_fkey" FOREIGN KEY ("buildingId") REFERENCES "building"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
38 changes: 28 additions & 10 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,43 @@ enum PostType {
}

model Post {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
type PostType
title String @db.VarChar(255)
description String @db.Text
title String @db.VarChar(255)
description String @db.Text
images String[]
location String
category ItemCategory @default(ETC)
status PostStatus
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
category ItemCategory @default(ETC)
status PostStatus
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
authorId String @db.Uuid
author User @relation(fields: [authorId], references: [uuid])
Comment Comment[]
comment Comment[]
buildingId Int @default(2)
building Building @relation(fields: [buildingId], references: [id])
locationDetail String? // 세부 위치
@@map("post")
}

model Building {
id Int @id @default(autoincrement())
name String @unique() @db.VarChar(20)
enName String @db.VarChar(20)
gps String @db.VarChar(30)
code String @db.VarChar(4) // 건물 번호 e.g. E11
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("building")
}

enum CommentType {
COMMENT // 일반 댓글
REPLY // 대댓글
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { UserModule } from './user/user.module';
import { PostModule } from './post/post.module';
import { ImageModule } from './image/image.module';
import { CommentModule } from './comment/comment.module';
import { BuildingModule } from './building/building.module';

@Module({
imports: [
Expand All @@ -15,6 +16,7 @@ import { CommentModule } from './comment/comment.module';
PostModule,
ImageModule,
CommentModule,
BuildingModule,
],
controllers: [AppController],
providers: [],
Expand Down
90 changes: 90 additions & 0 deletions src/building/building.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Patch,
Post,
} from '@nestjs/common';
import {
ApiInternalServerErrorResponse,
ApiNoContentResponse,
ApiOkResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { BuildingService } from './building.service';
import { CreateBuildingDto } from './dto/req/createBuilding.dto';
import { BuildingResponseDto } from './dto/res/buildingRes.dto';
import { UpdateBuildingDto } from './dto/req/updateBuilding.dto';

@ApiTags('Building')
@Controller('building')
export class BuildingController {
constructor(private buildingService: BuildingService) {}

@ApiOperation({
summary: 'create building',
description: 'register building information',
})
@ApiOkResponse({
type: BuildingResponseDto,
description: 'Return Created Building',
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
})
@Post()
async createBuilding(
@Body() createBuildingDto: CreateBuildingDto,
): Promise<BuildingResponseDto> {
return this.buildingService.createBuilding(createBuildingDto);
}

@ApiOperation({
summary: 'get all buildings',
description: 'get all buildings information',
})
@ApiOkResponse({
type: [BuildingResponseDto],
description: 'Return All Buildings',
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
})
@Get()
async getAllBuildings(): Promise<BuildingResponseDto[]> {
return this.buildingService.getAllBuildings();
}

@ApiOperation({
summary: 'update building',
description: 'update building',
})
@ApiOkResponse({
type: BuildingResponseDto,
description: 'Return updated building',
})
@Patch(':id')
async updateBuilding(
@Param('id', ParseIntPipe) id: number,
@Body() updateBuildingDto: UpdateBuildingDto,
): Promise<BuildingResponseDto> {
return this.buildingService.updateBuilding(id, updateBuildingDto);
}

@ApiOperation({
summary: 'delete building',
description: 'delete building',
})
@ApiNoContentResponse({ description: 'No content returned' })
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
})
@Delete(':id')
async deleteBuilding(@Param('id', ParseIntPipe) id: number): Promise<void> {
return this.buildingService.deleteBuilding(id);
}
}
13 changes: 13 additions & 0 deletions src/building/building.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { BuildingController } from './building.controller';
import { PrismaModule } from 'src/prisma/prisma.module';
import { BuildingService } from './building.service';
import { BuildingRepository } from './building.repository';

@Module({
imports: [PrismaModule],
providers: [BuildingService, BuildingRepository],
controllers: [BuildingController],
exports: [BuildingService],
})
export class BuildingModule {}
56 changes: 56 additions & 0 deletions src/building/building.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateBuildingDto } from './dto/req/createBuilding.dto';
import { UpdateBuildingDto } from './dto/req/updateBuilding.dto';
import { BuildingResponseDto } from './dto/res/buildingRes.dto';

@Injectable()
export class BuildingRepository {
constructor(private prismaService: PrismaService) {}

async createBuilding(
createBuildingDto: CreateBuildingDto,
): Promise<BuildingResponseDto> {
return this.prismaService.building.create({
data: {
...createBuildingDto,
},
});
}

async getAllBuildings(): Promise<BuildingResponseDto[]> {
return this.prismaService.building.findMany({
where: {},
});
}

async getBuildingByName(name: string): Promise<BuildingResponseDto> {
return this.prismaService.building.findUnique({
where: { name },
});
}

async getBuildingById(id: number): Promise<BuildingResponseDto> {
return this.prismaService.building.findUnique({
where: { id },
});
}

async updateBuilding(
id: number,
updateBuildingDto: UpdateBuildingDto,
): Promise<BuildingResponseDto> {
const updatedBuilding = await this.prismaService.building.update({
where: { id },
data: updateBuildingDto,
});

return updatedBuilding;
}

async deleteBuilding(id: number): Promise<void> {
await this.prismaService.building.delete({
where: { id },
});
}
}
57 changes: 57 additions & 0 deletions src/building/building.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
ConflictException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { CreateBuildingDto } from './dto/req/createBuilding.dto';
import { BuildingRepository } from './building.repository';
import { UpdateBuildingDto } from './dto/req/updateBuilding.dto';
import { BuildingResponseDto } from './dto/res/buildingRes.dto';

@Injectable()
export class BuildingService {
constructor(private buildingRepository: BuildingRepository) {}

async createBuilding(
createBuildingDto: CreateBuildingDto,
): Promise<BuildingResponseDto> {
const building = await this.buildingRepository.getBuildingByName(
createBuildingDto.name,
);

if (building) {
throw new ConflictException('Building name already exists.');
}

return this.buildingRepository.createBuilding(createBuildingDto);
}

async getAllBuildings(): Promise<BuildingResponseDto[]> {
return this.buildingRepository.getAllBuildings();
}

async updateBuilding(
id: number,
updateBuildingDto: UpdateBuildingDto,
): Promise<BuildingResponseDto> {
const building = await this.buildingRepository.getBuildingById(id);
if (!building) {
throw new NotFoundException('Building not found.');
}

return this.buildingRepository.updateBuilding(id, updateBuildingDto);
}

async deleteBuilding(id: number): Promise<void> {
const building = await this.buildingRepository.getBuildingById(id);
if (!building) {
throw new NotFoundException('Building not found.');
}

return this.buildingRepository.deleteBuilding(id);
}

async getBuildingById(id: number): Promise<BuildingResponseDto> {
return this.buildingRepository.getBuildingById(id);
}
}
43 changes: 43 additions & 0 deletions src/building/dto/req/createBuilding.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString, Matches } from 'class-validator';

export class CreateBuildingDto {
@ApiProperty({
type: String,
description: 'Building Name',
example: '대학 A동',
})
@IsString()
@IsNotEmpty()
name: string;

@ApiProperty({
type: String,
description: 'Building Name in english',
example: 'College A',
})
@IsString()
@IsNotEmpty()
enName: string;

@ApiProperty({
type: String,
description: 'GPS info (lat, lon)',
example: '(35.229695, 126.844536)',
})
@IsString()
@IsNotEmpty()
@Matches(/^\((-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)\)$/, {
message: 'GPS must be in format (latitude, longitude)',
})
gps: string;

@ApiProperty({
type: String,
description: 'Building Code',
example: 'N4',
})
@IsString()
@IsNotEmpty()
code: string;
}
Loading

0 comments on commit 5115459

Please sign in to comment.