From 6edb3b7268e19def22eea718ac11caec78085649 Mon Sep 17 00:00:00 2001 From: raulgonzalez Date: Tue, 30 Apr 2024 17:01:06 +0200 Subject: [PATCH] Add user repor,error middleware and db connect --- .eslintrc.cjs | 20 +-- jest.config.js | 18 ++- package-lock.json | 3 +- package.json | 3 +- .../20240430112638_init/migration.sql | 34 +++++ .../20240430123011_init/migration.sql | 12 ++ .../20240430124831_init/migration.sql | 17 +++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 46 +++++++ sonar-project.properties | 2 +- src/app.ts | 19 +++ src/entities/character.schema.ts | 17 +++ src/entities/character.ts | 18 +++ src/entities/user.schema.ts | 13 ++ src/entities/user.ts | 16 +++ src/index.ts | 30 +++++ src/middleware/errors.middleware.test.ts | 45 +++++++ src/middleware/errors.middleware.ts | 48 +++++++ src/repositories/type.repo.ts | 11 ++ src/repositories/user.sql.repo.test.ts | 117 ++++++++++++++++++ src/repositories/users.sql.repo.ts | 108 ++++++++++++++++ src/tools/db.connect.ts | 9 ++ 22 files changed, 587 insertions(+), 22 deletions(-) create mode 100644 prisma/migrations/20240430112638_init/migration.sql create mode 100644 prisma/migrations/20240430123011_init/migration.sql create mode 100644 prisma/migrations/20240430124831_init/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 src/app.ts create mode 100644 src/entities/character.schema.ts create mode 100644 src/entities/character.ts create mode 100644 src/entities/user.schema.ts create mode 100644 src/entities/user.ts create mode 100644 src/middleware/errors.middleware.test.ts create mode 100644 src/middleware/errors.middleware.ts create mode 100644 src/repositories/type.repo.ts create mode 100644 src/repositories/user.sql.repo.test.ts create mode 100644 src/repositories/users.sql.repo.ts create mode 100644 src/tools/db.connect.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ed6b9d4..09081d1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,28 +3,20 @@ module.exports = { browser: true, es2021: true, node: true, + jest: true, }, - extends: 'xo', + extends: ['xo', 'prettier'], overrides: [ { - env: { - node: true, - }, - files: ['.eslintrc.{js,cjs}'], - parserOptions: { - sourceType: 'script', - }, - }, - { - extends: ['xo-typescript'], + extends: ['xo-typescript', 'prettier'], files: ['*.ts', '*.tsx'], }, ], parserOptions: { ecmaVersion: 'latest', sourceType: 'module', + tsconfigRootDir: __dirname, + project: '/tsconfig.json', }, - rules: { - indent: 'off', - }, + rules: {}, }; diff --git a/jest.config.js b/jest.config.js index 426be17..d477cea 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,17 @@ -const config = { - clearMocks: true, +export default { collectCoverage: true, - + collectCoverageFrom: ['src/*/*.ts'], coverageDirectory: 'coverage', - + coveragePathIgnorePatterns: [ + 'index.ts', + 'type.repo.ts', + 'entities', + 'interface', + 'tools', + '_mock', + ], coverageProvider: 'v8', + preset: 'ts-jest', + testPathIgnorePatterns: ['dist'], + resolver: 'jest-ts-webcompat-resolver', }; -export default config; diff --git a/package-lock.json b/package-lock.json index 3e2f304..c231994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,9 +21,10 @@ "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", "nodemon": "^3.1.0", - "prisma": "^5.12.1" + "prisma": "^5.13.0" }, "devDependencies": { + "@jest/reporters": "29.7.0", "@types/bcrypt": "^5.0.2", "@types/cors": "^2.8.17", "@types/debug": "^4.1.12", diff --git a/package.json b/package.json index 0cb629d..601c391 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@types/express": "^4.17.21", "@types/jest": "^29.5.12", "@types/jsonwebtoken": "^9.0.6", + "@jest/reporters": "29.7.0", "@types/morgan": "^1.9.9", "@types/node": "^20.12.7", "@typescript-eslint/eslint-plugin": "^7.7.1", @@ -55,6 +56,6 @@ "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", "nodemon": "^3.1.0", - "prisma": "^5.12.1" + "prisma": "^5.13.0" } } diff --git a/prisma/migrations/20240430112638_init/migration.sql b/prisma/migrations/20240430112638_init/migration.sql new file mode 100644 index 0000000..ce4bf6f --- /dev/null +++ b/prisma/migrations/20240430112638_init/migration.sql @@ -0,0 +1,34 @@ +-- CreateEnum +CREATE TYPE "Race" AS ENUM ('men', 'elve', 'dwarf', 'urukhai', 'orc', 'hobbit'); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Character" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT NOT NULL, + "imgUrl" TEXT NOT NULL, + "faction" TEXT NOT NULL, + "race" "Race" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Character_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- AddForeignKey +ALTER TABLE "Character" ADD CONSTRAINT "Character_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20240430123011_init/migration.sql b/prisma/migrations/20240430123011_init/migration.sql new file mode 100644 index 0000000..b724b2d --- /dev/null +++ b/prisma/migrations/20240430123011_init/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - A unique constraint covering the columns `[userNamo]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `userNamo` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "userNamo" TEXT NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "User_userNamo_key" ON "User"("userNamo"); diff --git a/prisma/migrations/20240430124831_init/migration.sql b/prisma/migrations/20240430124831_init/migration.sql new file mode 100644 index 0000000..c2f6831 --- /dev/null +++ b/prisma/migrations/20240430124831_init/migration.sql @@ -0,0 +1,17 @@ +/* + Warnings: + + - You are about to drop the column `userNamo` on the `User` table. All the data in the column will be lost. + - A unique constraint covering the columns `[userName]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `userName` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropIndex +DROP INDEX "User_userNamo_key"; + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "userNamo", +ADD COLUMN "userName" TEXT NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "User_userName_key" ON "User"("userName"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -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" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..485fd99 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,46 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} +model User { + id String @id @default(cuid()) + email String @unique + userName String @unique + password String + character Character[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} +model Character{ +id String @id @default(cuid()) +user User @relation(fields:[userId], references:[id]) +userId String +name String +description String +imgUrl String +faction String +race Race +createdAt DateTime @default(now()) +updatedAt DateTime @updatedAt +} + + +enum Race { +men +elve +dwarf +urukhai +orc +hobbit +} + diff --git a/sonar-project.properties b/sonar-project.properties index 1b74c5e..7f433ca 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -14,4 +14,4 @@ sonar.organization=isdi-coders-2023 sonar.sources=./src sonar.test.inclusions=./src///.test., ./src///.spec. sonar.javascript.lcov.reportPaths=coverage/lcov.info -sonar.coverage.exclusions= src/index.ts, src/app.ts, src//.test., src//routing., src/main.ts, src//.spec., src/model/, +sonar.coverage.exclusions= src/index.ts, src/app.ts, src//.test., src//routing., src/main.ts, src//.spec., src/model/,**/type.*, diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..bd24e87 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,19 @@ +import express, { type Express } from 'express'; +import morgan from 'morgan'; +import cors from 'cors'; +import createDebug from 'debug'; +import { type PrismaClient } from '@prisma/client'; + +const debug = createDebug('GONJI:app'); +export const createApp = () => { + debug('Creating app'); + return express(); +}; + +export const startApp = (app: Express, prisma: PrismaClient) => { + debug('Starting app'); + app.use(express.json()); + app.use(morgan('dev')); + app.use(cors()); + app.use(express.static('public')); +}; diff --git a/src/entities/character.schema.ts b/src/entities/character.schema.ts new file mode 100644 index 0000000..aeccb65 --- /dev/null +++ b/src/entities/character.schema.ts @@ -0,0 +1,17 @@ +import joy from 'joi'; +import { type CharacterCreateDto } from './character'; + +export const characterCreateSchema = joy.object({ + name: joy.string().required(), + imgUrl: joy.string().uri().required(), + description: joy.string().required(), + faction: joy.string().required(), + userId: joy.string().required(), +}); +export const characterUpdateSchema = joy.object>({ + name: joy.string(), + imgUrl: joy.string().uri(), + description: joy.string(), + faction: joy.string(), + userId: joy.string(), +}); diff --git a/src/entities/character.ts b/src/entities/character.ts new file mode 100644 index 0000000..678ec14 --- /dev/null +++ b/src/entities/character.ts @@ -0,0 +1,18 @@ +export type Character = { + id: string; + name: string; + imgUrl: string; + description: string; + faction: string; + race: 'Men' | 'Elf' | 'Elve' | 'Dwarf' | 'Uruk-hai' | 'Orc' | 'Hobbit'; + userId: string; +}; +export type CharacterCreateDto = { + name: string; + imgUrl: string; + description: string; + faction: string; + race: 'Men' | 'Elf' | 'Elve' | 'Dwarf' | 'Uruk-hai' | 'Orc' | 'Hobbit'; + userId: string; +}; +export type CharacterUpdateDto = Partial; diff --git a/src/entities/user.schema.ts b/src/entities/user.schema.ts new file mode 100644 index 0000000..df7be34 --- /dev/null +++ b/src/entities/user.schema.ts @@ -0,0 +1,13 @@ +import joy from 'joi'; +import { type UserCreateDto } from './user'; + +export const userCreateSchema = joy.object({ + email: joy.string().email().required(), + password: joy.string().min(5).required(), + userName: joy.string().min(3).required(), +}); +export const userUpdateSchema = joy.object>({ + email: joy.string().email(), + password: joy.string().min(5), + userName: joy.string().min(3), +}); diff --git a/src/entities/user.ts b/src/entities/user.ts new file mode 100644 index 0000000..389d334 --- /dev/null +++ b/src/entities/user.ts @@ -0,0 +1,16 @@ +import { type Character } from './character'; + +export type User = { + id: string; + email: string; + password: string; + userName: string; + characters: Character[]; +}; + +export type UserCreateDto = { + email: string; + password: string; + userName: string; +}; +export type UserUpdateDto = Partial; diff --git a/src/index.ts b/src/index.ts index 8b13789..46f779c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,31 @@ +import { createServer } from 'http'; +import createDebug from 'debug'; +import 'dotenv/config'; +import { createApp, startApp } from './app.js'; +import { dbConnect } from './tools/db.connect.js'; +const debug = createDebug('GONJI:server'); +debug('Starting server'); + +const port = process.env.PORT ?? 3000; + +const app = createApp(); +const server = createServer(app); + +dbConnect() + .then((prisma) => { + startApp(app, prisma); + server.listen(port); + }) + .catch((error) => { + server.emit('error', error); + }); + +server.on('error', (error) => { + debug('Error:', error); + process.exit(1); +}); + +server.on('listening', () => { + console.log(`Server Express is running http://localhost:${port}`); +}); diff --git a/src/middleware/errors.middleware.test.ts b/src/middleware/errors.middleware.test.ts new file mode 100644 index 0000000..769a6ad --- /dev/null +++ b/src/middleware/errors.middleware.test.ts @@ -0,0 +1,45 @@ +import { type Request, type Response } from 'express'; +import { ErrorsMiddleware, HttpError } from './errors.middleware'; +import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; + +const req = {} as unknown as Request; +const res = { + json: jest.fn(), + status: jest.fn(), +} as unknown as Response; +const next = jest.fn(); + +describe('Given a instance of the class ErrorsMiddleware', () => { + const middleware = new ErrorsMiddleware(); + test('Then it should be instance of the class', () => { + expect(middleware).toBeInstanceOf(ErrorsMiddleware); + }); + describe('When we use the method handle with a HttpError', () => { + test('Then it should call res.status 404', () => { + const error = new HttpError(404, 'Not Found', 'Article not found'); + middleware.handle(error, req, res, next); + expect(res.status).toHaveBeenCalledWith(404); + expect(res.json).toHaveBeenCalled(); + }); + }); + describe('When we use the method handle with a PrismaClientKnownRequestError', () => { + test('Then it should call res.status 404', () => { + const error = new PrismaClientKnownRequestError('error', { + code: 'P2025', + clientVersion: '3.0.0', + }); + middleware.handle(error, req, res, next); + expect(res.status).toHaveBeenCalledWith(403); + expect(res.json).toHaveBeenCalled(); + }); + }); + + describe('When we use the method handle with a Error', () => { + test('Then it should call res.status with 500', () => { + const error = new Error('Something went wrong'); + middleware.handle(error, req, res, next); + expect(res.status).toHaveBeenCalledWith(500); + expect(res.json).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/middleware/errors.middleware.ts b/src/middleware/errors.middleware.ts new file mode 100644 index 0000000..e55dab1 --- /dev/null +++ b/src/middleware/errors.middleware.ts @@ -0,0 +1,48 @@ +import { type NextFunction, type Request, type Response } from 'express'; +import createDebug from 'debug'; +import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; +const debug = createDebug('W7E:errors:middleware'); + +export class HttpError extends Error { + constructor( + public status: number, + public statusMessage: string, + message?: string, + options?: ErrorOptions + ) { + super(message, options); + } +} +export class ErrorsMiddleware { + constructor() { + debug('Instantiated errors middleware'); + } + + handle(error: Error, _req: Request, res: Response, _next: NextFunction) { + let status = 500; + let json = { + status: '500 Internal Server Error', + message: error.message, + }; + + if (error instanceof HttpError) { + debug('Error', error.message); + status = error.status; + json = { + status: `${error.status} ${error.statusMessage}`, + message: error.message, + }; + } else if (error instanceof PrismaClientKnownRequestError) { + debug('Prisma error', error.message); + status = 403; + json = { + status: '403 Forbidden', + message: error.message, + }; + } + + debug('Request received', error.message); + res.status(status); + res.json(json); + } +} diff --git a/src/repositories/type.repo.ts b/src/repositories/type.repo.ts new file mode 100644 index 0000000..5db3972 --- /dev/null +++ b/src/repositories/type.repo.ts @@ -0,0 +1,11 @@ +export type Repo = { + readAll(): Promise; + readById(id: string): Promise; + create(data: C): Promise; + update(id: string, data: Partial): Promise; + delete(id: string): Promise; +}; + +export type WithLoginRepo = Repo & { + searchForLogin(key: 'email' | 'name', value: string): Promise>; +}; diff --git a/src/repositories/user.sql.repo.test.ts b/src/repositories/user.sql.repo.test.ts new file mode 100644 index 0000000..c5d3357 --- /dev/null +++ b/src/repositories/user.sql.repo.test.ts @@ -0,0 +1,117 @@ +import { type PrismaClient } from '@prisma/client'; +import { UsersSqlRepo } from './users.sql.repo'; +import { HttpError } from '../middleware/errors.middleware'; +import { type UserCreateDto } from '../entities/user'; + +const mockPrisma = { + user: { + findMany: jest.fn().mockResolvedValue([]), + findUnique: jest.fn().mockResolvedValue({ id: '1' }), + findFirst: jest.fn().mockResolvedValue({ id: '1' }), + create: jest.fn().mockResolvedValue({}), + update: jest.fn().mockResolvedValue({}), + delete: jest.fn().mockResolvedValue({}), + }, +} as unknown as PrismaClient; +describe('Given a instance of the class UsersSqlRepo', () => { + const repo = new UsersSqlRepo(mockPrisma); + + test('Then it should be instance of the class', () => { + expect(repo).toBeInstanceOf(UsersSqlRepo); + }); + + describe('When we use the method readAll', () => { + test('Then it should call prisma.findMany', async () => { + const result = await repo.readAll(); + expect(mockPrisma.user.findMany).toHaveBeenCalled(); + expect(result).toEqual([]); + }); + }); + + describe('When we use the method readById with a valid ID', () => { + test('Then it should call prisma.findUnique', async () => { + const result = await repo.readById('1'); + expect(mockPrisma.user.findUnique).toHaveBeenCalled(); + expect(result).toEqual({ id: '1' }); + }); + }); + + describe('When we use the method readById with an invalid ID', () => { + test('Then it should throw an error', async () => { + (mockPrisma.user.findUnique as jest.Mock).mockResolvedValueOnce(null); + await expect(repo.readById('2')).rejects.toThrow( + new HttpError(404, 'Not Found', 'User 2 not found') + ); + }); + }); + + describe('When we use the method searchForLogin with a valid key', () => { + test('Then it should call prisma.findFirst', async () => { + const result = await repo.searchForLogin('email', 'test@sample.com'); + expect(mockPrisma.user.findFirst).toHaveBeenCalled(); + expect(result).toEqual({ id: '1' }); + }); + }); + + describe('When we use the method searchForLogin with an invalid key', () => { + test('Then it should throw an error', async () => { + await expect( + repo.searchForLogin('invalid' as 'name', 'test') + ).rejects.toThrow( + new HttpError(400, 'Bad Request', 'Invalid query parameters') + ); + }); + }); + + describe('When we use the method searchForLogin with an invalid value', () => { + test('Then it should throw an error', async () => { + (mockPrisma.user.findFirst as jest.Mock).mockResolvedValueOnce(null); + await expect(repo.searchForLogin('email', 'test')).rejects.toThrow( + new HttpError(400, 'Bad Request', 'Invalid email or password') + ); + }); + }); + + describe('When we use the method create', () => { + test('Then it should call prisma.create', async () => { + const data = {} as unknown as UserCreateDto; + const result = await repo.create(data); + expect(mockPrisma.user.create).toHaveBeenCalled(); + expect(result).toEqual({}); + }); + }); + + describe('When we use the method update with a valid ID', () => { + test('Then it should call prisma.update', async () => { + const result = await repo.update('1', {}); + expect(mockPrisma.user.update).toHaveBeenCalled(); + expect(result).toEqual({}); + }); + }); + + describe('When we use the method update with an invalid ID', () => { + test('Then it should throw an error', async () => { + (mockPrisma.user.findUnique as jest.Mock).mockResolvedValueOnce(null); + await expect(repo.update('2', {})).rejects.toThrow( + new HttpError(404, 'Not Found', 'User 2 not found') + ); + }); + }); + + describe('When we use the method delete with a valid ID', () => { + test('Then it should call prisma.delete', async () => { + const result = await repo.delete('1'); + expect(mockPrisma.user.delete).toHaveBeenCalled(); + expect(result).toEqual({}); + }); + }); + + describe('When we use the method delete with an invalid ID', () => { + test('Then it should throw an error', async () => { + (mockPrisma.user.findUnique as jest.Mock).mockResolvedValueOnce(null); + await expect(repo.delete('2')).rejects.toThrow( + new HttpError(404, 'Not Found', 'User 2 not found') + ); + }); + }); +}); diff --git a/src/repositories/users.sql.repo.ts b/src/repositories/users.sql.repo.ts new file mode 100644 index 0000000..7c74d46 --- /dev/null +++ b/src/repositories/users.sql.repo.ts @@ -0,0 +1,108 @@ +import createDebug from 'debug'; +import { type WithLoginRepo } from './type.repo'; +import { type UserCreateDto, type User } from '../entities/user'; +import { type PrismaClient } from '@prisma/client'; +import { HttpError } from '../middleware/errors.middleware'; +const debug = createDebug('GONJI:users:repository:sql'); + +const select = { + id: true, + email: true, + password: true, + userName: true, + characters: { + select: { + id: true, + name: true, + imgUrl: true, + description: true, + faction: true, + race: true, + }, + }, +}; + +export class UsersSqlRepo implements WithLoginRepo { + constructor(private readonly prisma: PrismaClient) { + debug('Instantiated users sql repository'); + } + + async readAll() { + return this.prisma.user.findMany({ + select, + }); + } + + async readById(id: string) { + const user = await this.prisma.user.findUnique({ + where: { id }, + select, + }); + if (!user) { + throw new HttpError(404, 'Not Found', `User ${id} not found`); + } + + return user; + } + + async searchForLogin(key: 'email' | 'name', value: string) { + if (!['email', 'name'].includes(key)) { + throw new HttpError(404, 'Not Found', 'Invalid query parameters'); + } + + const userData = await this.prisma.user.findFirst({ + where: { + [key]: value, + }, + select: { + id: true, + email: true, + password: true, + userName: true, + }, + }); + + if (!userData) { + throw new HttpError(404, 'Not Found', `Invalid ${key} or password`); + } + + return userData; + } + + async create(data: UserCreateDto) { + const newUser = this.prisma.user.create({ + data, + select, + }); + return newUser; + } + + async update(id: string, data: Partial) { + const user = await this.prisma.user.findUnique({ + where: { id }, + }); + if (!user) { + throw new HttpError(404, 'Not Found', `User ${id} not found`); + } + + return this.prisma.user.update({ + where: { id }, + data, + select, + }); + } + + async delete(id: string) { + const user = await this.prisma.user.findUnique({ + where: { id }, + }); + if (!user) { + throw new HttpError(404, 'Not Found', `User ${id} not found`); + } + + return this.prisma.user.delete({ + where: { id }, + select, + }); + } +} diff --git a/src/tools/db.connect.ts b/src/tools/db.connect.ts new file mode 100644 index 0000000..b2c6709 --- /dev/null +++ b/src/tools/db.connect.ts @@ -0,0 +1,9 @@ +import { PrismaClient } from '@prisma/client'; +import createDebug from 'debug'; + +const debug = createDebug('GONJI:db.connect'); +export const dbConnect = async () => { + debug('Connecting to database'); + const prisma = new PrismaClient(); + return prisma; +};