geobase/src/modules/countries/countries.service.ts

117 lines
2.8 KiB
TypeScript

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ILike, Repository } from 'typeorm';
import { Country } from './countries.entity';
import { intOrNull } from 'src/utils/int-or-null';
const COUNTRIES_URL =
'https://download.geonames.org/export/dump/countryInfo.txt';
const ACCEPT_FIELDS = [
'iso',
'iso3',
'isoNumeric',
'fips',
'country',
'capital',
'area',
'population',
'continent',
'tld',
'currencyCode',
'currencyName',
'phone',
'postalCodeFormat',
'postalCodeRegex',
'languages',
'geonameid',
'neighbours',
'equivalentFipsCode',
];
@Injectable()
export class CountriesService {
constructor(
@InjectRepository(Country, 'geobase')
private countryRepository: Repository<Country>,
) {}
private mapAllowedQuery(select: string[]) {
return (Array.isArray(select) ? select : [select]).filter((field) =>
ACCEPT_FIELDS.includes(field),
) as unknown as (keyof Country)[];
}
async pullCountries() {
const countryList = await fetch(COUNTRIES_URL).then((x) => x.text());
const entries = countryList
.split('\n')
.filter((line) => line && !line.startsWith('#'))
.map((line) => line.replace('\r', '').split('\t'))
.map((entry) => {
const country = new Country();
Object.assign(country, {
iso: entry[0],
iso3: entry[1],
isoNumeric: entry[2],
fips: entry[3],
country: entry[4],
capital: entry[5],
area: parseFloat(entry[6] || '0'),
population: intOrNull(entry[7]),
continent: entry[8],
tld: entry[9],
currencyCode: entry[10],
currencyName: entry[11],
phone: entry[12],
postalCodeFormat: entry[13],
postalCodeRegex: entry[14],
languages: entry[15],
geonameid: intOrNull(entry[16]),
neighbours: entry[17],
equivalentFipsCode: entry[18],
});
return country;
});
await this.countryRepository.save(entries);
}
async getAll(fields = ACCEPT_FIELDS) {
const select = this.mapAllowedQuery(fields);
return this.countryRepository.find({
select,
});
}
async search(query?: string, fields = ACCEPT_FIELDS) {
const select = this.mapAllowedQuery(fields);
const filter = {};
if (query) {
filter['country'] = ILike(`%${query}%`);
}
return this.countryRepository.find({
where: filter,
select,
});
}
async getByISO(iso: string, fields = ACCEPT_FIELDS) {
const select = this.mapAllowedQuery(fields);
const find = await this.countryRepository.findOne({
where: {
[iso.length === 2 ? 'iso' : 'iso3']: iso,
},
select,
});
if (!find) {
throw new NotFoundException();
}
return find;
}
}