Merge branch 'findForPoints' into 'main'

add findForPoints

See merge request v3/services/territory!4
This commit is contained in:
Sylvain Briat 2023-02-09 14:08:51 +00:00
commit 32805e8a49
9 changed files with 159 additions and 0 deletions

View File

@ -15,6 +15,18 @@ export class TerritoryRepository<T> extends PrismaRepository<T> {
); );
} }
async findForPoints(points: Point[]): Promise<ICollection<T>> {
const multipoint = points
.map((point) => '(' + point.lon + ' ' + point.lat + ')')
.join(', ');
return await this.findAllByQuery(
['uuid', 'name'],
[
`ST_Intersects(ST_GeomFromText('MULTIPOINT(${multipoint})',4326),shape) = true`,
],
);
}
async createTerritory(territory: Partial<Territory>): Promise<T> { async createTerritory(territory: Partial<Territory>): Promise<T> {
try { try {
const affectedRowNumber = await this.createWithFields({ const affectedRowNumber = await this.createWithFields({

View File

@ -86,6 +86,19 @@ describe('TerritoryRepository', () => {
}); });
}); });
describe('findForPoints', () => {
it('should return an array of entities', async () => {
const entities = await repository.findForPoints([
new Point(6.1, 48.2),
new Point(6.2, 48.3),
]);
expect(entities).toStrictEqual({
data: mockTerritories,
total: mockTerritories.length,
});
});
});
describe('createTerritory', () => { describe('createTerritory', () => {
it('should create a new territory', async () => { it('should create a new territory', async () => {
const territory = await repository.createTerritory({ const territory = await repository.createTerritory({

View File

@ -19,6 +19,8 @@ import { DatabaseException } from 'src/modules/database/src/exceptions/database.
import { UpdateTerritoryRequest } from '../../domain/dtos/update-territory.request'; import { UpdateTerritoryRequest } from '../../domain/dtos/update-territory.request';
import { UpdateTerritoryCommand } from '../../commands/update-territory.command'; import { UpdateTerritoryCommand } from '../../commands/update-territory.command';
import { DeleteTerritoryCommand } from '../../commands/delete-territory.command'; import { DeleteTerritoryCommand } from '../../commands/delete-territory.command';
import { FindAllTerritoriesForPointsRequest } from '../../domain/dtos/find-all-territories-for-points.request';
import { FindAllTerritoriesForPointsQuery } from '../../queries/find-all-territories-for-points.query';
@UsePipes( @UsePipes(
new RpcValidationPipe({ new RpcValidationPipe({
@ -49,6 +51,21 @@ export class TerritoriesController {
}); });
} }
@GrpcMethod('TerritoriesService', 'FindAllForPoints')
async findAllTerritoriesForPoints(
data: FindAllTerritoriesForPointsRequest,
): Promise<ICollection<Territory>> {
const territoryCollection = await this._queryBus.execute(
new FindAllTerritoriesForPointsQuery(data),
);
return Promise.resolve({
data: territoryCollection.data.map((territory: Territory) =>
this._mapper.map(territory, Territory, TerritoryPresenter),
),
total: territoryCollection.total,
});
}
@GrpcMethod('TerritoriesService', 'FindAll') @GrpcMethod('TerritoriesService', 'FindAll')
async findAll( async findAll(
data: FindAllTerritoriesRequest, data: FindAllTerritoriesRequest,

View File

@ -6,6 +6,7 @@ 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 FindAllForPoints(Points) returns (Territories);
rpc Create(TerritoryShape) returns (Territory); rpc Create(TerritoryShape) returns (Territory);
rpc Update(TerritoryShape) returns (Territory); rpc Update(TerritoryShape) returns (Territory);
rpc Delete(TerritoryByUuid) returns (Empty); rpc Delete(TerritoryByUuid) returns (Empty);
@ -41,4 +42,8 @@ message Point {
float lat = 2; float lat = 2;
} }
message Points {
repeated Point points = 1;
}
message Empty {} message Empty {}

View File

@ -0,0 +1,9 @@
import { Type } from 'class-transformer';
import { IsArray } from 'class-validator';
import { Point } from '../entities/point';
export class FindAllTerritoriesForPointsRequest {
@IsArray()
@Type(() => Point)
points: Point[];
}

View File

@ -0,0 +1,18 @@
import { QueryHandler } from '@nestjs/cqrs';
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
import { TerritoriesRepository } from '../../adapters/secondaries/territories.repository';
import { FindAllTerritoriesForPointsQuery } from '../../queries/find-all-territories-for-points.query';
import { Territory } from '../entities/territory';
@QueryHandler(FindAllTerritoriesForPointsQuery)
export class FindAllTerritoriesForPointsUseCase {
constructor(private readonly _repository: TerritoriesRepository) {}
async execute(
findAllTerritoriesForPointsQuery: FindAllTerritoriesForPointsQuery,
): Promise<ICollection<Territory>> {
return this._repository.findForPoints(
findAllTerritoriesForPointsQuery.points,
);
}
}

View File

@ -0,0 +1,12 @@
import { FindAllTerritoriesForPointsRequest } from '../domain/dtos/find-all-territories-for-points.request';
import { Point } from '../domain/entities/point';
export class FindAllTerritoriesForPointsQuery {
points: Point[];
constructor(
findAllTerritoriesForPointsRequest?: FindAllTerritoriesForPointsRequest,
) {
this.points = findAllTerritoriesForPointsRequest.points;
}
}

View File

@ -12,6 +12,7 @@ import { TerritoryMessager } from './adapters/secondaries/territory.messager';
import { CreateTerritoryUseCase } from './domain/usecases/create-territory.usecase'; import { CreateTerritoryUseCase } from './domain/usecases/create-territory.usecase';
import { DeleteTerritoryUseCase } from './domain/usecases/delete-territory.usecase'; import { DeleteTerritoryUseCase } from './domain/usecases/delete-territory.usecase';
import { FindAllTerritoriesForPointUseCase } from './domain/usecases/find-all-territories-for-point.usecase'; import { FindAllTerritoriesForPointUseCase } from './domain/usecases/find-all-territories-for-point.usecase';
import { FindAllTerritoriesForPointsUseCase } from './domain/usecases/find-all-territories-for-points.usecase';
import { FindAllTerritoriesUseCase } from './domain/usecases/find-all-territories.usecase'; import { FindAllTerritoriesUseCase } from './domain/usecases/find-all-territories.usecase';
import { FindTerritoryByUuidUseCase } from './domain/usecases/find-territory-by-uuid.usecase'; import { FindTerritoryByUuidUseCase } from './domain/usecases/find-territory-by-uuid.usecase';
import { UpdateTerritoryUseCase } from './domain/usecases/update-territory.usecase'; import { UpdateTerritoryUseCase } from './domain/usecases/update-territory.usecase';
@ -58,6 +59,7 @@ import { TerritoryProfile } from './mappers/territory.profile';
TerritoryMessager, TerritoryMessager,
LoggingMessager, LoggingMessager,
FindAllTerritoriesForPointUseCase, FindAllTerritoriesForPointUseCase,
FindAllTerritoriesForPointsUseCase,
FindAllTerritoriesUseCase, FindAllTerritoriesUseCase,
FindTerritoryByUuidUseCase, FindTerritoryByUuidUseCase,
CreateTerritoryUseCase, CreateTerritoryUseCase,

View File

@ -0,0 +1,71 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TerritoriesRepository } from '../../adapters/secondaries/territories.repository';
import { FindAllTerritoriesForPointsRequest } from '../../domain/dtos/find-all-territories-for-points.request';
import { Point } from '../../domain/entities/point';
import { FindAllTerritoriesForPointsUseCase } from '../../domain/usecases/find-all-territories-for-points.usecase';
import { FindAllTerritoriesForPointsQuery } from '../../queries/find-all-territories-for-points.query';
const findAllTerritoriesForPointsRequest: FindAllTerritoriesForPointsRequest =
new FindAllTerritoriesForPointsRequest();
findAllTerritoriesForPointsRequest.points = [
new Point(6.181455, 48.685689),
new Point(6.191455, 48.695689),
];
const findforPointsQuery: FindAllTerritoriesForPointsQuery =
new FindAllTerritoriesForPointsQuery(findAllTerritoriesForPointsRequest);
const mockTerritories = [
{
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
name: 'Nancy',
},
{
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
name: 'Meurthe-et-Moselle',
},
];
const mockTerritoriesRepository = {
findForPoints: jest
.fn()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.mockImplementation((query?: FindAllTerritoriesForPointsQuery) => {
return Promise.resolve(mockTerritories);
}),
};
describe('FindAllTerritoriesforPointsUseCase', () => {
let findAllTerritoriesForPointsUseCase: FindAllTerritoriesForPointsUseCase;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: TerritoriesRepository,
useValue: mockTerritoriesRepository,
},
FindAllTerritoriesForPointsUseCase,
],
}).compile();
findAllTerritoriesForPointsUseCase =
module.get<FindAllTerritoriesForPointsUseCase>(
FindAllTerritoriesForPointsUseCase,
);
});
it('should be defined', () => {
expect(findAllTerritoriesForPointsUseCase).toBeDefined();
});
describe('execute', () => {
it('should return an array filled with territories', async () => {
const territories = await findAllTerritoriesForPointsUseCase.execute(
findforPointsQuery,
);
expect(territories).toBe(mockTerritories);
});
});
});