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> {
|
|
|
|
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) {
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async delete(uuid: string): Promise<T> {
|
|
|
|
try {
|
|
|
|
const entity = await this._prisma[this._model].delete({
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async deleteMany(where: any): Promise<void> {
|
|
|
|
try {
|
|
|
|
const entity = await this._prisma[this._model].deleteMany({
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async findAllByQuery(
|
2023-04-26 12:14:46 +00:00
|
|
|
include: string[],
|
|
|
|
where: string[],
|
2023-04-06 09:12:49 +00:00
|
|
|
): Promise<ICollection<T>> {
|
|
|
|
const query = `SELECT ${include.join(',')} FROM ${
|
|
|
|
this._model
|
|
|
|
} WHERE ${where.join(' AND ')}`;
|
2023-04-26 12:14:46 +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,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async createWithFields(fields: object): Promise<number> {
|
|
|
|
try {
|
2023-04-25 15:49:47 +00:00
|
|
|
const command = `INSERT INTO ${this._model} ("${Object.keys(fields).join(
|
|
|
|
'","',
|
|
|
|
)}") VALUES (${Object.values(fields).join(',')})`;
|
2023-04-06 09:12:49 +00:00
|
|
|
return await this._prisma.$executeRawUnsafe(command);
|
|
|
|
} 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-04-25 15:49:47 +00:00
|
|
|
async updateWithFields(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 {
|
|
|
|
const command = `UPDATE ${this._model} SET ${values.join(
|
|
|
|
', ',
|
|
|
|
)} WHERE uuid = '${uuid}'`;
|
|
|
|
return await this._prisma.$executeRawUnsafe(command);
|
|
|
|
} 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async healthCheck(): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
await this._prisma.$queryRaw`SELECT 1`;
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|