diff --git a/apps/auth/prisma/schema.prisma b/apps/auth/prisma/schema.prisma new file mode 100644 index 0000000..2baa5df --- /dev/null +++ b/apps/auth/prisma/schema.prisma @@ -0,0 +1,27 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model User { + uuid String @id @default(uuid()) @db.Uuid + isBlocked Boolean @default(false) + + devices UserDevice[] @relation("userDevice") +} + +model UserDevice { + fingerprint Bytes @id @db.ByteA + name String @db.VarChar(100) + userUuid String @db.Uuid + isBlocked Boolean @default(false) + + user User @relation("userDevice", fields: [userUuid], references: [uuid]) +} diff --git a/apps/auth/src/prisma/error/record-not-found.error.ts b/apps/auth/src/prisma/error/record-not-found.error.ts new file mode 100644 index 0000000..e1c9cb1 --- /dev/null +++ b/apps/auth/src/prisma/error/record-not-found.error.ts @@ -0,0 +1 @@ +export class RecordNotFoundError extends Error {} diff --git a/apps/auth/src/prisma/interceptor/prisma-error.interceptor.ts b/apps/auth/src/prisma/interceptor/prisma-error.interceptor.ts new file mode 100644 index 0000000..7ad4b9a --- /dev/null +++ b/apps/auth/src/prisma/interceptor/prisma-error.interceptor.ts @@ -0,0 +1,26 @@ +import { + CallHandler, + ConflictException, + ExecutionContext, + Injectable, + NestInterceptor, + NotFoundException +} from "@nestjs/common"; +import { catchError, Observable } from "rxjs"; +import { RecordNotFoundError } from "../error/record-not-found.error"; +import { UniqueConstraintFailedError } from "../error/unique-constraint-failed.error"; + +@Injectable() +export class PrismaErrorInterceptor implements NestInterceptor { + intercept(context: ExecutionContext, next: CallHandler): Observable { + return next + .handle() + .pipe( + catchError(err => { + if (err instanceof RecordNotFoundError) throw new NotFoundException(err.message); + if (err instanceof UniqueConstraintFailedError) throw new ConflictException(err.message); + throw err; + }) + ); + } +} diff --git a/apps/auth/src/prisma/prisma.module.ts b/apps/auth/src/prisma/prisma.module.ts new file mode 100644 index 0000000..44400fd --- /dev/null +++ b/apps/auth/src/prisma/prisma.module.ts @@ -0,0 +1,10 @@ +import { Global, Module } from "@nestjs/common"; +import { PrismaService } from "./service/prisma.service"; + +@Global() +@Module({ + providers: [PrismaService], + exports: [PrismaService] +}) +export class PrismaModule { +} diff --git a/apps/auth/src/prisma/service/prisma.service.spec.ts b/apps/auth/src/prisma/service/prisma.service.spec.ts new file mode 100644 index 0000000..a68cb9e --- /dev/null +++ b/apps/auth/src/prisma/service/prisma.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PrismaService } from './prisma.service'; + +describe('PrismaService', () => { + let service: PrismaService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [PrismaService], + }).compile(); + + service = module.get(PrismaService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/apps/auth/src/prisma/service/prisma.service.ts b/apps/auth/src/prisma/service/prisma.service.ts new file mode 100644 index 0000000..aaa764a --- /dev/null +++ b/apps/auth/src/prisma/service/prisma.service.ts @@ -0,0 +1,15 @@ +import { INestApplication, Injectable, OnModuleInit } from "@nestjs/common"; +import { PrismaClient } from "@prisma/client"; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit { + async onModuleInit() { + await this.$connect(); + } + + async enableShutdownHooks(app: INestApplication) { + this.$on("beforeExit", async () => { + await app.close(); + }); + } +}