Merge branch 'clean' into 'main'
clean using es6 See merge request v3/service/user!38
This commit is contained in:
commit
b4fdadda37
|
@ -12,8 +12,12 @@ WORKDIR /usr/src/app
|
||||||
# Copying this first prevents re-running npm install on every code change.
|
# Copying this first prevents re-running npm install on every code change.
|
||||||
COPY --chown=node:node package*.json ./
|
COPY --chown=node:node package*.json ./
|
||||||
|
|
||||||
|
# Copy prisma (needed for prisma error types)
|
||||||
|
COPY --chown=node:node ./prisma prisma
|
||||||
|
|
||||||
# Install app dependencies using the `npm ci` command instead of `npm install`
|
# Install app dependencies using the `npm ci` command instead of `npm install`
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
RUN npx prisma generate
|
||||||
|
|
||||||
# Bundle app source
|
# Bundle app source
|
||||||
COPY --chown=node:node . .
|
COPY --chown=node:node . .
|
||||||
|
|
|
@ -11,8 +11,8 @@ import { Configuration } from '../../domain/entities/configuration';
|
||||||
@Controller()
|
@Controller()
|
||||||
export class ConfigurationMessagerController {
|
export class ConfigurationMessagerController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _commandBus: CommandBus,
|
private readonly commandBus: CommandBus,
|
||||||
private readonly _configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@RabbitSubscribe({
|
@RabbitSubscribe({
|
||||||
|
@ -22,14 +22,14 @@ export class ConfigurationMessagerController {
|
||||||
const configuration: Configuration = JSON.parse(message);
|
const configuration: Configuration = JSON.parse(message);
|
||||||
if (
|
if (
|
||||||
configuration.domain ==
|
configuration.domain ==
|
||||||
this._configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
this.configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
||||||
) {
|
) {
|
||||||
const setConfigurationRequest: SetConfigurationRequest =
|
const setConfigurationRequest: SetConfigurationRequest =
|
||||||
new SetConfigurationRequest();
|
new SetConfigurationRequest();
|
||||||
setConfigurationRequest.domain = configuration.domain;
|
setConfigurationRequest.domain = configuration.domain;
|
||||||
setConfigurationRequest.key = configuration.key;
|
setConfigurationRequest.key = configuration.key;
|
||||||
setConfigurationRequest.value = configuration.value;
|
setConfigurationRequest.value = configuration.value;
|
||||||
await this._commandBus.execute(
|
await this.commandBus.execute(
|
||||||
new SetConfigurationCommand(setConfigurationRequest),
|
new SetConfigurationCommand(setConfigurationRequest),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,12 @@ export class ConfigurationMessagerController {
|
||||||
const deletedConfiguration: Configuration = JSON.parse(message);
|
const deletedConfiguration: Configuration = JSON.parse(message);
|
||||||
if (
|
if (
|
||||||
deletedConfiguration.domain ==
|
deletedConfiguration.domain ==
|
||||||
this._configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
this.configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
||||||
) {
|
) {
|
||||||
const deleteConfigurationRequest = new DeleteConfigurationRequest();
|
const deleteConfigurationRequest = new DeleteConfigurationRequest();
|
||||||
deleteConfigurationRequest.domain = deletedConfiguration.domain;
|
deleteConfigurationRequest.domain = deletedConfiguration.domain;
|
||||||
deleteConfigurationRequest.key = deletedConfiguration.key;
|
deleteConfigurationRequest.key = deletedConfiguration.key;
|
||||||
await this._commandBus.execute(
|
await this.commandBus.execute(
|
||||||
new DeleteConfigurationCommand(deleteConfigurationRequest),
|
new DeleteConfigurationCommand(deleteConfigurationRequest),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -61,14 +61,14 @@ export class ConfigurationMessagerController {
|
||||||
configurations.forEach(async (configuration) => {
|
configurations.forEach(async (configuration) => {
|
||||||
if (
|
if (
|
||||||
configuration.domain ==
|
configuration.domain ==
|
||||||
this._configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
this.configService.get<string>('SERVICE_CONFIGURATION_DOMAIN')
|
||||||
) {
|
) {
|
||||||
const setConfigurationRequest: SetConfigurationRequest =
|
const setConfigurationRequest: SetConfigurationRequest =
|
||||||
new SetConfigurationRequest();
|
new SetConfigurationRequest();
|
||||||
setConfigurationRequest.domain = configuration.domain;
|
setConfigurationRequest.domain = configuration.domain;
|
||||||
setConfigurationRequest.key = configuration.key;
|
setConfigurationRequest.key = configuration.key;
|
||||||
setConfigurationRequest.value = configuration.value;
|
setConfigurationRequest.value = configuration.value;
|
||||||
await this._commandBus.execute(
|
await this.commandBus.execute(
|
||||||
new SetConfigurationCommand(setConfigurationRequest),
|
new SetConfigurationCommand(setConfigurationRequest),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,14 @@ import { IConfigurationRepository } from '../../domain/interfaces/configuration.
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RedisConfigurationRepository extends IConfigurationRepository {
|
export class RedisConfigurationRepository extends IConfigurationRepository {
|
||||||
constructor(@InjectRedis() private readonly _redis: Redis) {
|
constructor(@InjectRedis() private readonly redis: Redis) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(key: string): Promise<string> {
|
get = async (key: string): Promise<string> => await this.redis.get(key);
|
||||||
return await this._redis.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
async set(key: string, value: string) {
|
set = async (key: string, value: string): Promise<'OK'> =>
|
||||||
await this._redis.set(key, value);
|
this.redis.set(key, value);
|
||||||
}
|
|
||||||
|
|
||||||
async del(key: string) {
|
del = async (key: string): Promise<number> => this.redis.del(key);
|
||||||
await this._redis.del(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,15 @@ import { DeleteConfigurationCommand } from '../../commands/delete-configuration.
|
||||||
|
|
||||||
@CommandHandler(DeleteConfigurationCommand)
|
@CommandHandler(DeleteConfigurationCommand)
|
||||||
export class DeleteConfigurationUseCase {
|
export class DeleteConfigurationUseCase {
|
||||||
constructor(private _configurationRepository: RedisConfigurationRepository) {}
|
constructor(private configurationRepository: RedisConfigurationRepository) {}
|
||||||
|
|
||||||
async execute(deleteConfigurationCommand: DeleteConfigurationCommand) {
|
execute = async (
|
||||||
await this._configurationRepository.del(
|
deleteConfigurationCommand: DeleteConfigurationCommand,
|
||||||
|
): Promise<void> => {
|
||||||
|
await this.configurationRepository.del(
|
||||||
deleteConfigurationCommand.deleteConfigurationRequest.domain +
|
deleteConfigurationCommand.deleteConfigurationRequest.domain +
|
||||||
':' +
|
':' +
|
||||||
deleteConfigurationCommand.deleteConfigurationRequest.key,
|
deleteConfigurationCommand.deleteConfigurationRequest.key,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import { GetConfigurationQuery } from '../../queries/get-configuration.query';
|
||||||
|
|
||||||
@QueryHandler(GetConfigurationQuery)
|
@QueryHandler(GetConfigurationQuery)
|
||||||
export class GetConfigurationUseCase {
|
export class GetConfigurationUseCase {
|
||||||
constructor(private _configurationRepository: RedisConfigurationRepository) {}
|
constructor(private configurationRepository: RedisConfigurationRepository) {}
|
||||||
|
|
||||||
async execute(getConfigurationQuery: GetConfigurationQuery): Promise<string> {
|
execute = async (
|
||||||
return this._configurationRepository.get(
|
getConfigurationQuery: GetConfigurationQuery,
|
||||||
|
): Promise<string> =>
|
||||||
|
this.configurationRepository.get(
|
||||||
getConfigurationQuery.domain + ':' + getConfigurationQuery.key,
|
getConfigurationQuery.domain + ':' + getConfigurationQuery.key,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,12 +6,14 @@ import { SetConfigurationCommand } from '../../commands/set-configuration.comman
|
||||||
export class SetConfigurationUseCase {
|
export class SetConfigurationUseCase {
|
||||||
constructor(private _configurationRepository: RedisConfigurationRepository) {}
|
constructor(private _configurationRepository: RedisConfigurationRepository) {}
|
||||||
|
|
||||||
async execute(setConfigurationCommand: SetConfigurationCommand) {
|
execute = async (
|
||||||
|
setConfigurationCommand: SetConfigurationCommand,
|
||||||
|
): Promise<void> => {
|
||||||
await this._configurationRepository.set(
|
await this._configurationRepository.set(
|
||||||
setConfigurationCommand.setConfigurationRequest.domain +
|
setConfigurationCommand.setConfigurationRequest.domain +
|
||||||
':' +
|
':' +
|
||||||
setConfigurationCommand.setConfigurationRequest.key,
|
setConfigurationCommand.setConfigurationRequest.key,
|
||||||
setConfigurationCommand.setConfigurationRequest.value,
|
setConfigurationCommand.setConfigurationRequest.value,
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,6 +1,6 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { PrismaService } from './src/adapters/secondaries/prisma-service';
|
import { PrismaService } from './adapters/secondaries/prisma-service';
|
||||||
import { UserRepository } from './src/domain/user-repository';
|
import { UserRepository } from './domain/user-repository';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [PrismaService, UserRepository],
|
providers: [PrismaService, UserRepository],
|
||||||
|
|
|
@ -1,202 +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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : using any is not good, but needed for nested entities
|
|
||||||
// TODO : Refactor for good clean architecture ?
|
|
||||||
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 { Injectable } from '@nestjs/common';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaService } from '../../src/adapters/secondaries/prisma-service';
|
import { PrismaService } from '../../adapters/secondaries/prisma-service';
|
||||||
import { PrismaRepository } from '../../src/adapters/secondaries/prisma-repository.abstract';
|
import { PrismaRepository } from '../../adapters/secondaries/prisma-repository.abstract';
|
||||||
import { DatabaseException } from '../../src/exceptions/database.exception';
|
import { DatabaseException } from '../../exceptions/database.exception';
|
||||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime';
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
class FakeEntity {
|
class FakeEntity {
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
|
@ -41,7 +41,7 @@ Array.from({ length: 10 }).forEach(() => {
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class FakePrismaRepository extends PrismaRepository<FakeEntity> {
|
class FakePrismaRepository extends PrismaRepository<FakeEntity> {
|
||||||
protected _model = 'fake';
|
protected model = 'fake';
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakePrismaService extends PrismaService {
|
class FakePrismaService extends PrismaService {
|
||||||
|
@ -57,10 +57,40 @@ const mockPrismaService = {
|
||||||
|
|
||||||
return Promise.resolve([fakeEntities, fakeEntities.length]);
|
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
|
$queryRaw: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -69,7 +99,7 @@ const mockPrismaService = {
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.mockImplementation(() => {
|
.mockImplementation(() => {
|
||||||
throw new PrismaClientKnownRequestError('Database unavailable', {
|
throw new Prisma.PrismaClientKnownRequestError('Database unavailable', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -80,7 +110,7 @@ const mockPrismaService = {
|
||||||
.mockResolvedValueOnce(fakeEntityCreated)
|
.mockResolvedValueOnce(fakeEntityCreated)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -109,7 +139,7 @@ const mockPrismaService = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entity && params?.where?.uuid == 'unknown') {
|
if (!entity && params?.where?.uuid == 'unknown') {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -131,7 +161,7 @@ const mockPrismaService = {
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -145,14 +175,14 @@ const mockPrismaService = {
|
||||||
.fn()
|
.fn()
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -182,7 +212,7 @@ const mockPrismaService = {
|
||||||
.fn()
|
.fn()
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
clientVersion: 'version',
|
||||||
});
|
});
|
||||||
|
@ -206,7 +236,7 @@ const mockPrismaService = {
|
||||||
.fn()
|
.fn()
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((params?: any) => {
|
.mockImplementationOnce((params?: any) => {
|
||||||
throw new PrismaClientKnownRequestError('unknown request', {
|
throw new Prisma.PrismaClientKnownRequestError('unknown request', {
|
||||||
code: 'code',
|
code: 'code',
|
||||||
clientVersion: 'version',
|
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', () => {
|
describe('healthCheck', () => {
|
||||||
it('should throw a DatabaseException for client error', async () => {
|
it('should throw a DatabaseException for client error', async () => {
|
||||||
await expect(fakeRepository.healthCheck()).rejects.toBeInstanceOf(
|
await expect(fakeRepository.healthCheck()).rejects.toBeInstanceOf(
|
||||||
|
|
|
@ -19,7 +19,7 @@ interface HealthCheckResponse {
|
||||||
@Controller()
|
@Controller()
|
||||||
export class HealthServerController {
|
export class HealthServerController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
private readonly prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@GrpcMethod('Health', 'Check')
|
@GrpcMethod('Health', 'Check')
|
||||||
|
@ -29,7 +29,7 @@ export class HealthServerController {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
metadata: any,
|
metadata: any,
|
||||||
): Promise<HealthCheckResponse> {
|
): Promise<HealthCheckResponse> {
|
||||||
const healthCheck = await this._prismaHealthIndicatorUseCase.isHealthy(
|
const healthCheck = await this.prismaHealthIndicatorUseCase.isHealthy(
|
||||||
'prisma',
|
'prisma',
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -10,21 +10,21 @@ import { PrismaHealthIndicatorUseCase } from '../../domain/usecases/prisma.healt
|
||||||
@Controller('health')
|
@Controller('health')
|
||||||
export class HealthController {
|
export class HealthController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
private readonly prismaHealthIndicatorUseCase: PrismaHealthIndicatorUseCase,
|
||||||
private _healthCheckService: HealthCheckService,
|
private readonly healthCheckService: HealthCheckService,
|
||||||
private _messager: Messager,
|
private readonly messager: Messager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@HealthCheck()
|
@HealthCheck()
|
||||||
async check() {
|
async check() {
|
||||||
try {
|
try {
|
||||||
return await this._healthCheckService.check([
|
return await this.healthCheckService.check([
|
||||||
async () => this._prismaHealthIndicatorUseCase.isHealthy('prisma'),
|
async () => this.prismaHealthIndicatorUseCase.isHealthy('prisma'),
|
||||||
]);
|
]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const healthCheckResult: HealthCheckResult = error.response;
|
const healthCheckResult: HealthCheckResult = error.response;
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'logging.user.health.crit',
|
'logging.user.health.crit',
|
||||||
JSON.stringify(healthCheckResult.error),
|
JSON.stringify(healthCheckResult.error),
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,13 +6,13 @@ import { IMessageBroker } from './message-broker';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Messager extends IMessageBroker {
|
export class Messager extends IMessageBroker {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _amqpConnection: AmqpConnection,
|
private readonly amqpConnection: AmqpConnection,
|
||||||
configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {
|
) {
|
||||||
super(configService.get<string>('RMQ_EXCHANGE'));
|
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(routingKey: string, message: string): void {
|
publish = (routingKey: string, message: string): void => {
|
||||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
this.amqpConnection.publish(this.exchange, routingKey, message);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,18 @@ import { UsersRepository } from '../../../user/adapters/secondaries/users.reposi
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
||||||
constructor(private readonly _repository: UsersRepository) {
|
constructor(private readonly repository: UsersRepository) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
async isHealthy(key: string): Promise<HealthIndicatorResult> {
|
isHealthy = async (key: string): Promise<HealthIndicatorResult> => {
|
||||||
try {
|
try {
|
||||||
await this._repository.healthCheck();
|
await this.repository.healthCheck();
|
||||||
return this.getStatus(key, true);
|
return this.getStatus(key, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new HealthCheckError('Prisma', {
|
throw new HealthCheckError('Prisma', {
|
||||||
prisma: e.message,
|
prisma: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||||
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||||
import { CreateUserCommand } from '../../commands/create-user.command';
|
import { CreateUserCommand } from '../../commands/create-user.command';
|
||||||
import { DeleteUserCommand } from '../../commands/delete-user.command';
|
import { DeleteUserCommand } from '../../commands/delete-user.command';
|
||||||
import { UpdateUserCommand } from '../../commands/update-user.command';
|
import { UpdateUserCommand } from '../../commands/update-user.command';
|
||||||
|
@ -21,7 +21,7 @@ import { User } from '../../domain/entities/user';
|
||||||
import { FindAllUsersQuery } from '../../queries/find-all-users.query';
|
import { FindAllUsersQuery } from '../../queries/find-all-users.query';
|
||||||
import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query';
|
import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query';
|
||||||
import { UserPresenter } from './user.presenter';
|
import { UserPresenter } from './user.presenter';
|
||||||
import { ICollection } from '../../../database/src/interfaces/collection.interface';
|
import { ICollection } from '../../../database/interfaces/collection.interface';
|
||||||
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
||||||
|
|
||||||
@UsePipes(
|
@UsePipes(
|
||||||
|
@ -33,21 +33,21 @@ import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
||||||
@Controller()
|
@Controller()
|
||||||
export class UserController {
|
export class UserController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _commandBus: CommandBus,
|
private readonly commandBus: CommandBus,
|
||||||
private readonly _queryBus: QueryBus,
|
private readonly queryBus: QueryBus,
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly mapper: Mapper,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@GrpcMethod('UsersService', 'FindAll')
|
@GrpcMethod('UsersService', 'FindAll')
|
||||||
@UseInterceptors(CacheInterceptor)
|
@UseInterceptors(CacheInterceptor)
|
||||||
@CacheKey('UsersServiceFindAll')
|
@CacheKey('UsersServiceFindAll')
|
||||||
async findAll(data: FindAllUsersRequest): Promise<ICollection<User>> {
|
async findAll(data: FindAllUsersRequest): Promise<ICollection<User>> {
|
||||||
const userCollection = await this._queryBus.execute(
|
const userCollection = await this.queryBus.execute(
|
||||||
new FindAllUsersQuery(data),
|
new FindAllUsersQuery(data),
|
||||||
);
|
);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: userCollection.data.map((user: User) =>
|
data: userCollection.data.map((user: User) =>
|
||||||
this._mapper.map(user, User, UserPresenter),
|
this.mapper.map(user, User, UserPresenter),
|
||||||
),
|
),
|
||||||
total: userCollection.total,
|
total: userCollection.total,
|
||||||
});
|
});
|
||||||
|
@ -58,8 +58,8 @@ export class UserController {
|
||||||
@CacheKey('UsersServiceFindOneByUuid')
|
@CacheKey('UsersServiceFindOneByUuid')
|
||||||
async findOneByUuid(data: FindUserByUuidRequest): Promise<UserPresenter> {
|
async findOneByUuid(data: FindUserByUuidRequest): Promise<UserPresenter> {
|
||||||
try {
|
try {
|
||||||
const user = await this._queryBus.execute(new FindUserByUuidQuery(data));
|
const user = await this.queryBus.execute(new FindUserByUuidQuery(data));
|
||||||
return this._mapper.map(user, User, UserPresenter);
|
return this.mapper.map(user, User, UserPresenter);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new RpcException({
|
throw new RpcException({
|
||||||
code: 5,
|
code: 5,
|
||||||
|
@ -71,8 +71,8 @@ export class UserController {
|
||||||
@GrpcMethod('UsersService', 'Create')
|
@GrpcMethod('UsersService', 'Create')
|
||||||
async createUser(data: CreateUserRequest): Promise<UserPresenter> {
|
async createUser(data: CreateUserRequest): Promise<UserPresenter> {
|
||||||
try {
|
try {
|
||||||
const user = await this._commandBus.execute(new CreateUserCommand(data));
|
const user = await this.commandBus.execute(new CreateUserCommand(data));
|
||||||
return this._mapper.map(user, User, UserPresenter);
|
return this.mapper.map(user, User, UserPresenter);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof DatabaseException) {
|
if (e instanceof DatabaseException) {
|
||||||
if (e.message.includes('Already exists')) {
|
if (e.message.includes('Already exists')) {
|
||||||
|
@ -89,9 +89,9 @@ export class UserController {
|
||||||
@GrpcMethod('UsersService', 'Update')
|
@GrpcMethod('UsersService', 'Update')
|
||||||
async updateUser(data: UpdateUserRequest): Promise<UserPresenter> {
|
async updateUser(data: UpdateUserRequest): Promise<UserPresenter> {
|
||||||
try {
|
try {
|
||||||
const user = await this._commandBus.execute(new UpdateUserCommand(data));
|
const user = await this.commandBus.execute(new UpdateUserCommand(data));
|
||||||
|
|
||||||
return this._mapper.map(user, User, UserPresenter);
|
return this.mapper.map(user, User, UserPresenter);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof DatabaseException) {
|
if (e instanceof DatabaseException) {
|
||||||
if (e.message.includes('not found')) {
|
if (e.message.includes('not found')) {
|
||||||
|
@ -108,7 +108,7 @@ export class UserController {
|
||||||
@GrpcMethod('UsersService', 'Delete')
|
@GrpcMethod('UsersService', 'Delete')
|
||||||
async deleteUser(data: FindUserByUuidRequest): Promise<void> {
|
async deleteUser(data: FindUserByUuidRequest): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this._commandBus.execute(new DeleteUserCommand(data.uuid));
|
await this.commandBus.execute(new DeleteUserCommand(data.uuid));
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -6,13 +6,13 @@ import { IMessageBroker } from '../../domain/interfaces/message-broker';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Messager extends IMessageBroker {
|
export class Messager extends IMessageBroker {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _amqpConnection: AmqpConnection,
|
private readonly amqpConnection: AmqpConnection,
|
||||||
configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {
|
) {
|
||||||
super(configService.get<string>('RMQ_EXCHANGE'));
|
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(routingKey: string, message: string): void {
|
publish = (routingKey: string, message: string): void => {
|
||||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
this.amqpConnection.publish(this.exchange, routingKey, message);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { UserRepository } from '../../../database/src/domain/user-repository';
|
import { UserRepository } from '../../../database/domain/user-repository';
|
||||||
import { User } from '../../domain/entities/user';
|
import { User } from '../../domain/entities/user';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersRepository extends UserRepository<User> {
|
export class UsersRepository extends UserRepository<User> {
|
||||||
protected _model = 'user';
|
protected model = 'user';
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,29 +10,29 @@ import { User } from '../entities/user';
|
||||||
@CommandHandler(CreateUserCommand)
|
@CommandHandler(CreateUserCommand)
|
||||||
export class CreateUserUseCase {
|
export class CreateUserUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _repository: UsersRepository,
|
private readonly repository: UsersRepository,
|
||||||
private readonly _messager: Messager,
|
private readonly messager: Messager,
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly mapper: Mapper,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: CreateUserCommand): Promise<User> {
|
execute = async (command: CreateUserCommand): Promise<User> => {
|
||||||
const entity = this._mapper.map(
|
const entity = this.mapper.map(
|
||||||
command.createUserRequest,
|
command.createUserRequest,
|
||||||
CreateUserRequest,
|
CreateUserRequest,
|
||||||
User,
|
User,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await this._repository.create(entity);
|
const user = await this.repository.create(entity);
|
||||||
this._messager.publish('user.create', JSON.stringify(user));
|
this.messager.publish('user.create', JSON.stringify(user));
|
||||||
this._messager.publish('logging.user.create.info', JSON.stringify(user));
|
this.messager.publish('logging.user.create.info', JSON.stringify(user));
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let key = 'logging.user.create.crit';
|
let key = 'logging.user.create.crit';
|
||||||
if (error.message.includes('Already exists')) {
|
if (error.message.includes('Already exists')) {
|
||||||
key = 'logging.user.create.warning';
|
key = 'logging.user.create.warning';
|
||||||
}
|
}
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
command,
|
command,
|
||||||
|
@ -41,5 +41,5 @@ export class CreateUserUseCase {
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,24 +7,21 @@ import { User } from '../entities/user';
|
||||||
@CommandHandler(DeleteUserCommand)
|
@CommandHandler(DeleteUserCommand)
|
||||||
export class DeleteUserUseCase {
|
export class DeleteUserUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _repository: UsersRepository,
|
private readonly repository: UsersRepository,
|
||||||
private readonly _messager: Messager,
|
private readonly messager: Messager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: DeleteUserCommand): Promise<User> {
|
execute = async (command: DeleteUserCommand): Promise<User> => {
|
||||||
try {
|
try {
|
||||||
const user = await this._repository.delete(command.uuid);
|
const user = await this.repository.delete(command.uuid);
|
||||||
this._messager.publish(
|
this.messager.publish('user.delete', JSON.stringify({ uuid: user.uuid }));
|
||||||
'user.delete',
|
this.messager.publish(
|
||||||
JSON.stringify({ uuid: user.uuid }),
|
|
||||||
);
|
|
||||||
this._messager.publish(
|
|
||||||
'logging.user.delete.info',
|
'logging.user.delete.info',
|
||||||
JSON.stringify({ uuid: user.uuid }),
|
JSON.stringify({ uuid: user.uuid }),
|
||||||
);
|
);
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'logging.user.delete.crit',
|
'logging.user.delete.crit',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
command,
|
command,
|
||||||
|
@ -33,5 +30,5 @@ export class DeleteUserUseCase {
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
import { QueryHandler } from '@nestjs/cqrs';
|
import { QueryHandler } from '@nestjs/cqrs';
|
||||||
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
import { ICollection } from 'src/modules/database/interfaces/collection.interface';
|
||||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
|
import { UsersRepository } from '../../adapters/secondaries/users.repository';
|
||||||
import { FindAllUsersQuery } from '../../queries/find-all-users.query';
|
import { FindAllUsersQuery } from '../../queries/find-all-users.query';
|
||||||
import { User } from '../entities/user';
|
import { User } from '../entities/user';
|
||||||
|
|
||||||
@QueryHandler(FindAllUsersQuery)
|
@QueryHandler(FindAllUsersQuery)
|
||||||
export class FindAllUsersUseCase {
|
export class FindAllUsersUseCase {
|
||||||
constructor(private readonly _repository: UsersRepository) {}
|
constructor(private readonly repository: UsersRepository) {}
|
||||||
|
|
||||||
async execute(
|
execute = async (
|
||||||
findAllUsersQuery: FindAllUsersQuery,
|
findAllUsersQuery: FindAllUsersQuery,
|
||||||
): Promise<ICollection<User>> {
|
): Promise<ICollection<User>> =>
|
||||||
return this._repository.findAll(
|
this.repository.findAll(findAllUsersQuery.page, findAllUsersQuery.perPage);
|
||||||
findAllUsersQuery.page,
|
|
||||||
findAllUsersQuery.perPage,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,17 @@ import { User } from '../entities/user';
|
||||||
@QueryHandler(FindUserByUuidQuery)
|
@QueryHandler(FindUserByUuidQuery)
|
||||||
export class FindUserByUuidUseCase {
|
export class FindUserByUuidUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _repository: UsersRepository,
|
private readonly repository: UsersRepository,
|
||||||
private readonly _messager: Messager,
|
private readonly messager: Messager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(findUserByUuid: FindUserByUuidQuery): Promise<User> {
|
execute = async (findUserByUuid: FindUserByUuidQuery): Promise<User> => {
|
||||||
try {
|
try {
|
||||||
const user = await this._repository.findOneByUuid(findUserByUuid.uuid);
|
const user = await this.repository.findOneByUuid(findUserByUuid.uuid);
|
||||||
if (!user) throw new NotFoundException();
|
if (!user) throw new NotFoundException();
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'logging.user.read.warning',
|
'logging.user.read.warning',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
query: findUserByUuid,
|
query: findUserByUuid,
|
||||||
|
@ -27,5 +27,5 @@ export class FindUserByUuidUseCase {
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,34 +10,34 @@ import { User } from '../entities/user';
|
||||||
@CommandHandler(UpdateUserCommand)
|
@CommandHandler(UpdateUserCommand)
|
||||||
export class UpdateUserUseCase {
|
export class UpdateUserUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _repository: UsersRepository,
|
private readonly repository: UsersRepository,
|
||||||
private readonly _messager: Messager,
|
private readonly messager: Messager,
|
||||||
@InjectMapper() private readonly _mapper: Mapper,
|
@InjectMapper() private readonly mapper: Mapper,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: UpdateUserCommand): Promise<User> {
|
execute = async (command: UpdateUserCommand): Promise<User> => {
|
||||||
const entity = this._mapper.map(
|
const entity = this.mapper.map(
|
||||||
command.updateUserRequest,
|
command.updateUserRequest,
|
||||||
UpdateUserRequest,
|
UpdateUserRequest,
|
||||||
User,
|
User,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await this._repository.update(
|
const user = await this.repository.update(
|
||||||
command.updateUserRequest.uuid,
|
command.updateUserRequest.uuid,
|
||||||
entity,
|
entity,
|
||||||
);
|
);
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'user.update',
|
'user.update',
|
||||||
JSON.stringify(command.updateUserRequest),
|
JSON.stringify(command.updateUserRequest),
|
||||||
);
|
);
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'logging.user.update.info',
|
'logging.user.update.info',
|
||||||
JSON.stringify(command.updateUserRequest),
|
JSON.stringify(command.updateUserRequest),
|
||||||
);
|
);
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._messager.publish(
|
this.messager.publish(
|
||||||
'logging.user.update.crit',
|
'logging.user.update.crit',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
command,
|
command,
|
||||||
|
@ -46,5 +46,5 @@ export class UpdateUserUseCase {
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { TestingModule, Test } from '@nestjs/testing';
|
import { TestingModule, Test } from '@nestjs/testing';
|
||||||
import { DatabaseModule } from '../../../database/database.module';
|
import { DatabaseModule } from '../../../database/database.module';
|
||||||
import { PrismaService } from '../../../database/src/adapters/secondaries/prisma-service';
|
import { PrismaService } from '../../../database/adapters/secondaries/prisma-service';
|
||||||
import { DatabaseException } from '../../../database/src/exceptions/database.exception';
|
import { DatabaseException } from '../../../database/exceptions/database.exception';
|
||||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
|
import { UsersRepository } from '../../adapters/secondaries/users.repository';
|
||||||
import { User } from '../../domain/entities/user';
|
import { User } from '../../domain/entities/user';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue