feat: add Prisma ORM to backend with spaces migration and PrismaService
This commit is contained in:
parent
71a4c63926
commit
08eddc1d9a
@ -6,7 +6,9 @@
|
|||||||
"build": "nest build",
|
"build": "nest build",
|
||||||
"start": "nest start",
|
"start": "nest start",
|
||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:prod": "node dist/main"
|
"start:prod": "node dist/main",
|
||||||
|
"db:migrate": "prisma migrate deploy",
|
||||||
|
"db:generate": "prisma generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
@ -14,6 +16,7 @@
|
|||||||
"@nestjs/jwt": "^10.0.0",
|
"@nestjs/jwt": "^10.0.0",
|
||||||
"@nestjs/passport": "^10.0.0",
|
"@nestjs/passport": "^10.0.0",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
|
"@prisma/client": "^5.0.0",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
@ -24,6 +27,7 @@
|
|||||||
"@nestjs/schematics": "^10.0.0",
|
"@nestjs/schematics": "^10.0.0",
|
||||||
"@types/node": "^20.0.0",
|
"@types/node": "^20.0.0",
|
||||||
"@types/passport-jwt": "^4.0.0",
|
"@types/passport-jwt": "^4.0.0",
|
||||||
|
"prisma": "^5.0.0",
|
||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
backend/prisma/migrations/20260615000000_init/migration.sql
Normal file
17
backend/prisma/migrations/20260615000000_init/migration.sql
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "reservas" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"resourceId" TEXT NOT NULL,
|
||||||
|
"resourceName" TEXT NOT NULL,
|
||||||
|
"date" TEXT NOT NULL,
|
||||||
|
"startTime" TEXT NOT NULL,
|
||||||
|
"endTime" TEXT NOT NULL,
|
||||||
|
"author" TEXT NOT NULL,
|
||||||
|
"notes" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "reservas_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "reservas_resourceName_date_startTime_key" ON "reservas"("resourceName", "date", "startTime");
|
||||||
3
backend/prisma/migrations/migration_lock.toml
Normal file
3
backend/prisma/migrations/migration_lock.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "postgresql"
|
||||||
23
backend/prisma/schema.prisma
Normal file
23
backend/prisma/schema.prisma
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Reserva {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
resourceId String
|
||||||
|
resourceName String
|
||||||
|
date String // "YYYY-MM-DD"
|
||||||
|
startTime String // "HH:mm"
|
||||||
|
endTime String // "HH:mm"
|
||||||
|
author String
|
||||||
|
notes String?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@unique([resourceName, date, startTime])
|
||||||
|
@@map("reservas")
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
import { AuthModule } from './auth/auth.module';
|
import { AuthModule } from './auth/auth.module';
|
||||||
import { CmsModule } from './cms/cms.module';
|
import { CmsModule } from './cms/cms.module';
|
||||||
import { DirectoryModule } from './directory/directory.module';
|
import { DirectoryModule } from './directory/directory.module';
|
||||||
@ -8,6 +9,7 @@ import { TicketingModule } from './ticketing/ticketing.module';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
PrismaModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
CmsModule,
|
CmsModule,
|
||||||
DirectoryModule,
|
DirectoryModule,
|
||||||
@ -17,3 +19,4 @@ import { TicketingModule } from './ticketing/ticketing.module';
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
||||||
|
|||||||
9
backend/src/prisma/prisma.module.ts
Normal file
9
backend/src/prisma/prisma.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { PrismaService } from './prisma.service';
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
providers: [PrismaService],
|
||||||
|
exports: [PrismaService],
|
||||||
|
})
|
||||||
|
export class PrismaModule {}
|
||||||
16
backend/src/prisma/prisma.service.ts
Normal file
16
backend/src/prisma/prisma.service.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PrismaService
|
||||||
|
extends PrismaClient
|
||||||
|
implements OnModuleInit, OnModuleDestroy
|
||||||
|
{
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.$connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
async onModuleDestroy() {
|
||||||
|
await this.$disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ export class SpacesController {
|
|||||||
* Devuelve todas las reservas (opcionalmente filtradas por fecha)
|
* Devuelve todas las reservas (opcionalmente filtradas por fecha)
|
||||||
*/
|
*/
|
||||||
@Get()
|
@Get()
|
||||||
findAll(@Query('date') date?: string) {
|
async findAll(@Query('date') date?: string) {
|
||||||
return this.spacesService.findAll(date);
|
return this.spacesService.findAll(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export class SpacesController {
|
|||||||
* Crea una nueva reserva
|
* Crea una nueva reserva
|
||||||
*/
|
*/
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() dto: CreateReservaDto) {
|
async create(@Body() dto: CreateReservaDto) {
|
||||||
return this.spacesService.create(dto);
|
return this.spacesService.create(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ export class SpacesController {
|
|||||||
* Elimina una reserva por ID
|
* Elimina una reserva por ID
|
||||||
*/
|
*/
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
delete(@Param('id') id: string) {
|
async delete(@Param('id') id: string) {
|
||||||
this.spacesService.delete(id);
|
await this.spacesService.delete(id);
|
||||||
return { message: 'Reserva eliminada correctamente.' };
|
return { message: 'Reserva eliminada correctamente.' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { SpacesController } from './spaces.controller';
|
||||||
|
import { SpacesService } from './spaces.service';
|
||||||
|
|
||||||
@Module({})
|
@Module({
|
||||||
|
controllers: [SpacesController],
|
||||||
|
providers: [SpacesService],
|
||||||
|
})
|
||||||
export class SpacesModule {}
|
export class SpacesModule {}
|
||||||
|
|||||||
@ -1,26 +1,28 @@
|
|||||||
import { Injectable, ConflictException } from '@nestjs/common';
|
import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
|
||||||
import { CreateReservaDto, Reserva } from './reserva.dto';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { CreateReservaDto } from './reserva.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpacesService {
|
export class SpacesService {
|
||||||
private reservas: Reserva[] = [];
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
private idCounter = 1;
|
|
||||||
|
|
||||||
findAll(date?: string): Reserva[] {
|
async findAll(date?: string) {
|
||||||
if (date) {
|
return this.prisma.reserva.findMany({
|
||||||
return this.reservas.filter((r) => r.date === date);
|
where: date ? { date } : undefined,
|
||||||
}
|
orderBy: { createdAt: 'desc' },
|
||||||
return this.reservas;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
create(dto: CreateReservaDto): Reserva {
|
async create(dto: CreateReservaDto) {
|
||||||
// Verificar conflicto: mismo recurso, mismo día, mismo horario de inicio
|
const conflict = await this.prisma.reserva.findUnique({
|
||||||
const conflict = this.reservas.find(
|
where: {
|
||||||
(r) =>
|
resourceName_date_startTime: {
|
||||||
r.resourceName === dto.resourceName &&
|
resourceName: dto.resourceName,
|
||||||
r.date === dto.date &&
|
date: dto.date,
|
||||||
r.startTime === dto.startTime,
|
startTime: dto.startTime,
|
||||||
);
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
throw new ConflictException(
|
throw new ConflictException(
|
||||||
@ -28,17 +30,16 @@ export class SpacesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newReserva: Reserva = {
|
return this.prisma.reserva.create({ data: dto });
|
||||||
...dto,
|
|
||||||
id: String(this.idCounter++),
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.reservas.unshift(newReserva);
|
|
||||||
return newReserva;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(id: string): void {
|
async delete(id: string): Promise<void> {
|
||||||
this.reservas = this.reservas.filter((r) => r.id !== id);
|
const reserva = await this.prisma.reserva.findUnique({ where: { id } });
|
||||||
|
|
||||||
|
if (!reserva) {
|
||||||
|
throw new NotFoundException(`Reserva con id "${id}" no encontrada.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.prisma.reserva.delete({ where: { id } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user