Merge branch 'clean' into 'main'
clean using es6 See merge request v3/service/auth!38
This commit is contained in:
commit
ecb71b8cc3
|
@ -3,7 +3,7 @@ import { InjectMapper } from '@automapper/nestjs';
|
|||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DatabaseException } from 'src/modules/database/src/exceptions/database.exception';
|
||||
import { DatabaseException } from 'src/modules/database/exceptions/database.exception';
|
||||
import { AddUsernameCommand } from '../../commands/add-username.command';
|
||||
import { CreateAuthenticationCommand } from '../../commands/create-authentication.command';
|
||||
import { DeleteAuthenticationCommand } from '../../commands/delete-authentication.command';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthRepository } from '../../../database/src/domain/auth-repository';
|
||||
import { AuthRepository } from '../../../database/domain/auth-repository';
|
||||
import { Authentication } from '../../domain/entities/authentication';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationRepository extends AuthRepository<Authentication> {
|
||||
protected _model = 'auth';
|
||||
protected model = 'auth';
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ import { IMessageBroker } from '../../domain/interfaces/message-broker';
|
|||
@Injectable()
|
||||
export class Messager extends IMessageBroker {
|
||||
constructor(
|
||||
private readonly _amqpConnection: AmqpConnection,
|
||||
private readonly amqpConnection: AmqpConnection,
|
||||
configService: ConfigService,
|
||||
) {
|
||||
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||
}
|
||||
|
||||
publish(routingKey: string, message: string): void {
|
||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||
}
|
||||
publish = (routingKey: string, message: string): void => {
|
||||
this.amqpConnection.publish(this.exchange, routingKey, message);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthRepository } from '../../../database/src/domain/auth-repository';
|
||||
import { AuthRepository } from '../../../database/domain/auth-repository';
|
||||
import { Username } from '../../domain/entities/username';
|
||||
|
||||
@Injectable()
|
||||
export class UsernameRepository extends AuthRepository<Username> {
|
||||
protected _model = 'username';
|
||||
protected model = 'username';
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export class AddUsernameUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: AddUsernameCommand): Promise<Username> {
|
||||
execute = async (command: AddUsernameCommand): Promise<Username> => {
|
||||
const { uuid, username, type } = command.addUsernameRequest;
|
||||
try {
|
||||
return await this._usernameRepository.create({
|
||||
|
@ -29,5 +29,5 @@ export class AddUsernameUseCase {
|
|||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ export class CreateAuthenticationUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: CreateAuthenticationCommand): Promise<Authentication> {
|
||||
execute = async (
|
||||
command: CreateAuthenticationCommand,
|
||||
): Promise<Authentication> => {
|
||||
const { uuid, password, ...username } = command.createAuthenticationRequest;
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
|
||||
|
@ -40,5 +42,5 @@ export class CreateAuthenticationUseCase {
|
|||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { AuthenticationRepository } from '../../adapters/secondaries/authenticat
|
|||
import { Messager } from '../../adapters/secondaries/messager';
|
||||
import { UsernameRepository } from '../../adapters/secondaries/username.repository';
|
||||
import { DeleteAuthenticationCommand } from '../../commands/delete-authentication.command';
|
||||
import { Authentication } from '../entities/authentication';
|
||||
|
||||
@CommandHandler(DeleteAuthenticationCommand)
|
||||
export class DeleteAuthenticationUseCase {
|
||||
|
@ -12,7 +13,9 @@ export class DeleteAuthenticationUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: DeleteAuthenticationCommand) {
|
||||
execute = async (
|
||||
command: DeleteAuthenticationCommand,
|
||||
): Promise<Authentication> => {
|
||||
try {
|
||||
await this._usernameRepository.deleteMany({
|
||||
uuid: command.deleteAuthenticationRequest.uuid,
|
||||
|
@ -30,5 +33,5 @@ export class DeleteAuthenticationUseCase {
|
|||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export class DeleteUsernameUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: DeleteUsernameCommand) {
|
||||
execute = async (command: DeleteUsernameCommand): Promise<void> => {
|
||||
try {
|
||||
const { username } = command.deleteUsernameRequest;
|
||||
const usernameFound = await this._usernameRepository.findOne({
|
||||
|
@ -34,5 +34,5 @@ export class DeleteUsernameUseCase {
|
|||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export class UpdatePasswordUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: UpdatePasswordCommand): Promise<Authentication> {
|
||||
execute = async (command: UpdatePasswordCommand): Promise<Authentication> => {
|
||||
const { uuid, password } = command.updatePasswordRequest;
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
|
||||
|
@ -30,5 +30,5 @@ export class UpdatePasswordUseCase {
|
|||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export class UpdateUsernameUseCase {
|
|||
private readonly _messager: Messager,
|
||||
) {}
|
||||
|
||||
async execute(command: UpdateUsernameCommand): Promise<Username> {
|
||||
execute = async (command: UpdateUsernameCommand): Promise<Username> => {
|
||||
const { uuid, username, type } = command.updateUsernameRequest;
|
||||
if (!username) throw new BadRequestException();
|
||||
// update username if it exists, otherwise create it
|
||||
|
@ -63,5 +63,5 @@ export class UpdateUsernameUseCase {
|
|||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ export class ValidateAuthenticationUseCase {
|
|||
private readonly _usernameRepository: UsernameRepository,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
execute = async (
|
||||
validate: ValidateAuthenticationQuery,
|
||||
): Promise<Authentication> {
|
||||
): Promise<Authentication> => {
|
||||
let username = new Username();
|
||||
try {
|
||||
username = await this._usernameRepository.findOne({
|
||||
|
@ -37,5 +37,5 @@ export class ValidateAuthenticationUseCase {
|
|||
} catch (e) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { TestingModule, Test } from '@nestjs/testing';
|
||||
import { DatabaseModule } from '../../../database/database.module';
|
||||
import { PrismaService } from '../../../database/src/adapters/secondaries/prisma-service';
|
||||
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
||||
import { PrismaService } from '../../../database/adapters/secondaries/prisma-service';
|
||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||
import { AuthenticationRepository } from '../../adapters/secondaries/authentication.repository';
|
||||
import { v4 } from 'uuid';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { TestingModule, Test } from '@nestjs/testing';
|
||||
import { DatabaseModule } from '../../../database/database.module';
|
||||
import { PrismaService } from '../../../database/src/adapters/secondaries/prisma-service';
|
||||
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
||||
import { PrismaService } from '../../../database/adapters/secondaries/prisma-service';
|
||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||
import { v4 } from 'uuid';
|
||||
import { Type } from '../../domain/dtos/type.enum';
|
||||
import { UsernameRepository } from '../../adapters/secondaries/username.repository';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ValidateAuthenticationQuery } from '../../queries/validate-authenticati
|
|||
import { UsernameRepository } from '../../adapters/secondaries/username.repository';
|
||||
import { Type } from '../../domain/dtos/type.enum';
|
||||
import { NotFoundException, UnauthorizedException } from '@nestjs/common';
|
||||
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
||||
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||
import { ValidateAuthenticationRequest } from '../../domain/dtos/validate-authentication.request';
|
||||
|
||||
const mockAuthenticationRepository = {
|
||||
|
|
|
@ -5,13 +5,12 @@ import { Authorization } from '../entities/authorization';
|
|||
|
||||
@QueryHandler(DecisionQuery)
|
||||
export class DecisionUseCase {
|
||||
constructor(private readonly _decisionMaker: OpaDecisionMaker) {}
|
||||
constructor(private readonly decisionMaker: OpaDecisionMaker) {}
|
||||
|
||||
async execute(decisionQuery: DecisionQuery): Promise<Authorization> {
|
||||
return this._decisionMaker.decide(
|
||||
execute = (decisionQuery: DecisionQuery): Promise<Authorization> =>
|
||||
this.decisionMaker.decide(
|
||||
decisionQuery.domain,
|
||||
decisionQuery.action,
|
||||
decisionQuery.context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { DatabaseException } from '../../exceptions/database.exception';
|
||||
import { ICollection } from '../../interfaces/collection.interface';
|
||||
import { IRepository } from '../../interfaces/repository.interface';
|
||||
import { PrismaService } from './prisma-service';
|
||||
|
||||
/**
|
||||
* Child classes MUST redefined _model property with appropriate model name
|
||||
*/
|
||||
@Injectable()
|
||||
export abstract class PrismaRepository<T> implements IRepository<T> {
|
||||
protected model: string;
|
||||
|
||||
constructor(protected readonly prisma: PrismaService) {}
|
||||
|
||||
findAll = async (
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
where?: any,
|
||||
include?: any,
|
||||
): Promise<ICollection<T>> => {
|
||||
const [data, total] = await this.prisma.$transaction([
|
||||
this.prisma[this.model].findMany({
|
||||
where,
|
||||
include,
|
||||
skip: (page - 1) * perPage,
|
||||
take: perPage,
|
||||
}),
|
||||
this.prisma[this.model].count({
|
||||
where,
|
||||
}),
|
||||
]);
|
||||
return Promise.resolve({
|
||||
data,
|
||||
total,
|
||||
});
|
||||
};
|
||||
|
||||
findOneByUuid = async (uuid: string): Promise<T> => {
|
||||
try {
|
||||
const entity = await this.prisma[this.model].findUnique({
|
||||
where: { uuid },
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
findOne = async (where: any, include?: any): Promise<T> => {
|
||||
try {
|
||||
const entity = await this.prisma[this.model].findFirst({
|
||||
where: where,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO : using any is not good, but needed for nested entities
|
||||
// TODO : Refactor for good clean architecture ?
|
||||
create = async (entity: Partial<T> | any, include?: any): Promise<T> => {
|
||||
try {
|
||||
const res = await this.prisma[this.model].create({
|
||||
data: entity,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
update = async (uuid: string, entity: Partial<T>): Promise<T> => {
|
||||
try {
|
||||
const updatedEntity = await this.prisma[this.model].update({
|
||||
where: { uuid },
|
||||
data: entity,
|
||||
});
|
||||
return updatedEntity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateWhere = async (
|
||||
where: any,
|
||||
entity: Partial<T> | any,
|
||||
include?: any,
|
||||
): Promise<T> => {
|
||||
try {
|
||||
const updatedEntity = await this.prisma[this.model].update({
|
||||
where: where,
|
||||
data: entity,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return updatedEntity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
delete = async (uuid: string): Promise<T> => {
|
||||
try {
|
||||
const entity = await this.prisma[this.model].delete({
|
||||
where: { uuid },
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
deleteMany = async (where: any): Promise<void> => {
|
||||
try {
|
||||
const entity = await this.prisma[this.model].deleteMany({
|
||||
where: where,
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
findAllByQuery = async (
|
||||
include: string[],
|
||||
where: string[],
|
||||
): Promise<ICollection<T>> => {
|
||||
const query = `SELECT ${include.join(',')} FROM ${
|
||||
this.model
|
||||
} WHERE ${where.join(' AND ')}`;
|
||||
const data: T[] = await this.prisma.$queryRawUnsafe(query);
|
||||
return Promise.resolve({
|
||||
data,
|
||||
total: data.length,
|
||||
});
|
||||
};
|
||||
|
||||
createWithFields = async (fields: object): Promise<number> => {
|
||||
try {
|
||||
const command = `INSERT INTO ${this.model} ("${Object.keys(fields).join(
|
||||
'","',
|
||||
)}") VALUES (${Object.values(fields).join(',')})`;
|
||||
return await this.prisma.$executeRawUnsafe(command);
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateWithFields = async (uuid: string, entity: object): Promise<number> => {
|
||||
entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`;
|
||||
const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`);
|
||||
try {
|
||||
const command = `UPDATE ${this.model} SET ${values.join(
|
||||
', ',
|
||||
)} WHERE uuid = '${uuid}'`;
|
||||
return await this.prisma.$executeRawUnsafe(command);
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
healthCheck = async (): Promise<boolean> => {
|
||||
try {
|
||||
await this.prisma.$queryRaw`SELECT 1`;
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
Prisma.PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { AuthenticationRepository } from '../authentication/adapters/secondaries/authentication.repository';
|
||||
import { UsernameRepository } from '../authentication/adapters/secondaries/username.repository';
|
||||
import { PrismaService } from './src/adapters/secondaries/prisma-service';
|
||||
import { PrismaService } from './adapters/secondaries/prisma-service';
|
||||
|
||||
@Module({
|
||||
providers: [PrismaService, AuthenticationRepository, UsernameRepository],
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime';
|
||||
import { DatabaseException } from '../../exceptions/database.exception';
|
||||
import { ICollection } from '../../interfaces/collection.interface';
|
||||
import { IRepository } from '../../interfaces/repository.interface';
|
||||
import { PrismaService } from './prisma-service';
|
||||
|
||||
/**
|
||||
* Child classes MUST redefined _model property with appropriate model name
|
||||
*/
|
||||
@Injectable()
|
||||
export abstract class PrismaRepository<T> implements IRepository<T> {
|
||||
protected _model: string;
|
||||
|
||||
constructor(protected readonly _prisma: PrismaService) {}
|
||||
|
||||
async findAll(
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
where?: any,
|
||||
include?: any,
|
||||
): Promise<ICollection<T>> {
|
||||
const [data, total] = await this._prisma.$transaction([
|
||||
this._prisma[this._model].findMany({
|
||||
where,
|
||||
include,
|
||||
skip: (page - 1) * perPage,
|
||||
take: perPage,
|
||||
}),
|
||||
this._prisma[this._model].count({
|
||||
where,
|
||||
}),
|
||||
]);
|
||||
return Promise.resolve({
|
||||
data,
|
||||
total,
|
||||
});
|
||||
}
|
||||
|
||||
async findOneByUuid(uuid: string): Promise<T> {
|
||||
try {
|
||||
const entity = await this._prisma[this._model].findUnique({
|
||||
where: { uuid },
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async findOne(where: any, include?: any): Promise<T> {
|
||||
try {
|
||||
const entity = await this._prisma[this._model].findFirst({
|
||||
where: where,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(PrismaClientKnownRequestError.name, e.code);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async create(entity: Partial<T> | any, include?: any): Promise<T> {
|
||||
try {
|
||||
const res = await this._prisma[this._model].create({
|
||||
data: entity,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async update(uuid: string, entity: Partial<T>): Promise<T> {
|
||||
try {
|
||||
const updatedEntity = await this._prisma[this._model].update({
|
||||
where: { uuid },
|
||||
data: entity,
|
||||
});
|
||||
return updatedEntity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateWhere(
|
||||
where: any,
|
||||
entity: Partial<T> | any,
|
||||
include?: any,
|
||||
): Promise<T> {
|
||||
try {
|
||||
const updatedEntity = await this._prisma[this._model].update({
|
||||
where: where,
|
||||
data: entity,
|
||||
include: include,
|
||||
});
|
||||
|
||||
return updatedEntity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async delete(uuid: string): Promise<T> {
|
||||
try {
|
||||
const entity = await this._prisma[this._model].delete({
|
||||
where: { uuid },
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async deleteMany(where: any): Promise<void> {
|
||||
try {
|
||||
const entity = await this._prisma[this._model].deleteMany({
|
||||
where: where,
|
||||
});
|
||||
|
||||
return entity;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async healthCheck(): Promise<boolean> {
|
||||
try {
|
||||
await this._prisma.$queryRaw`SELECT 1`;
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof PrismaClientKnownRequestError) {
|
||||
throw new DatabaseException(
|
||||
PrismaClientKnownRequestError.name,
|
||||
e.code,
|
||||
e.message,
|
||||
);
|
||||
} else {
|
||||
throw new DatabaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PrismaService } from '../../src/adapters/secondaries/prisma-service';
|
||||
import { PrismaRepository } from '../../src/adapters/secondaries/prisma-repository.abstract';
|
||||
import { DatabaseException } from '../../src/exceptions/database.exception';
|
||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime';
|
||||
import { PrismaService } from '../../adapters/secondaries/prisma-service';
|
||||
import { PrismaRepository } from '../../adapters/secondaries/prisma-repository.abstract';
|
||||
import { DatabaseException } from '../../exceptions/database.exception';
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
class FakeEntity {
|
||||
uuid?: string;
|
||||
|
@ -41,7 +41,7 @@ Array.from({ length: 10 }).forEach(() => {
|
|||
|
||||
@Injectable()
|
||||
class FakePrismaRepository extends PrismaRepository<FakeEntity> {
|
||||
protected _model = 'fake';
|
||||
protected model = 'fake';
|
||||
}
|
||||
|
||||
class FakePrismaService extends PrismaService {
|
||||
|
@ -57,10 +57,40 @@ const mockPrismaService = {
|
|||
|
||||
return Promise.resolve([fakeEntities, fakeEntities.length]);
|
||||
}),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
$queryRawUnsafe: jest.fn().mockImplementation((query?: string) => {
|
||||
return Promise.resolve(fakeEntities);
|
||||
}),
|
||||
$executeRawUnsafe: jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(fakeEntityCreated)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((fields: object) => {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((fields: object) => {
|
||||
throw new Error('an unknown error');
|
||||
})
|
||||
.mockResolvedValueOnce(fakeEntityCreated)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((fields: object) => {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((fields: object) => {
|
||||
throw new Error('an unknown error');
|
||||
}),
|
||||
$queryRaw: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -69,7 +99,7 @@ const mockPrismaService = {
|
|||
return true;
|
||||
})
|
||||
.mockImplementation(() => {
|
||||
throw new PrismaClientKnownRequestError('Database unavailable', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('Database unavailable', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -80,7 +110,7 @@ const mockPrismaService = {
|
|||
.mockResolvedValueOnce(fakeEntityCreated)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -109,7 +139,7 @@ const mockPrismaService = {
|
|||
}
|
||||
|
||||
if (!entity && params?.where?.uuid == 'unknown') {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -131,7 +161,7 @@ const mockPrismaService = {
|
|||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -145,14 +175,14 @@ const mockPrismaService = {
|
|||
.fn()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -182,7 +212,7 @@ const mockPrismaService = {
|
|||
.fn()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -206,7 +236,7 @@ const mockPrismaService = {
|
|||
.fn()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.mockImplementationOnce((params?: any) => {
|
||||
throw new PrismaClientKnownRequestError('unknown request', {
|
||||
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||
code: 'code',
|
||||
clientVersion: 'version',
|
||||
});
|
||||
|
@ -440,6 +470,86 @@ describe('PrismaRepository', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('findAllByquery', () => {
|
||||
it('should return an array of entities', async () => {
|
||||
const entities = await fakeRepository.findAllByQuery(
|
||||
['uuid', 'name'],
|
||||
['name is not null'],
|
||||
);
|
||||
expect(entities).toStrictEqual({
|
||||
data: fakeEntities,
|
||||
total: fakeEntities.length,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createWithFields', () => {
|
||||
it('should create an entity', async () => {
|
||||
jest.spyOn(prisma, '$queryRawUnsafe');
|
||||
|
||||
const newEntity = await fakeRepository.createWithFields({
|
||||
uuid: '804319b3-a09b-4491-9f82-7976bfce0aff',
|
||||
name: 'my-name',
|
||||
});
|
||||
expect(newEntity).toBe(fakeEntityCreated);
|
||||
expect(prisma.$queryRawUnsafe).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException for client error', async () => {
|
||||
await expect(
|
||||
fakeRepository.createWithFields({
|
||||
uuid: '804319b3-a09b-4491-9f82-7976bfce0aff',
|
||||
name: 'my-name',
|
||||
}),
|
||||
).rejects.toBeInstanceOf(DatabaseException);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if uuid is not found', async () => {
|
||||
await expect(
|
||||
fakeRepository.createWithFields({
|
||||
name: 'my-name',
|
||||
}),
|
||||
).rejects.toBeInstanceOf(DatabaseException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateWithFields', () => {
|
||||
it('should update an entity', async () => {
|
||||
jest.spyOn(prisma, '$queryRawUnsafe');
|
||||
|
||||
const updatedEntity = await fakeRepository.updateWithFields(
|
||||
'804319b3-a09b-4491-9f82-7976bfce0aff',
|
||||
{
|
||||
name: 'my-name',
|
||||
},
|
||||
);
|
||||
expect(updatedEntity).toBe(fakeEntityCreated);
|
||||
expect(prisma.$queryRawUnsafe).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException for client error', async () => {
|
||||
await expect(
|
||||
fakeRepository.updateWithFields(
|
||||
'804319b3-a09b-4491-9f82-7976bfce0aff',
|
||||
{
|
||||
name: 'my-name',
|
||||
},
|
||||
),
|
||||
).rejects.toBeInstanceOf(DatabaseException);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if uuid is not found', async () => {
|
||||
await expect(
|
||||
fakeRepository.updateWithFields(
|
||||
'804319b3-a09b-4491-9f82-7976bfce0aff',
|
||||
{
|
||||
name: 'my-name',
|
||||
},
|
||||
),
|
||||
).rejects.toBeInstanceOf(DatabaseException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('healthCheck', () => {
|
||||
it('should throw a DatabaseException for client error', async () => {
|
||||
await expect(fakeRepository.healthCheck()).rejects.toBeInstanceOf(
|
||||
|
|
|
@ -11,21 +11,21 @@ import { PrismaHealthIndicatorUseCase } from '../../domain/usecases/prisma.healt
|
|||
@Controller('health')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
private readonly _prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
||||
private _healthCheckService: HealthCheckService,
|
||||
private _messager: Messager,
|
||||
private readonly prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
||||
private healthCheckService: HealthCheckService,
|
||||
private messager: Messager,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@HealthCheck()
|
||||
async check() {
|
||||
try {
|
||||
return await this._healthCheckService.check([
|
||||
async () => this._prismaHealthIndicatorUseCase.isHealthy('prisma'),
|
||||
return await this.healthCheckService.check([
|
||||
async () => this.prismaHealthIndicatorUseCase.isHealthy('prisma'),
|
||||
]);
|
||||
} catch (error) {
|
||||
const healthCheckResult: HealthCheckResult = error.response;
|
||||
this._messager.publish(
|
||||
this.messager.publish(
|
||||
'logging.auth.health.crit',
|
||||
JSON.stringify(healthCheckResult.error),
|
||||
);
|
||||
|
|
|
@ -6,13 +6,13 @@ import { IMessageBroker } from './message-broker';
|
|||
@Injectable()
|
||||
export class Messager extends IMessageBroker {
|
||||
constructor(
|
||||
private readonly _amqpConnection: AmqpConnection,
|
||||
private readonly amqpConnection: AmqpConnection,
|
||||
configService: ConfigService,
|
||||
) {
|
||||
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||
}
|
||||
|
||||
publish(routingKey: string, message: string): void {
|
||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||
}
|
||||
publish = (routingKey: string, message: string): void => {
|
||||
this.amqpConnection.publish(this.exchange, routingKey, message);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,18 +8,18 @@ import { AuthenticationRepository } from '../../../authentication/adapters/secon
|
|||
|
||||
@Injectable()
|
||||
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
||||
constructor(private readonly _repository: AuthenticationRepository) {
|
||||
constructor(private readonly repository: AuthenticationRepository) {
|
||||
super();
|
||||
}
|
||||
|
||||
async isHealthy(key: string): Promise<HealthIndicatorResult> {
|
||||
isHealthy = async (key: string): Promise<HealthIndicatorResult> => {
|
||||
try {
|
||||
await this._repository.healthCheck();
|
||||
await this.repository.healthCheck();
|
||||
return this.getStatus(key, true);
|
||||
} catch (e) {
|
||||
throw new HealthCheckError('Prisma', {
|
||||
prisma: e.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue