feat: als and prisma

This commit is contained in:
sauravdhakal12
2026-02-10 17:19:53 +05:45
parent 65480c4f8c
commit 9561693cb4
32 changed files with 2124 additions and 35 deletions

View File

@@ -1,10 +1,28 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module';
import { RequestContextMiddleware } from 'core/als/request-context.middleware';
import { RequestContextModule } from 'core/als/request-context.module';
import { ConfigModule } from '@nestjs/config';
import { PrismaModule } from './prisma/prisma.module';
@Module({
imports: [],
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
UserModule,
AuthModule,
RequestContextModule,
PrismaModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(RequestContextMiddleware).forRoutes('*paths');
}
}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller';
describe('AuthController', () => {
let controller: AuthController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController],
}).compile();
controller = module.get<AuthController>(AuthController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';
@Controller('auth')
export class AuthController {}

9
src/auth/auth.module.ts Normal file
View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
@Module({
providers: [AuthService],
controllers: [AuthController]
})
export class AuthModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

4
src/auth/auth.service.ts Normal file
View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class AuthService {}

1
src/auth/types/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './jwt';

26
src/auth/types/jwt.ts Normal file
View File

@@ -0,0 +1,26 @@
export interface UserPayload {
iat?: number;
exp?: number;
userId: string;
email: string;
role: 'user';
}
// For restaurant owners, also resId
export interface StaffPayload {
iat?: number;
exp?: number;
userId: string;
email: string;
role: 'staff';
}
export interface AdminPayload {
iat?: number;
exp?: number;
userId: string;
email: string;
role: 'admin';
}
export type AuthPayload = UserPayload | StaffPayload | AdminPayload;

View File

@@ -1,8 +1,13 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
const config = app.get(ConfigService);
const port = config.get<number>('PORT') ?? 3000;
await app.listen(port);
}
bootstrap();

View File

@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import { RequestContextModule } from 'core/als/request-context.module';
@Module({
imports: [RequestContextModule],
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}

View File

@@ -0,0 +1,57 @@
import {
Global,
Injectable,
OnModuleDestroy,
OnModuleInit,
} from '@nestjs/common';
import { PrismaClient } from 'prisma/generated/prisma/client';
import { Pool } from 'pg';
import { PrismaPg } from '@prisma/adapter-pg';
import { RequestContextService } from 'core/als/request-context.service';
import { ConfigService } from '@nestjs/config';
@Global()
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleDestroy, OnModuleInit
{
constructor(
private readonly ctx: RequestContextService,
private readonly configService: ConfigService,
) {
const connectionString = configService.get<string>('DATABASE_URL');
const connectionPool = new Pool({
connectionString,
});
console.log(connectionString);
const adapter = new PrismaPg(connectionPool);
super({
adapter: adapter,
log: ['info', 'error', 'warn'],
});
}
async onModuleInit() {
try {
await this.$connect();
await this.$queryRaw`SELECT 1`;
} catch (err) {
console.error('❌ Prisma connection failed');
// throw err;
}
}
async onModuleDestroy() {
await this.$disconnect();
}
/*
* For shared transaction across services. If present, return the transaction.
* Else returns itself.
* */
get client() {
return this.ctx.get().tx ?? this;
}
}

7
src/user/user.module.ts Normal file
View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
@Module({
providers: [UserService]
})
export class UserModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
}).compile();
service = module.get<UserService>(UserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

4
src/user/user.service.ts Normal file
View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {}