Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions infra/scripts/build-lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ async function buildLambda() {
platform: 'node',
target: 'node22',
outfile: path.join(outDir, 'index.js'),
minify: false,
treeShaking: false,
minify: true,
treeShaking: true,
sourcemap: false,
external: [
'class-transformer/storage',
'@nestjs/microservices',
'@nestjs/websockets/socket-module',
'@nestjs/microservices/microservices-module',
'pino-pretty',
],
});

Expand Down
30 changes: 1 addition & 29 deletions src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { NestFactory } from '@nestjs/core';
import type { ExpressAdapter } from '@nestjs/platform-express';
import { NestExpressApplication } from '@nestjs/platform-express';
import { DocumentBuilder, OpenAPIObject, SwaggerModule } from '@nestjs/swagger';
import cookieParser from 'cookie-parser';
import { Logger } from 'nestjs-pino';
import { cleanupOpenApiDoc } from 'nestjs-zod';

import { EnvService } from '@/env/env.service';

Expand All @@ -20,7 +18,6 @@ export async function createNestApp(adapter?: ExpressAdapter) {
});

const envService = app.get(EnvService);
const enableNestLogs = envService.get('ENABLE_NEST_LOGS');

app.enableCors({
origin: envService.get('APP_URL'),
Expand All @@ -30,35 +27,10 @@ export async function createNestApp(adapter?: ExpressAdapter) {
});
app.use(cookieParser(envService.get('COOKIE_SECRET')));

const enableNestLogs = envService.get('ENABLE_NEST_LOGS');
if (enableNestLogs) {
app.useLogger(app.get(Logger));
}

const config = new DocumentBuilder()
.setTitle('SVM - Sistema Viver Melhor')
.setDescription(
'Esta documentação lista as rotas disponíveis da aplicação, bem como seus respectivos requisitos e dados retornados.',
)
.setVersion('0.0.1')
.build();

const cleanupSwagger = cleanupOpenApiDoc as unknown as (
doc: OpenAPIObject,
) => OpenAPIObject;

const swaggerDocument = SwaggerModule.createDocument(app, config);
const cleanedDocument = cleanupSwagger(swaggerDocument);

SwaggerModule.setup('/swagger', app, cleanedDocument, {
swaggerOptions: {
withCredentials: true,
persistAuthorization: true,
requestInterceptor: (request: { credentials?: string }) => {
request.credentials = 'include';
return request;
},
},
});

return app;
}
29 changes: 2 additions & 27 deletions src/app/database/database.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';

import { testTypeOrmConfig } from '@/config/typeorm.config';
import { getTypeOrmConfig } from '@/config/typeorm.config';
import { EnvModule } from '@/env/env.module';
import { EnvService } from '@/env/env.service';

Expand All @@ -11,31 +10,7 @@ import { EnvService } from '@/env/env.service';
TypeOrmModule.forRootAsync({
imports: [EnvModule],
inject: [EnvService],
useFactory: (env: EnvService) => {
if (env.get('NODE_ENV') === 'test') {
return testTypeOrmConfig();
}

// Use regular configuration for all other environments
return {
type: 'mysql',
host: env.get('DB_HOST'),
port: env.get('DB_PORT'),
database: env.get('DB_DATABASE'),
username: env.get('DB_USERNAME'),
password: env.get('DB_PASSWORD'),
migrations: [__dirname + 'infra/database/migrations/**/*.ts'],
namingStrategy: new SnakeNamingStrategy(),
autoLoadEntities: true,
synchronize: false,
retryAttempts: 3,
retryDelay: 3000,
extra: {
connectionLimit: 10,
connectTimeout: 10000,
},
};
},
useFactory: (env: EnvService) => getTypeOrmConfig(env),
}),
],
})
Expand Down
11 changes: 8 additions & 3 deletions src/app/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'reflect-metadata';

import type { RequestListener } from 'node:http';

import { INestApplication } from '@nestjs/common';
import { ExpressAdapter } from '@nestjs/platform-express';
import serverlessExpress from '@vendia/serverless-express';
import { APIGatewayProxyEvent, Callback, Context } from 'aws-lambda';
Expand All @@ -10,16 +11,20 @@ import express from 'express';
import { createNestApp } from './app';

let cachedHandler: ReturnType<typeof serverlessExpress>;
let app: INestApplication;

const expressApp = express();
const adapter = new ExpressAdapter(expressApp);

