117 lines
2.8 KiB
TypeScript
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;
|
|
}
|
|
}
|