Skip to content

Commit

Permalink
run all SQLs for geoCoding in same transaction as other queries
Browse files Browse the repository at this point in the history
  • Loading branch information
asuramaru1 committed Feb 28, 2022
1 parent fb0c67f commit e15193e
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 75 deletions.
41 changes: 29 additions & 12 deletions api/src/modules/admin-regions/admin-region.repository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { EntityRepository, SelectQueryBuilder } from 'typeorm';
import {
EntityManager,
EntityRepository,
QueryRunner,
SelectQueryBuilder,
} from 'typeorm';
import { AdminRegion } from 'modules/admin-regions/admin-region.entity';
import { ExtendedTreeRepository } from 'utils/tree.repository';
import { CreateAdminRegionDto } from 'modules/admin-regions/dto/create.admin-region.dto';
Expand All @@ -13,12 +18,18 @@ export class AdminRegionRepository extends ExtendedTreeRepository<
> {
logger: Logger = new Logger(AdminRegionRepository.name);

async getAdminRegionAndGeoRegionIdByCoordinatesAndLevel(searchParams: {
lng: number;
lat: number;
level: number;
}): Promise<{ adminRegionId: string; geoRegionId: string }> {
const res: any = await this.query(
async getAdminRegionAndGeoRegionIdByCoordinatesAndLevel(
searchParams: {
lng: number;
lat: number;
level: number;
},
queryRunner?: QueryRunner,
): Promise<{ adminRegionId: string; geoRegionId: string }> {
const manager: EntityManager | this = queryRunner
? queryRunner.manager
: this;
const res: any = await manager.query(
`
SELECT a.id AS "adminRegionId", g.id AS "geoRegionId"
FROM admin_region a
Expand Down Expand Up @@ -55,11 +66,17 @@ export class AdminRegionRepository extends ExtendedTreeRepository<
// level 1 or 2, and depending on coordinates, level 0.
// Check how to properly perform this

async getClosestAdminRegionByCoordinates(coordinates: {
lng: number;
lat: number;
}): Promise<any> {
const res: any = await this.query(
async getClosestAdminRegionByCoordinates(
coordinates: {
lng: number;
lat: number;
},
queryRunner?: QueryRunner,
): Promise<any> {
const manager: EntityManager | this = queryRunner
? queryRunner.manager
: this;
const res: any = await manager.query(
`SELECT a.id AS "adminRegionId" , a."name", a."level" , g."name" , g.id AS "geoRegionId"
FROM admin_region a
RIGHT JOIN geo_region g on a."geoRegionId" = g.id
Expand Down
34 changes: 23 additions & 11 deletions api/src/modules/admin-regions/admin-regions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { UpdateAdminRegionDto } from 'modules/admin-regions/dto/update.admin-reg
import { FindTreesWithOptionsArgs } from 'utils/tree.repository';
import { SourcingLocationsService } from 'modules/sourcing-locations/sourcing-locations.service';
import { GetAdminRegionTreeWithOptionsDto } from 'modules/admin-regions/dto/get-admin-region-tree-with-options.dto';
import { QueryBuilder, QueryRunner } from 'typeorm';

@Injectable()
export class AdminRegionsService extends AppBaseService<
Expand Down Expand Up @@ -77,9 +78,12 @@ export class AdminRegionsService extends AppBaseService<
// TODO: proper typing after validating this works
async getAdminAndGeoRegionIdByCountryIsoAlpha2(
countryIsoAlpha2Code: string,
queryRunner?: QueryRunner,
): Promise<{ id: string; geoRegionId: string }> {
const adminAndGeoRegionId: any = await this.adminRegionRepository
.createQueryBuilder('ar')
const adminRegionQueryBuilder: QueryBuilder<AdminRegion> = queryRunner
? queryRunner.manager.createQueryBuilder(AdminRegion, 'ar')
: this.adminRegionRepository.createQueryBuilder('ar');
const adminAndGeoRegionId: any = await adminRegionQueryBuilder
.select('id')
.addSelect('"geoRegionId"')
.where('ar.isoA2 = :countryIsoAlpha2Code', {
Expand All @@ -106,22 +110,30 @@ export class AdminRegionsService extends AppBaseService<
return adminRegion;
}

async getAdminRegionIdByCoordinatesAndLevel(searchParams: {
lng: number;
lat: number;
level: number;
}): Promise<{ adminRegionId: string; geoRegionId: string }> {
async getAdminRegionIdByCoordinatesAndLevel(
searchParams: {
lng: number;
lat: number;
level: number;
},
queryRunner?: QueryRunner,
): Promise<{ adminRegionId: string; geoRegionId: string }> {
return this.adminRegionRepository.getAdminRegionAndGeoRegionIdByCoordinatesAndLevel(
searchParams,
queryRunner,
);
}

async getClosestAdminRegionByCoordinates(coordinates: {
lng: number;
lat: number;
}): Promise<any> {
async getClosestAdminRegionByCoordinates(
coordinates: {
lng: number;
lat: number;
},
queryRunner?: QueryRunner,
): Promise<any> {
return this.adminRegionRepository.getClosestAdminRegionByCoordinates(
coordinates,
queryRunner,
);
}

Expand Down
22 changes: 17 additions & 5 deletions api/src/modules/geo-coding/geo-coding.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CountryOfProductionService } from 'modules/geo-coding/geocoding-strateg
import { UnknownLocationService } from 'modules/geo-coding/geocoding-strategies/unknown-location.geocoding.service';
import { SourcingData } from 'modules/import-data/sourcing-data/dto-processor.service';
import { LOCATION_TYPES } from 'modules/sourcing-locations/sourcing-location.entity';
import { QueryRunner } from 'typeorm';

@Injectable()
export class GeoCodingService {
Expand All @@ -19,6 +20,7 @@ export class GeoCodingService {

async geoCodeLocations(
sourcingData: SourcingData[],
queryRunner?: QueryRunner,
): Promise<SourcingData[]> {
this.logger.log(
`Geocoding locations for ${sourcingData.length} sourcing record elements`,
Expand All @@ -28,25 +30,25 @@ export class GeoCodingService {
sourcingData.map(async (sourcingData: SourcingData) => {
if (sourcingData.locationType === LOCATION_TYPES.UNKNOWN) {
geoCodedSourcingData.push(
await this.geoCodeUnknownLocationType(sourcingData),
await this.geoCodeUnknownLocationType(sourcingData, queryRunner),
);
}
if (
sourcingData.locationType === LOCATION_TYPES.COUNTRY_OF_PRODUCTION
) {
geoCodedSourcingData.push(
await this.geoCodeCountryOfProduction(sourcingData),
await this.geoCodeCountryOfProduction(sourcingData, queryRunner),
);
}

if (sourcingData.locationType === LOCATION_TYPES.AGGREGATION_POINT) {
geoCodedSourcingData.push(
await this.geoCodeAggregationPoint(sourcingData),
await this.geoCodeAggregationPoint(sourcingData, queryRunner),
);
}
if (sourcingData.locationType === LOCATION_TYPES.POINT_OF_PRODUCTION) {
geoCodedSourcingData.push(
await this.geoCodePointOfProduction(sourcingData),
await this.geoCodePointOfProduction(sourcingData, queryRunner),
);
}
}),
Expand All @@ -56,31 +58,41 @@ export class GeoCodingService {

async geoCodeAggregationPoint(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<SourcingData> {
return this.aggregationPointGeocodingService.geoCodeAggregationPoint(
sourcingData,
queryRunner,
);
}

async geoCodePointOfProduction(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<SourcingData> {
return this.pointOfProductionGeocodingService.geoCodePointOfProduction(
sourcingData,
queryRunner,
);
}

async geoCodeCountryOfProduction(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<SourcingData> {
return this.countryOfProductionService.geoCodeCountryOfProduction(
sourcingData,
queryRunner,
);
}

async geoCodeUnknownLocationType(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<SourcingData> {
return this.unknownLocationService.geoCodeUnknownLocationType(sourcingData);
return this.unknownLocationService.geoCodeUnknownLocationType(
sourcingData,
queryRunner,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { GeoCodingBaseService } from 'modules/geo-coding/geo-coding.base.service
import { SourcingData } from 'modules/import-data/sourcing-data/dto-processor.service';
import { GeocodeResponseData } from '@googlemaps/google-maps-services-js/dist/geocode/geocode';
import { GeoRegion } from 'modules/geo-regions/geo-region.entity';
import { QueryRunner } from 'typeorm';

@Injectable()
export class AggregationPointGeocodingService extends GeoCodingBaseService {
aggregationPointGeocodingLogger: Logger = new Logger(
AggregationPointGeocodingService.name,
);
async geoCodeAggregationPoint(sourcingData: SourcingData): Promise<any> {
async geoCodeAggregationPoint(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<any> {
/**
* The user must specify a country, and either an address OR coordinates
*/
Expand All @@ -23,22 +27,28 @@ export class AggregationPointGeocodingService extends GeoCodingBaseService {
*/
if (sourcingData.locationLatitude && sourcingData.locationLongitude) {
const geoRegionId: Pick<GeoRegion, 'id'> =
await this.geoRegionService.saveGeoRegionAsRadius({
name: sourcingData.locationCountryInput,
coordinates: {
lng: sourcingData.locationLongitude,
lat: sourcingData.locationLatitude,
await this.geoRegionService.saveGeoRegionAsRadius(
{
name: sourcingData.locationCountryInput,
coordinates: {
lng: sourcingData.locationLongitude,
lat: sourcingData.locationLatitude,
},
},
});
queryRunner,
);

/**
* Get closest AdminRegion given the same point
*/
const { adminRegionId } =
await this.adminRegionService.getClosestAdminRegionByCoordinates({
lng: sourcingData.locationLongitude,
lat: sourcingData.locationLatitude,
});
await this.adminRegionService.getClosestAdminRegionByCoordinates(
{
lng: sourcingData.locationLongitude,
lat: sourcingData.locationLatitude,
},
queryRunner,
);

return {
...sourcingData,
Expand All @@ -65,11 +75,14 @@ export class AggregationPointGeocodingService extends GeoCodingBaseService {
*/
if (this.isAddressAdminLevel1(geocodedResponseData.results[0].types)) {
const { adminRegionId, geoRegionId } =
await this.adminRegionService.getAdminRegionIdByCoordinatesAndLevel({
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
level: 1,
});
await this.adminRegionService.getAdminRegionIdByCoordinatesAndLevel(
{
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
level: 1,
},
queryRunner,
);
return {
...sourcingData,
adminRegionId,
Expand All @@ -78,11 +91,14 @@ export class AggregationPointGeocodingService extends GeoCodingBaseService {
}
if (this.isAddressAdminLevel2(geocodedResponseData.results[0].types)) {
const { adminRegionId, geoRegionId } =
await this.adminRegionService.getAdminRegionIdByCoordinatesAndLevel({
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
level: 2,
});
await this.adminRegionService.getAdminRegionIdByCoordinatesAndLevel(
{
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
level: 2,
},
queryRunner,
);
return {
...sourcingData,
adminRegionId,
Expand All @@ -95,21 +111,27 @@ export class AggregationPointGeocodingService extends GeoCodingBaseService {
* by it's name
*/
const geoRegionId: GeoRegion =
await this.geoRegionService.saveGeoRegionAsRadius({
name: sourcingData.locationCountryInput,
coordinates: {
lat: geocodedResponseData.results[0].geometry.location.lat,
lng: geocodedResponseData.results[0].geometry.location.lng,
await this.geoRegionService.saveGeoRegionAsRadius(
{
name: sourcingData.locationCountryInput,
coordinates: {
lat: geocodedResponseData.results[0].geometry.location.lat,
lng: geocodedResponseData.results[0].geometry.location.lng,
},
},
});
queryRunner,
);
/**
* Get closest AdminRegion given the same point
*/
const { adminRegionId } =
await this.adminRegionService.getClosestAdminRegionByCoordinates({
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
});
await this.adminRegionService.getClosestAdminRegionByCoordinates(
{
lng: geocodedResponseData?.results[0]?.geometry.location.lng,
lat: geocodedResponseData?.results[0]?.geometry.location.lat,
},
queryRunner,
);

return {
...sourcingData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { GeoCodingBaseService } from 'modules/geo-coding/geo-coding.base.service
import { SourcingData } from 'modules/import-data/sourcing-data/dto-processor.service';
import { SourcingLocation } from 'modules/sourcing-locations/sourcing-location.entity';
import { GeocodeResponseData } from '@googlemaps/google-maps-services-js/dist/geocode/geocode';
import { QueryRunner } from 'typeorm';

@Injectable()
export class CountryOfProductionService extends GeoCodingBaseService {
async geoCodeCountryOfProduction(
sourcingData: SourcingData,
queryRunner?: QueryRunner,
): Promise<SourcingLocation> {
/**
* The user must specify a country, and either address OR coordinates.
Expand All @@ -31,6 +33,7 @@ export class CountryOfProductionService extends GeoCodingBaseService {
const { id: adminRegionId, geoRegionId } =
await this.adminRegionService.getAdminAndGeoRegionIdByCountryIsoAlpha2(
geoCodedResponse.results[0]?.address_components?.[0]?.short_name,
queryRunner,
);
return {
...sourcingData,
Expand Down
Loading

0 comments on commit e15193e

Please sign in to comment.