Skip to content

Commit

Permalink
Fix pg json equality operator error, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeh committed Feb 28, 2024
1 parent b8c56d1 commit e5a0050
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 4 deletions.
3 changes: 2 additions & 1 deletion api/src/modules/geo-regions/geo-region.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ export class GeoRegionRepository extends Repository<GeoRegion> {
const initialQueryBuilder: SelectQueryBuilder<GeoRegion> =
this.createQueryBuilder('gr')
.innerJoin(SourcingLocation, 'sl', 'sl.geoRegionId = gr.id')
.distinct(true);
// Using groupBy instead of distinct to avoid the euality opertor for type json
.groupBy('gr.id');
const queryBuilder: SelectQueryBuilder<GeoRegion> =
BaseQueryBuilder.addFilters(initialQueryBuilder, getGeoRegionsDto);

Expand Down
6 changes: 5 additions & 1 deletion api/src/modules/geo-regions/geo-regions.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ export class GeoRegionsController {
dto: GetEUDRGeoRegions,
): Promise<GeoRegion[]> {
const results: GeoRegion[] =
await this.geoRegionsService.getGeoRegionsFromSourcingLocations(dto);
await this.geoRegionsService.getGeoRegionsFromSourcingLocations({
...dto,
withSourcingLocations: true,
eudr: true,
});
return this.geoRegionsService.serialize(results);
}

Expand Down
2 changes: 1 addition & 1 deletion api/src/modules/geo-regions/geo-regions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class GeoRegionsService extends AppBaseService<

get serializerConfig(): JSONAPISerializerConfig<GeoRegion> {
return {
attributes: ['name'],
attributes: ['name', 'theGeom'],
keyForAttribute: 'camelCase',
};
}
Expand Down
168 changes: 168 additions & 0 deletions api/test/common-steps/sourcing-locations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
LOCATION_TYPES,
SourcingLocation,
} from 'modules/sourcing-locations/sourcing-location.entity';
import {
createAdminRegion,
createBusinessUnit,
createIndicator,
createIndicatorRecord,
createMaterial,
createSourcingLocation,
createSourcingRecord,
createSupplier,
createUnit,
} from '../entity-mocks';
import {
Indicator,
INDICATOR_NAME_CODES,
} from '../../src/modules/indicators/indicator.entity';
import { SourcingRecord } from '../../src/modules/sourcing-records/sourcing-record.entity';
import { Material } from '../../src/modules/materials/material.entity';

type MockSourcingLocations = {
materials: Material[];
sourcingLocations: SourcingLocation[];
sourcingRecords: SourcingRecord[];
};

type MockSourcingLocationsWithIndicators = MockSourcingLocations & {
indicators: Indicator[];
};

export const CreateSourcingLocationsWithImpact =
async (): Promise<MockSourcingLocationsWithIndicators> => {
const parentMaterial = await createMaterial({
name: 'Parent Material',
});
const childMaterial = await createMaterial({
parentId: parentMaterial.id,
name: 'Child Material',
});
const supplier = await createSupplier();
const businessUnit = await createBusinessUnit();
const adminRegion = await createAdminRegion();
const sourcingLocationParentMaterial = await createSourcingLocation({
materialId: parentMaterial.id,
producerId: supplier.id,
businessUnitId: businessUnit.id,
adminRegionId: adminRegion.id,
});

const sourcingLocationChildMaterial = await createSourcingLocation({
materialId: childMaterial.id,
producerId: supplier.id,
businessUnitId: businessUnit.id,
adminRegionId: adminRegion.id,
});
const unit = await createUnit();
const indicators: Indicator[] = [];
for (const indicator of Object.values(INDICATOR_NAME_CODES)) {
indicators.push(
await createIndicator({
nameCode: indicator,
name: indicator,
unit,
shortName: indicator,
}),
);
}
const sourcingRecords: SourcingRecord[] = [];
for (const year of [2018, 2019, 2020, 2021, 2022, 2023]) {
sourcingRecords.push(
await createSourcingRecord({
sourcingLocationId: sourcingLocationParentMaterial.id,
year,
tonnage: 100 * year,
}),
);
sourcingRecords.push(
await createSourcingRecord({
sourcingLocationId: sourcingLocationChildMaterial.id,
year,
tonnage: 100 * year,
}),
);
}
for (const sourcingRecord of sourcingRecords) {
for (const indicator of indicators) {
await createIndicatorRecord({
sourcingRecordId: sourcingRecord.id,
indicatorId: indicator.id,
value: sourcingRecord.tonnage * 2,
});
}
}
return {
materials: [parentMaterial, childMaterial],
indicators,
sourcingRecords,
sourcingLocations: [
sourcingLocationParentMaterial,
sourcingLocationChildMaterial,
],
};
};

