Skip to content

Commit

Permalink
refactor(projects): move additional request info to single dto
Browse files Browse the repository at this point in the history
  • Loading branch information
kgajowy committed Oct 13, 2021
1 parent f385737 commit 5e961d8
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { GeoFeatureSetSpecification } from './dto/geo-feature-set-specification.
import { GeoFeature } from './geo-feature.api.entity';
import { GeoFeaturePropertySet } from './geo-feature.geo.entity';
import { DbConnections } from '@marxan-api/ormconfig.connections';
import { BBox } from 'geojson';

@Injectable()
export class GeoFeaturePropertySetService {
Expand All @@ -23,24 +24,24 @@ export class GeoFeaturePropertySetService {

getFeaturePropertySetsForFeatures(
geoFeatureIds: string[],
forProject?: Project | null | undefined,
withinBBox?: BBox | null,
): Promise<GeoFeaturePropertySet[]> {
const query = this.geoFeaturePropertySetsRepository
.createQueryBuilder('propertySets')
.distinct(true)
.where(`propertySets.featureId IN (:...ids)`, { ids: geoFeatureIds });

if (forProject) {
if (withinBBox) {
query.andWhere(
`st_intersects(
st_makeenvelope(:xmin, :ymin, :xmax, :ymax, 4326),
"propertySets".bbox
)`,
{
xmin: forProject.bbox[1],
ymin: forProject.bbox[3],
xmax: forProject.bbox[0],
ymax: forProject.bbox[2],
xmin: withinBBox[1],
ymin: withinBBox[3],
xmax: withinBBox[0],
ymax: withinBBox[2],
},
);
}
Expand Down Expand Up @@ -111,7 +112,7 @@ export class GeoFeaturePropertySetService {
Logger.debug(inspect(featuresInSpecification));
const metadataForFeaturesInSpecification = await this.getFeaturePropertySetsForFeatures(
idsOfFeaturesInSpecification,
project,
project?.bbox,
);
const featuresInSpecificationWithPropertiesMetadata = this.extendGeoFeaturesWithPropertiesFromPropertySets(
featuresInSpecification,
Expand Down
11 changes: 11 additions & 0 deletions api/apps/api/src/modules/geo-features/geo-features-request-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { AppInfoDTO } from '@marxan-api/dto/info.dto';
import { BBox } from 'geojson';

export interface GeoFeaturesRequestInfo extends AppInfoDTO {
params?: {
featureClassAndAliasFilter?: string;
projectId?: string;
bbox?: BBox;
ids?: string[];
};
}
15 changes: 6 additions & 9 deletions api/apps/api/src/modules/geo-features/geo-features.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { DbConnections } from '@marxan-api/ormconfig.connections';
import { GeometrySource } from './geometry-source.enum';
import { v4 } from 'uuid';
import { UploadShapefileDTO } from '../projects/dto/upload-shapefile.dto';
import { GeoFeaturesRequestInfo } from './geo-features-request-info';

const geoFeatureFilterKeyNames = [
'featureClassName',
Expand All @@ -45,16 +46,12 @@ type GeoFeatureFilterKeys = keyof Pick<
>;
type GeoFeatureFilters = Record<GeoFeatureFilterKeys, string[]>;

type ServiceRequestInfo = AppInfoDTO & {
forProject?: Project;
};

@Injectable()
export class GeoFeaturesService extends AppBaseService<
GeoFeature,
GeoFeatureSetSpecification,
GeoFeatureSetSpecification,
ServiceRequestInfo
GeoFeaturesRequestInfo
> {
constructor(
@InjectRepository(GeoFeatureGeometry, DbConnections.geoprocessingDB)
Expand Down Expand Up @@ -99,7 +96,7 @@ export class GeoFeaturesService extends AppBaseService<
setFilters(
query: SelectQueryBuilder<GeoFeature>,
filters: GeoFeatureFilters,
info?: ServiceRequestInfo,
info?: GeoFeaturesRequestInfo,
): SelectQueryBuilder<GeoFeature> {
this._processBaseFilters<GeoFeatureFilters>(
query,
Expand All @@ -115,7 +112,7 @@ export class GeoFeaturesService extends AppBaseService<
async extendFindAllQuery(
query: SelectQueryBuilder<GeoFeature>,
fetchSpecification: FetchSpecification,
info: ServiceRequestInfo,
info: GeoFeaturesRequestInfo,
): Promise<SelectQueryBuilder<GeoFeature>> {
/**
* We should either list only "public" features (i.e. they are not from a
Expand Down Expand Up @@ -210,7 +207,7 @@ export class GeoFeaturesService extends AppBaseService<
async extendFindAllResults(
entitiesAndCount: [any[], number],
fetchSpecification?: DeepReadonly<FetchSpecification>,
info?: ServiceRequestInfo,
info?: GeoFeaturesRequestInfo,
): Promise<[any[], number]> {
/**
* Short-circuit if there's no result to extend, or if the API client has
Expand Down Expand Up @@ -239,7 +236,7 @@ export class GeoFeaturesService extends AppBaseService<
);

const entitiesWithProperties = await this.geoFeaturesPropertySet
.getFeaturePropertySetsForFeatures(geoFeatureIds, info?.forProject)
.getFeaturePropertySetsForFeatures(geoFeatureIds, info?.params?.bbox)
.then((results) => {
return this.geoFeaturesPropertySet.extendGeoFeaturesWithPropertiesFromPropertySets(
entitiesAndCount[0],
Expand Down
2 changes: 2 additions & 0 deletions api/apps/api/src/modules/geo-features/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { FeaturesCalculated } from './processing';
export { GeoFeaturesService } from './geo-features.service';
export { GeoFeaturesRequestInfo } from './geo-features-request-info';
11 changes: 11 additions & 0 deletions api/apps/api/src/modules/projects/project-requests-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { AppInfoDTO } from '@marxan-api/dto/info.dto';
import { BBox } from 'geojson';

export interface ProjectsRequest extends AppInfoDTO {
params?: {
featureClassAndAliasFilter?: string;
projectId?: string;
bbox?: BBox;
nameSearch?: string;
} & AppInfoDTO['params'];
}
29 changes: 12 additions & 17 deletions api/apps/api/src/modules/projects/projects-crud.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import {
} from './planning-areas';
import { UsersProjectsApiEntity } from './control-level/users-projects.api.entity';
import { Roles } from '@marxan-api/modules/users/role.api.entity';
import { AppInfoDTO } from '@marxan-api/dto/info.dto';
import { DbConnections } from '@marxan-api/ormconfig.connections';
import { ProtectedArea } from '@marxan/protected-areas';

import { ProjectsRequest } from './project-requests-info';

const projectFilterKeyNames = [
'name',
'organizationId',
Expand All @@ -41,18 +42,12 @@ type ProjectFilterKeys = keyof Pick<
>;
type ProjectFilters = Record<ProjectFilterKeys, string[]>;

export type ProjectsInfoDTO = AppInfoDTO & {
params?: {
nameSearch?: string;
};
};

@Injectable()
export class ProjectsCrudService extends AppBaseService<
Project,
CreateProjectDTO,
UpdateProjectDTO,
ProjectsInfoDTO
ProjectsRequest
> {
constructor(
@InjectRepository(Project)
Expand Down Expand Up @@ -131,7 +126,7 @@ export class ProjectsCrudService extends AppBaseService<
setFilters(
query: SelectQueryBuilder<Project>,
filters: ProjectFilters,
_info?: ProjectsInfoDTO,
_info?: ProjectsRequest,
): SelectQueryBuilder<Project> {
this._processBaseFilters<ProjectFilters>(
query,
Expand All @@ -143,7 +138,7 @@ export class ProjectsCrudService extends AppBaseService<

async setDataCreate(
create: CreateProjectDTO,
info?: ProjectsInfoDTO,
info?: ProjectsRequest,
): Promise<Project> {
assertDefined(info?.authenticatedUser?.id);
/**
Expand Down Expand Up @@ -180,7 +175,7 @@ export class ProjectsCrudService extends AppBaseService<
async actionAfterCreate(
model: Project,
createModel: CreateProjectDTO,
_info?: ProjectsInfoDTO,
_info?: ProjectsRequest,
): Promise<void> {
if (
createModel.planningUnitAreakm2 &&
Expand Down Expand Up @@ -211,7 +206,7 @@ export class ProjectsCrudService extends AppBaseService<
async actionAfterUpdate(
model: Project,
createModel: UpdateProjectDTO,
_info?: ProjectsInfoDTO,
_info?: ProjectsRequest,
): Promise<void> {
/**
* @deprecated Workers and jobs should be move to the new functionality
Expand Down Expand Up @@ -243,7 +238,7 @@ export class ProjectsCrudService extends AppBaseService<
async setDataUpdate(
model: Project,
update: UpdateProjectDTO,
_?: ProjectsInfoDTO,
_?: ProjectsRequest,
): Promise<Project> {
const bbox = await this.planningAreasService.getPlanningAreaBBox({
...update,
Expand All @@ -262,7 +257,7 @@ export class ProjectsCrudService extends AppBaseService<
async extendGetByIdResult(
entity: Project,
_fetchSpecification?: FetchSpecification,
_info?: ProjectsInfoDTO,
_info?: ProjectsRequest,
): Promise<Project> {
const ids: MultiplePlanningAreaIds = entity;
const idAndName = await this.planningAreasService.getPlanningAreaIdAndName(
Expand All @@ -289,7 +284,7 @@ export class ProjectsCrudService extends AppBaseService<
extendGetByIdQuery(
query: SelectQueryBuilder<Project>,
fetchSpecification?: FetchSpecification,
info?: ProjectsInfoDTO,
info?: ProjectsRequest,
): SelectQueryBuilder<Project> {
const loggedUser = Boolean(info?.authenticatedUser);
query.leftJoin(
Expand All @@ -316,7 +311,7 @@ export class ProjectsCrudService extends AppBaseService<
async extendFindAllQuery(
query: SelectQueryBuilder<Project>,
fetchSpecification: FetchSpecification,
info?: ProjectsInfoDTO,
info?: ProjectsRequest,
): Promise<SelectQueryBuilder<Project>> {
const loggedUser = Boolean(info?.authenticatedUser);

Expand Down Expand Up @@ -382,7 +377,7 @@ export class ProjectsCrudService extends AppBaseService<
async extendFindAllResults(
entitiesAndCount: [Project[], number],
_fetchSpecification?: FetchSpecification,
_info?: ProjectsInfoDTO,
_info?: ProjectsRequest,
): Promise<[Project[], number]> {
const extendedEntities: Promise<Project>[] = entitiesAndCount[0].map(
(entity) => this.extendGetByIdResult(entity),
Expand Down
34 changes: 24 additions & 10 deletions api/apps/api/src/modules/projects/projects.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Injectable } from '@nestjs/common';
import { FetchSpecification } from 'nestjs-base-service';
import { AppInfoDTO } from '@marxan-api/dto/info.dto';

import { GeoFeaturesService } from '@marxan-api/modules/geo-features/geo-features.service';

import { ProjectsCrudService, ProjectsInfoDTO } from './projects-crud.service';
import { ProjectsCrudService } from './projects-crud.service';
import { JobStatusService } from './job-status';
import { ProtectedAreasFacade } from './protected-areas/protected-areas.facade';
import { Project } from './project.api.entity';
Expand All @@ -14,6 +13,8 @@ import { PlanningAreasService } from './planning-areas';
import { PlanningUnitGridService, ProjectId } from './planning-unit-grid';
import { assertDefined } from '@marxan/utils';

import { ProjectsRequest } from './project-requests-info';

export { validationFailed } from './planning-areas';

@Injectable()
Expand All @@ -29,24 +30,32 @@ export class ProjectsService {

async findAllGeoFeatures(
fetchSpec: FetchSpecification,
appInfo?: AppInfoDTO,
appInfo?: ProjectsRequest,
) {
const project = await this.assertProject(appInfo?.params?.projectId);
// /ACL slot/
return this.geoCrud.findAllPaginated(fetchSpec, appInfo);
return this.geoCrud.findAllPaginated(fetchSpec, {
...appInfo,
params: {
projectId: project.id,
bbox: project.bbox,
...appInfo,
},
});
}

async findAll(fetchSpec: FetchSpecification, info?: ProjectsInfoDTO) {
async findAll(fetchSpec: FetchSpecification, info?: ProjectsRequest) {
return this.projectsCrud.findAllPaginated(fetchSpec, info);
}

async findAllPublic(fetchSpec: FetchSpecification, info?: ProjectsInfoDTO) {
async findAllPublic(fetchSpec: FetchSpecification, info?: ProjectsRequest) {
// /ACL slot/
return this.projectsCrud.findAllPaginated(fetchSpec, info);
}

async findOne(
id: string,
info?: ProjectsInfoDTO,
info?: ProjectsRequest,
): Promise<Project | undefined> {
// /ACL slot/
try {
Expand All @@ -58,7 +67,7 @@ export class ProjectsService {
}

// TODO debt: shouldn't use API's DTO - avoid relating service to given access layer (Rest)
async create(input: CreateProjectDTO, info: AppInfoDTO) {
async create(input: CreateProjectDTO, info: ProjectsRequest) {
assertDefined(info.authenticatedUser);
const project = await this.projectsCrud.create(input, info);
await this.projectsCrud.assignCreatorRole(
Expand All @@ -81,7 +90,7 @@ export class ProjectsService {
async addShapeFor(
projectId: string,
file: Express.Multer.File,
info: ProjectsInfoDTO,
info: ProjectsRequest,
): Promise<Error | undefined> /** Debt: move to Either<ErrorSymbol,Ok> */ {
// /ACL slot - can?/
try {
Expand All @@ -99,7 +108,7 @@ export class ProjectsService {
return this.gridService.setPlanningUnitGrid(new ProjectId(projectId), file);
}

async getJobStatusFor(projectId: string, info: ProjectsInfoDTO) {
async getJobStatusFor(projectId: string, info: ProjectsRequest) {
await this.projectsCrud.getById(projectId, undefined, info);
return await this.jobStatusService.getJobStatusFor(projectId);
}
Expand All @@ -111,4 +120,9 @@ export class ProjectsService {
savePlanningAreaFromShapefile = this.planningAreaService.savePlanningAreaFromShapefile.bind(
this.planningAreaService,
);

private async assertProject(projectId = '') {
/** App Base Service throws 404 */
return await this.projectsCrud.getById(projectId);
}
}

0 comments on commit 5e961d8

Please sign in to comment.