2023-04-06 09:12:49 +00:00
|
|
|
import { Injectable } from '@nestjs/common';
|
2023-04-12 15:09:31 +00:00
|
|
|
import { Prisma } from '@prisma/client';
|
2023-04-06 09:12:49 +00:00
|
|
|
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> {
|
2023-05-11 15:47:55 +00:00
|
|
|
protected model: string;
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
constructor(protected readonly prisma: PrismaService) {}
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
findAll = async (
|
2023-04-06 09:12:49 +00:00
|
|
|
page = 1,
|
|
|
|
perPage = 10,
|
|
|
|
where?: any,
|
|
|
|
include?: any,
|
2023-05-25 07:07:31 +00:00
|
|
|
): Promise<ICollection<T>> => {
|
|
|
|
const [data, total] = await this.prisma.$transaction([
|
|
|
|
this.prisma[this.model].findMany({
|
2023-04-06 09:12:49 +00:00
|
|
|
where,
|
|
|
|
include,
|
|
|
|
skip: (page - 1) * perPage,
|
|
|
|
take: perPage,
|
|
|
|
}),
|
2023-05-25 07:07:31 +00:00
|
|
|
this.prisma[this.model].count({
|
2023-04-06 09:12:49 +00:00
|
|
|
where,
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
return Promise.resolve({
|
|
|
|
data,
|
|
|
|
total,
|
|
|
|
});
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
findOneByUuid = async (uuid: string): Promise<T> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const entity = await this.prisma[this.model].findUnique({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: { uuid },
|
|
|
|
});
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
findOne = async (where: any, include?: any): Promise<T> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const entity = await this.prisma[this.model].findFirst({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: where,
|
|
|
|
include: include,
|
|
|
|
});
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
|
|
|
throw new DatabaseException(
|
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
|
|
|
e.code,
|
|
|
|
);
|
2023-04-06 09:12:49 +00:00
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
|
|
|
// 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 {
|
2023-05-25 07:07:31 +00:00
|
|
|
const res = await this.prisma[this.model].create({
|
2023-04-06 09:12:49 +00:00
|
|
|
data: entity,
|
|
|
|
include: include,
|
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
update = async (uuid: string, entity: Partial<T>): Promise<T> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const updatedEntity = await this.prisma[this.model].update({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: { uuid },
|
|
|
|
data: entity,
|
|
|
|
});
|
|
|
|
return updatedEntity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
updateWhere = async (
|
2023-04-06 09:12:49 +00:00
|
|
|
where: any,
|
|
|
|
entity: Partial<T> | any,
|
|
|
|
include?: any,
|
2023-05-25 07:07:31 +00:00
|
|
|
): Promise<T> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const updatedEntity = await this.prisma[this.model].update({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: where,
|
|
|
|
data: entity,
|
|
|
|
include: include,
|
|
|
|
});
|
|
|
|
|
|
|
|
return updatedEntity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
delete = async (uuid: string): Promise<T> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const entity = await this.prisma[this.model].delete({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: { uuid },
|
|
|
|
});
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
deleteMany = async (where: any): Promise<void> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
const entity = await this.prisma[this.model].deleteMany({
|
2023-04-06 09:12:49 +00:00
|
|
|
where: where,
|
|
|
|
});
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
findAllByQuery = async (
|
2023-04-26 12:14:46 +00:00
|
|
|
include: string[],
|
|
|
|
where: string[],
|
2023-05-25 07:07:31 +00:00
|
|
|
): Promise<ICollection<T>> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
const query = `SELECT ${include.join(',')} FROM ${
|
2023-05-11 15:47:55 +00:00
|
|
|
this.model
|
2023-04-06 09:12:49 +00:00
|
|
|
} WHERE ${where.join(' AND ')}`;
|
2023-05-25 07:07:31 +00:00
|
|
|
const data: T[] = await this.prisma.$queryRawUnsafe(query);
|
2023-04-06 09:12:49 +00:00
|
|
|
return Promise.resolve({
|
|
|
|
data,
|
|
|
|
total: data.length,
|
|
|
|
});
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
createWithFields = async (fields: object): Promise<number> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-11 15:47:55 +00:00
|
|
|
const command = `INSERT INTO ${this.model} ("${Object.keys(fields).join(
|
2023-04-25 15:49:47 +00:00
|
|
|
'","',
|
|
|
|
)}") VALUES (${Object.values(fields).join(',')})`;
|
2023-05-25 07:07:31 +00:00
|
|
|
return await this.prisma.$executeRawUnsafe(command);
|
2023-04-06 09:12:49 +00:00
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
updateWithFields = async (uuid: string, entity: object): Promise<number> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
entity['"updatedAt"'] = `to_timestamp(${Date.now()} / 1000.0)`;
|
|
|
|
const values = Object.keys(entity).map((key) => `${key} = ${entity[key]}`);
|
|
|
|
try {
|
2023-05-11 15:47:55 +00:00
|
|
|
const command = `UPDATE ${this.model} SET ${values.join(
|
2023-04-06 09:12:49 +00:00
|
|
|
', ',
|
|
|
|
)} WHERE uuid = '${uuid}'`;
|
2023-05-25 07:07:31 +00:00
|
|
|
return await this.prisma.$executeRawUnsafe(command);
|
2023-04-06 09:12:49 +00:00
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
|
2023-05-25 07:07:31 +00:00
|
|
|
healthCheck = async (): Promise<boolean> => {
|
2023-04-06 09:12:49 +00:00
|
|
|
try {
|
2023-05-25 07:07:31 +00:00
|
|
|
await this.prisma.$queryRaw`SELECT 1`;
|
2023-04-06 09:12:49 +00:00
|
|
|
return true;
|
|
|
|
} catch (e) {
|
2023-04-12 15:09:31 +00:00
|
|
|
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
2023-04-06 09:12:49 +00:00
|
|
|
throw new DatabaseException(
|
2023-04-12 15:09:31 +00:00
|
|
|
Prisma.PrismaClientKnownRequestError.name,
|
2023-04-06 09:12:49 +00:00
|
|
|
e.code,
|
|
|
|
e.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new DatabaseException();
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 07:07:31 +00:00
|
|
|
};
|
2023-04-06 09:12:49 +00:00
|
|
|
}
|