export const handler = async (
event: APIGatewayProxyEvent,
context: Context,
callback: Callback,
) => {
context.callbackWaitsForEmptyEventLoop = false;

if (!cachedHandler) {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await createNestApp(adapter);
app = await createNestApp(adapter);

await app.init();

Expand Down
29 changes: 29 additions & 0 deletions src/app/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
import { DocumentBuilder, OpenAPIObject, SwaggerModule } from '@nestjs/swagger';
import { cleanupOpenApiDoc } from 'nestjs-zod';

import { EnvService } from '@/env/env.service';

import { createNestApp } from './app';

async function bootstrap(): Promise<void> {
const app = await createNestApp();

const config = new DocumentBuilder()
.setTitle('SVM - Sistema Viver Melhor')
.setDescription(
'Esta documentação lista as rotas disponíveis da aplicação, bem como seus respectivos requisitos e dados retornados.',
)
.setVersion('0.0.1')
.build();

const cleanupSwagger = cleanupOpenApiDoc as unknown as (
doc: OpenAPIObject,
) => OpenAPIObject;

const swaggerDocument = SwaggerModule.createDocument(app, config);
const cleanedDocument = cleanupSwagger(swaggerDocument);

SwaggerModule.setup('/swagger', app, cleanedDocument, {
swaggerOptions: {
withCredentials: true,
persistAuthorization: true,
requestInterceptor: (request: { credentials?: string }) => {
request.credentials = 'include';
return request;
},
},
});

const envService = app.get(EnvService);

const BASE_URL = envService.get('API_BASE_URL');
Expand Down
16 changes: 0 additions & 16 deletions src/config/database.config.ts

This file was deleted.

88 changes: 37 additions & 51 deletions src/config/typeorm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,49 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';

import { DATABASE_ENTITIES } from '@/domain/entities/database';
import { EnvService } from '@/env/env.service';

import { databaseConfig } from './database.config';
export function getTypeOrmConfig(env: EnvService): TypeOrmModuleOptions {
const isTestEnv = env.get('NODE_ENV') === 'test';

export const typeOrmConfig = (): TypeOrmModuleOptions => {
const config = databaseConfig();

return {
const baseConfig: TypeOrmModuleOptions = {
type: 'mysql',
host: config.host,
port: config.port,
username: config.username,
password: config.password,
database: config.database,
autoLoadEntities: true,
migrations: [__dirname + '/../infra/database/migrations/**/*.ts'],
synchronize: process.env.NODE_ENV !== 'production',
logging: process.env.NODE_ENV === 'development',
host: env.get('DB_HOST'),
port: env.get('DB_PORT'),
database: env.get('DB_DATABASE'),
username: env.get('DB_USERNAME'),
password: env.get('DB_PASSWORD'),
migrations: [__dirname + '/infra/database/migrations/**/*.ts'],
namingStrategy: new SnakeNamingStrategy(),
ssl:
process.env.APP_ENVIRONMENT === 'lambda'
? { rejectUnauthorized: true }
: undefined,
extra: {
connectionLimit: 10,
connectTimeout: 10000,
},
};
};

// Test-specific configuration
export const testTypeOrmConfig = (): TypeOrmModuleOptions => {
const config = databaseConfig();

return {
type: 'mysql',
host: config.host,
port: config.port,
username: config.username,
password: config.password,
database: config.schema || config.database, // Use test schema as database name in MySQL
entities: DATABASE_ENTITIES,
synchronize: false, // Disable synchronization for better performance
synchronize: false,
migrationsRun: false,
logging: false,
namingStrategy: new SnakeNamingStrategy(),
migrations: [], // Don't run migrations in test mode
dropSchema: false,
ssl: false,
retryAttempts: 1,
retryDelay: 500,
extra: {
connectionLimit: 3, // Reduced connection limit for tests
connectTimeout: 5000, // Faster timeout
acquireTimeout: 3000, // Faster acquire timeout
timeout: 3000, // Query timeout
charset: 'utf8mb4_unicode_ci',
// MySQL-specific optimizations for tests
ssl: false,
connectionLimit: 2,
connectTimeout: 2000,
enableKeepAlive: true,
keepAliveInitialDelay: 0,
},
// Additional performance optimizations
cache: false, // Disable caching in tests
dropSchema: false, // Don't drop schema
migrationsRun: false, // Don't run migrations
};
};

if (isTestEnv) {
return {
...baseConfig,
cache: false,
extra: {
...baseConfig.extra,
acquireTimeout: 2000,
charset: 'utf8mb4_unicode_ci',
ssl: false,
timeout: 2000,
},
};
}

return baseConfig;
}
10 changes: 0 additions & 10 deletions tests/config/test-database.module.ts

This file was deleted.

Loading