working crud
This commit is contained in:
parent
4e1fb9a8d6
commit
368ce98174
|
@ -215,4 +215,25 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateWithFields(uuid: string, entity: Partial<T>): 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 PrismaClientKnownRequestError) {
|
||||||
|
throw new DatabaseException(
|
||||||
|
PrismaClientKnownRequestError.name,
|
||||||
|
e.code,
|
||||||
|
e.message,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new DatabaseException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,4 +32,24 @@ export class TerritoryRepository<T> extends PrismaRepository<T> {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateTerritory(uuid: string, territory: Territory): Promise<T> {
|
||||||
|
try {
|
||||||
|
const fields = {};
|
||||||
|
if (territory.name) fields['name'] = `'${territory.name}'`;
|
||||||
|
if (territory.shape)
|
||||||
|
fields[
|
||||||
|
'shape'
|
||||||
|
] = `ST_GeomFromGeoJSON('{"type":"MultiPolygon","coordinates":${territory.shape}}')`;
|
||||||
|
const affectedRowNumber = await this.updateWithFields(uuid, fields);
|
||||||
|
if (affectedRowNumber == 1) {
|
||||||
|
return this.findOne({
|
||||||
|
name: territory.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw new DatabaseException();
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,18 @@ const mockPrismaService = {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// 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 PrismaClientKnownRequestError('unknown request', {
|
||||||
|
code: 'code',
|
||||||
|
clientVersion: 'version',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
.mockImplementationOnce((fields: object) => {
|
.mockImplementationOnce((fields: object) => {
|
||||||
throw new Error('an unknown error');
|
throw new Error('an unknown error');
|
||||||
}),
|
}),
|
||||||
|
@ -454,7 +466,7 @@ describe('PrismaRepository', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createwithFields', () => {
|
describe('createWithFields', () => {
|
||||||
it('should create an entity', async () => {
|
it('should create an entity', async () => {
|
||||||
jest.spyOn(prisma, '$queryRawUnsafe');
|
jest.spyOn(prisma, '$queryRawUnsafe');
|
||||||
|
|
||||||
|
@ -483,4 +495,41 @@ describe('PrismaRepository', () => {
|
||||||
).rejects.toBeInstanceOf(DatabaseException);
|
).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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import { Mapper } from '@automapper/core';
|
import { Mapper } from '@automapper/core';
|
||||||
import { InjectMapper } from '@automapper/nestjs';
|
import { InjectMapper } from '@automapper/nestjs';
|
||||||
import {
|
import { Controller, UsePipes } from '@nestjs/common';
|
||||||
CacheInterceptor,
|
|
||||||
CacheKey,
|
|
||||||
Controller,
|
|
||||||
UseInterceptors,
|
|
||||||
UsePipes,
|
|
||||||
} 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 { Territory } from '../../domain/entities/territory';
|
import { Territory } from '../../domain/entities/territory';
|
||||||
|
@ -41,8 +35,6 @@ export class TerritoriesController {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@GrpcMethod('TerritoriesService', 'FindAllForPoint')
|
@GrpcMethod('TerritoriesService', 'FindAllForPoint')
|
||||||
@UseInterceptors(CacheInterceptor)
|
|
||||||
@CacheKey('TerritoriesServiceFindAllForPoint')
|
|
||||||
async findAllTerritoriesForPoint(
|
async findAllTerritoriesForPoint(
|
||||||
data: FindAllTerritoriesForPointRequest,
|
data: FindAllTerritoriesForPointRequest,
|
||||||
): Promise<ICollection<Territory>> {
|
): Promise<ICollection<Territory>> {
|
||||||
|
@ -58,8 +50,6 @@ export class TerritoriesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GrpcMethod('TerritoriesService', 'FindAll')
|
@GrpcMethod('TerritoriesService', 'FindAll')
|
||||||
@UseInterceptors(CacheInterceptor)
|
|
||||||
@CacheKey('TerritoriesServiceFindAll')
|
|
||||||
async findAll(
|
async findAll(
|
||||||
data: FindAllTerritoriesRequest,
|
data: FindAllTerritoriesRequest,
|
||||||
): Promise<ICollection<Territory>> {
|
): Promise<ICollection<Territory>> {
|
||||||
|
@ -75,8 +65,6 @@ export class TerritoriesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GrpcMethod('TerritoriesService', 'FindOneByUuid')
|
@GrpcMethod('TerritoriesService', 'FindOneByUuid')
|
||||||
@UseInterceptors(CacheInterceptor)
|
|
||||||
@CacheKey('TerritoriesServiceFindOneByUuid')
|
|
||||||
async findOneByUuid(
|
async findOneByUuid(
|
||||||
data: FindTerritoryByUuidRequest,
|
data: FindTerritoryByUuidRequest,
|
||||||
): Promise<TerritoryPresenter> {
|
): Promise<TerritoryPresenter> {
|
||||||
|
|
|
@ -6,8 +6,8 @@ service TerritoriesService {
|
||||||
rpc FindOneByUuid(TerritoryByUuid) returns (Territory);
|
rpc FindOneByUuid(TerritoryByUuid) returns (Territory);
|
||||||
rpc FindAll(TerritoryFilter) returns (Territories);
|
rpc FindAll(TerritoryFilter) returns (Territories);
|
||||||
rpc FindAllForPoint(Point) returns (Territories);
|
rpc FindAllForPoint(Point) returns (Territories);
|
||||||
rpc Create(Territory) returns (Territory);
|
rpc Create(TerritoryShape) returns (Territory);
|
||||||
rpc Update(Territory) returns (Territory);
|
rpc Update(TerritoryShape) returns (Territory);
|
||||||
rpc Delete(TerritoryByUuid) returns (Empty);
|
rpc Delete(TerritoryByUuid) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,17 @@ message TerritoryByUuid {
|
||||||
string uuid = 1;
|
string uuid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Territory {
|
message TerritoryShape {
|
||||||
string uuid = 1;
|
string uuid = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
string shape = 3;
|
string shape = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Territory {
|
||||||
|
string uuid = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message TerritoryFilter {
|
message TerritoryFilter {
|
||||||
optional int32 page = 1;
|
optional int32 page = 1;
|
||||||
optional int32 perPage = 2;
|
optional int32 perPage = 2;
|
||||||
|
|
|
@ -18,16 +18,14 @@ export class UpdateTerritoryUseCase {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: UpdateTerritoryCommand): Promise<Territory> {
|
async execute(command: UpdateTerritoryCommand): Promise<Territory> {
|
||||||
const entity = this._mapper.map(
|
try {
|
||||||
|
const territory = await this._repository.updateTerritory(
|
||||||
|
command.updateTerritoryRequest.uuid,
|
||||||
|
this._mapper.map(
|
||||||
command.updateTerritoryRequest,
|
command.updateTerritoryRequest,
|
||||||
UpdateTerritoryRequest,
|
UpdateTerritoryRequest,
|
||||||
Territory,
|
Territory,
|
||||||
);
|
),
|
||||||
|
|
||||||
try {
|
|
||||||
const territory = await this._repository.update(
|
|
||||||
command.updateTerritoryRequest.uuid,
|
|
||||||
entity,
|
|
||||||
);
|
);
|
||||||
this._territoryMessager.publish(
|
this._territoryMessager.publish(
|
||||||
'update',
|
'update',
|
||||||
|
|
|
@ -45,7 +45,7 @@ import { TerritoryProfile } from './mappers/territory.profile';
|
||||||
store: await redisStore({
|
store: await redisStore({
|
||||||
host: configService.get<string>('REDIS_HOST'),
|
host: configService.get<string>('REDIS_HOST'),
|
||||||
port: configService.get<number>('REDIS_PORT'),
|
port: configService.get<number>('REDIS_PORT'),
|
||||||
ttl: configService.get('CACHE_TTL'),
|
ttl: configService.get<number>('CACHE_TTL'),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
|
|
|
@ -23,7 +23,7 @@ const updateTerritoryCommand: UpdateTerritoryCommand =
|
||||||
new UpdateTerritoryCommand(updateTerritoryRequest);
|
new UpdateTerritoryCommand(updateTerritoryRequest);
|
||||||
|
|
||||||
const mockTerritoriesRepository = {
|
const mockTerritoriesRepository = {
|
||||||
update: jest
|
updateTerritory: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementationOnce((uuid: string, params: any) => {
|
.mockImplementationOnce((uuid: string, params: any) => {
|
||||||
originalTerritory.name = params.name;
|
originalTerritory.name = params.name;
|
||||||
|
|
Loading…
Reference in New Issue