export const CreateEUDRSourcingLocations =
async (): Promise<MockSourcingLocations> => {
const parentMaterial = await createMaterial({
name: 'EUDR Parent Material',
});
const childMaterial = await createMaterial({
parentId: parentMaterial.id,
name: 'EUDR Child Material',
});
const supplier = await createSupplier();
const businessUnit = await createBusinessUnit();
const adminRegion = await createAdminRegion();
const sourcingLocationParentMaterial = await createSourcingLocation({
materialId: parentMaterial.id,
producerId: supplier.id,
businessUnitId: businessUnit.id,
adminRegionId: adminRegion.id,
locationType: LOCATION_TYPES.EUDR,
});

const sourcingLocationChildMaterial = await createSourcingLocation({
materialId: childMaterial.id,
producerId: supplier.id,
businessUnitId: businessUnit.id,
adminRegionId: adminRegion.id,
locationType: LOCATION_TYPES.EUDR,
});
const unit = await createUnit();
for (const indicator of Object.values(INDICATOR_NAME_CODES)) {
await createIndicator({
nameCode: indicator,
name: indicator,
unit,
shortName: indicator,
});
}
const sourcingRecords: SourcingRecord[] = [];
for (const year of [2018, 2019, 2020, 2021, 2022, 2023]) {
sourcingRecords.push(
await createSourcingRecord({
sourcingLocationId: sourcingLocationParentMaterial.id,
year,
tonnage: 100 * year,
}),
);
sourcingRecords.push(
await createSourcingRecord({
sourcingLocationId: sourcingLocationChildMaterial.id,
year,
tonnage: 100 * year,
}),
);
}
return {
materials: [parentMaterial, childMaterial],
sourcingLocations: [
sourcingLocationParentMaterial,
sourcingLocationChildMaterial,
],
sourcingRecords,
};
};
63 changes: 63 additions & 0 deletions api/test/e2e/geo-regions/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { createGeoRegion, createSourcingLocation } from '../../entity-mocks';
import { TestApplication } from '../../utils/application-manager';
import * as request from 'supertest';
import { GeoRegion } from '../../../src/modules/geo-regions/geo-region.entity';
import { LOCATION_TYPES } from '../../../src/modules/sourcing-locations/sourcing-location.entity';

export const geoRegionFixtures = () => ({
GivenGeoRegionsOfSourcingLocations: async () => {
const geoRegion = await createGeoRegion({
name: 'Regular GeoRegion',
});
const geoRegion2 = await createGeoRegion({
name: 'Regular GeoRegion 2',
});
await createSourcingLocation({ geoRegionId: geoRegion.id });
await createSourcingLocation({ geoRegionId: geoRegion2.id });
return {
geoRegions: [geoRegion, geoRegion2],
};
},
GivenEUDRGeoRegions: async () => {
const geoRegion = await createGeoRegion({
name: 'EUDR GeoRegion',
});
const geoRegion2 = await createGeoRegion({
name: 'EUDR GeoRegion 2',
});
await createSourcingLocation({
geoRegionId: geoRegion.id,
locationType: LOCATION_TYPES.EUDR,
});
await createSourcingLocation({
geoRegionId: geoRegion2.id,
locationType: LOCATION_TYPES.EUDR,
});
return {
eudrGeoRegions: [geoRegion, geoRegion2],
};
},
WhenIRequestEUDRGeoRegions: async (options: {
app: TestApplication;
jwtToken: string;
}) => {
return request(options.app.getHttpServer())
.get(`/api/v1/geo-regions/eudr`)
.set('Authorization', `Bearer ${options.jwtToken}`);
},
ThenIShouldOnlyReceiveEUDRGeoRegions: (
response: request.Response,
eudrGeoRegions: GeoRegion[],
) => {
expect(response.status).toBe(200);
expect(response.body.data.length).toBe(eudrGeoRegions.length);
for (const geoRegion of eudrGeoRegions) {
expect(
response.body.data.find(
(geoRegionResponse: GeoRegion) =>
geoRegionResponse.id === geoRegion.id,
),
).toBeDefined();
}
},
});
42 changes: 42 additions & 0 deletions api/test/e2e/geo-regions/geo-regions-filters.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { DataSource } from 'typeorm';
import ApplicationManager from '../../utils/application-manager';
import { TestApplication } from '../../utils/application-manager';
import { clearTestDataFromDatabase } from '../../utils/database-test-helper';
import { setupTestUser } from '../../utils/userAuth';

import { geoRegionFixtures } from './fixtures';

describe('GeoRegions Filters (e2e)', () => {
const fixtures = geoRegionFixtures();
let testApplication: TestApplication;
let jwtToken: string;
let dataSource: DataSource;

beforeAll(async () => {
testApplication = await ApplicationManager.init();

dataSource = testApplication.get<DataSource>(DataSource);
});
beforeEach(async () => {
({ jwtToken } = await setupTestUser(testApplication));
});

afterEach(async () => {
await clearTestDataFromDatabase(dataSource);
});

afterAll(async () => {
await testApplication.close();
});
describe('EUDR Geo Regions Filters', () => {
it('should only get geo-regions that are part of EUDR data', async () => {
await fixtures.GivenGeoRegionsOfSourcingLocations();
const { eudrGeoRegions } = await fixtures.GivenEUDRGeoRegions();
const response = await fixtures.WhenIRequestEUDRGeoRegions({
app: testApplication,
jwtToken,
});
fixtures.ThenIShouldOnlyReceiveEUDRGeoRegions(response, eudrGeoRegions);
});
});
});
2 changes: 1 addition & 1 deletion api/test/e2e/impact/impact-reports/impact-reports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Impact Reports', () => {
indicatorIds: indicators.map((indicator: Indicator) => indicator.id),
});

await fixtures.ThenIShouldGetAnImpactReportAboutProvidedFilters(response, {
fixtures.ThenIShouldGetAnImpactReportAboutProvidedFilters(response, {
materials,
});
});
Expand Down

0 comments on commit e5a0050

Please sign in to comment.