import { HttpService, Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { Observable } from 'rxjs'; import { AxiosResponse } from 'axios'; import { CreateStructureDto } from './dto/create-structure.dto'; import { Structure, StructureDocument } from './schemas/structure.schema'; import { Logger } from '@nestjs/common'; @Injectable() export class StructuresService { constructor( private readonly httpService: HttpService, @InjectModel(Structure.name) private structureModel: Model<StructureDocument> ) {} public async create(createStructrureDto: CreateStructureDto): Promise<Structure> { const createdStructure = new this.structureModel(createStructrureDto); return createdStructure.save(); } public async search(searchString: string, filters?: Array<any>): Promise<Structure[]> { let query: any; if (searchString && filters) { query = [...this.parseFilter(filters), { $text: { $search: searchString } }]; } else if (filters) { query = this.parseFilter(filters); } else { query = [{ $text: { $search: searchString } }]; } return this.structureModel.find({ $or: query }).exec(); } /** * Parse filter value from string to boolean * @param filters */ private parseFilter(filters: Array<any>): Array<any> { return filters.map((filter) => { const key = Object.keys(filter)[0]; if (filter[key] === 'True') { return { [key]: true }; } else { return filter; } }); } public async findAll(): Promise<Structure[]> { const structures = await this.structureModel.find().exec(); // Update structures coord and address before sending them await Promise.all( structures.map((structure: Structure) => { // If structre has no address, add it if (!structure.address) { this.getStructurePosition(structure).then((postition) => { this.structureModel .findOneAndUpdate({ id: structure.id }, { address: postition.address, coord: postition.coord }) .exec(); }); } if (structure.coord.length <= 0) { this.getStructurePosition(structure).then((postition) => { this.structureModel.findOneAndUpdate({ id: postition.id }, { coord: postition.coord }).exec(); }); } }) ); return this.structureModel.find().exec(); } /** * Get structures positions and add marker corresponding to those positons on the map */ private getStructurePosition(structure: Structure): Promise<Structure> { return new Promise((resolve) => { this.getCoord(structure.n, structure.voie, structure.commune).subscribe( (res) => { const address = res.data.features[0]; structure.address = structure.voie + ' - ' + address.properties.postcode + ' ' + address.properties.city; structure.coord = address.geometry.coordinates; resolve(structure); }, (err) => { Logger.error(`[getCoord] Request error: ${err.config.url}`, err); } ); }); } /** * Count every value occurence of a given key * @param key structure key * @return [{id: 'key', count: 'value'}] */ public async countByStructureKey(key: string): Promise<any> { const uniqueElements = await this.structureModel.distinct(key).exec(); return await Promise.all( uniqueElements.map(async (value) => { return { id: value, count: await this.structureModel.countDocuments({ [key]: { $elemMatch: { $eq: value } } }).exec(), }; }) ); } public async countByEquipmentsKey(key: string, displayKey: string): Promise<any> { return [{ id: displayKey, count: await this.structureModel.countDocuments({ [key]: true }).exec() }]; } public getCoord(numero: string, address: string, zipcode: string): Observable<AxiosResponse<any>> { const req = 'https://download.data.grandlyon.com/geocoding/photon/api' + '?q=' + numero + ' ' + address + ' ' + zipcode; Logger.log(`[StructureService - getCoord] Request : ${req}`); return this.httpService.get(encodeURI(req)); } }