UNPKG

@publidata/utils-data-manager

Version:

Collection of methods to extract data from publidata

480 lines (421 loc) 14.3 kB
const axios = require("axios"); const { isEmpty } = require("lodash"); const haversine = require("haversine-distance"); const DataSourcePublidata = require("./../Publidata"); const { getId } = require("@publidata/utils-mapper"); const { facilityIconTranslation } = require("@publidata/utils-translation"); const { instanciatePublidataObject } = require("../../types"); const DATA_STORE_COLLECTIONS_MAX_CAPACITY = 100; const ALLOWED_FACILITY_TYPES = [ 71, 85, 86, 87, 88, 89, 91, 413, 458, 459, 496, 497, 559, 562, 566, 600, 726, 772, 777, 784, 785, 790, 799, 801, 802, 804, 808 ]; class DataSourcePipedrive { constructor(uid, instance) { this.instance = instance; this.endpoint = uid ? `${instance.custom_settings.url.utils}/api/v1/redis/${uid}` : `${instance.custom_settings.url.utils}/api/v1/redis/9d60b180-0151-11ea-b0d5-69d50c2027c3`; this.publidata = new DataSourcePublidata(instance); this.dataStore = { collections: { data: new Map(), maxCapacity: DATA_STORE_COLLECTIONS_MAX_CAPACITY } }; } verifyDataStoreCapacity(dataStoreType) { if (dataStoreType.data.length) { return dataStoreType.data.length < dataStoreType.maxCapacity; } return true; } removeFirstItemFromDataStore(dataStoreType) { const keysIterator = dataStoreType.data.keys(); const firstKey = keysIterator.next().value; dataStoreType.data.delete(firstKey); } saveDataInDataStore(uri, value) { const { collections } = this.dataStore; if (!this.verifyDataStoreCapacity(collections)) { this.removeFirstItemFromDataStore(collections); } collections.data.set(uri, value); } getDataFromDataStore(uri) { const { collections } = this.dataStore; const dataInCollections = collections.data.get(uri); if (dataInCollections) return dataInCollections; return null; } encodeTypes(types) { return types.toString().replace(",", ":"); } getObject(params) { const { types, size } = params; const encodedTypes = this.encodeTypes(types); const uri = `${this.endpoint}:${encodedTypes}${ size ? `?size=${size}` : "" }`; const storageUri = `${this.endpoint}:${encodedTypes}${ size ? `:${size}` : "" }`; const object = this.getDataFromDataStore(storageUri); if (object) return new Promise(resolve => { if (Array.isArray(object)) { resolve({ data: object }); } else resolve(object); }); return new Promise((resolve, reject) => { axios .get(uri) .then(response => { const { data } = response; const { value } = data; let returnValue; if (Array.isArray(value)) returnValue = value; else returnValue = [value]; this.saveDataInDataStore(storageUri, returnValue); resolve({ data: returnValue }); }) .catch(err => reject(err)); }); } getInstance() { const params = { types: ["instance"] }; return this.getObject(params); } getDocumentsByInstanceId(params) { return this.publidata.getDocumentsByInstanceId(params); } getDocumentsByIds(params) { const { instances } = params; return this.publidata.getDocumentsByIds({ instances }); } getProceduresByIds(params) { return this.publidata.getProceduresByIds(params); } getCities(params) { return this.publidata.getCities({ ...params, instances: [] }); } getSectors(params) { return this.publidata.getSectors(params); } getItems(params) { return this.publidata.getItems(params); } getAlerts(params = {}) { return this.publidata.getAlerts(params); } getAlert(params = {}) { return this.publidata.getAlert(params); } getFacilitiesAlerts(params) { return this.publidata.getFacilitiesAlerts(params); } getWasteCollectionAlerts(params) { return this.publidata.getWasteCollectionAlerts(params); } getNews(params) { return this.publidata.getNews(params); } getNewsTotalPages(params) { return this.publidata.getNewsTotalPages(params); } getData(params) { return this.publidata.getData(params); } //---------------------------------------------------- //-------------- GET: WASTE COLLECTIONS -------------- //---------------------------------------------------- getWasteCollections(params = {}) { const newParams = { ...params, types: ["waste_collections"], size: 100 }; if (!params.ids) return this.getObject(newParams); return new Promise(resolve => { this.getObject(newParams).then(({ data }) => { const { ids } = params; const normalizeId = id => parseInt(id, 10); const normalizedIds = ids.map(normalizeId); const filteredData = data.filter(wasteCollection => normalizedIds.includes(normalizeId(getId(wasteCollection))) ); resolve({ data: filteredData }); }); }); } getWasteCollection = this.getWasteCollections; getWasteCollectionById = this.getWasteCollections; //---------------------------------------------------- //----------------- GET : FACILITIES ----------------- //---------------------------------------------------- getWasteCollectionFacilities(params) { return new Promise((resolve, reject) => { const ids = params.services; this.getWasteCollectionById({ ids }) .then(wasteCollection => { const publidataWasteCollection = instanciatePublidataObject( wasteCollection.data[0], this.instance, this ); const [facility_types] = publidataWasteCollection.facilityTypes; // eslint-disable-line camelcase /* eslint-disable camelcase */ if (facility_types) { this.getFacilitiesByType({ facility_types, ...params }) .then(response => { resolve(response); }) .catch(err => reject(err)); } }) .catch(err => reject(err)); }); } getWasteCollectionFacility(params) { return new Promise((resolve, reject) => { const ids = params.services; this.getWasteCollectionById({ ids }) .then(wasteCollection => { const publidataWasteCollection = instanciatePublidataObject( wasteCollection.data[0], this.instance, this ); /* eslint-disable camelcase */ const [facility_types] = publidataWasteCollection.facilityTypes; if (facility_types) { this.getFacilityByType({ facility_types, ...params }) .then(response => { resolve(response); }) .catch(err => reject(err)); } else { resolve({ data: [] }); } }) .catch(err => reject(err)); }); } // ------------------------ // Facility types based getters // ------------------------ getRecyclingBins(garbageType) { const newParams = { types: ["recycling_bins", garbageType], size: 10000 }; return this.getObject(newParams); } getRecyclingCenters() { const newParams = { types: ["recycling_centers"], size: 1000 }; return this.getObject(newParams); } getMobiles(garbageType) { const types = garbageType ? ["mobiles", garbageType] : "mobiles"; const newParams = { types, size: 10000 }; return this.getObject(newParams); } getReuses(garbageType) { const types = garbageType ? ["reuses", garbageType] : "reuses"; const newParams = { types, size: 10000 }; return this.getObject(newParams); } /** * Get all the facilities of each facility_types * @param {object} params - { facility_types: [1,2,3]} */ getFacilities(params) { const facilityTypes = params.facility_types || ALLOWED_FACILITY_TYPES; const promises = facilityTypes.map(facilityType => this.getFacilitiesByType({ ...params, facility_types: facilityType }) ); const promise = Promise.all(promises) .then( results => new Promise(resolve => { let data = []; results.forEach(result => (data = [...data, ...result.data])); // Order by distance const { geo_point } = params; data = this.orderFacilitiesByDistance(data, geo_point); resolve({ data }); }) ) .catch(err => new Promise((resolve, reject) => reject(err))); return promise; } /** * Order facilities based on distance | Mutates the array * @param {array} facilities - Array of facilities * @param {*} geo_point - { lat: 0, lon: 0 } * @returns {array} - Ordered array of facilities */ orderFacilitiesByDistance(facilities = [], geo_point) { if (!facilities) throw new Error("No facilities provided"); if (!geo_point) return facilities; facilities.filter(Boolean).forEach(facility => { if (!facility?._source?.location) return; const { lat, lon } = facility?._source.location; facility._source.distance = haversine( { latitude: lat, longitude: lon }, { latitude: geo_point.lat, longitude: geo_point.lon } ); }); return facilities.sort((a, b) => a._source.distance - b._source.distance); } /** * Get a facility based on its id * @param {object} params * @returns {Promise} - Promise of the facility */ getFacilityById(params) { return new Promise((resolve, reject) => { this.getFacilities(params) .then(results => { const { ids } = params; const resultsFilteredById = results.data.filter(result => ids.find(id => `${id}` === `${getId(result)}`) ); resolve({ data: resultsFilteredById }); }) .catch(err => reject(err)); }); } /** * Helper function to determine which method to use to get the facilities * @param {object} params * @returns {Promise} - Promise of the facilities */ getFacilitiesByTypeMethod(params) { const facilityTypes = params.facility_types; let facilityType; if (Array.isArray(facilityTypes)) [facilityType] = facilityTypes; else facilityType = facilityTypes; if (facilityType === 71) return this.getRecyclingCenters(); if (facilityType === 91) return this.getMobiles(); if (facilityType === 778 || facilityType === 777) return this.getReuses(); const garbageType = facilityType === 562 ? "canin" : facilityIconTranslation(facilityType); const reuse = [89, 726, 776, 799, 801, 804]; if (reuse.includes(facilityType)) return this.getReuses(garbageType); if (facilityType === 566) return this.getMobiles(garbageType); return this.getRecyclingBins(garbageType); } /** * Get all the facilities of a facility_type, check this.getFacilitiesByTypeMethod for more info * @param {object} params * @returns {Promise} - Promise of the facilities */ getFacilitiesByType(params) { const method = this.getFacilitiesByTypeMethod(params); const { geo_point } = params; return method.then(({ data }) => { return new Promise(resolve => { const orderedData = this.orderFacilitiesByDistance(data, geo_point); resolve({ data: orderedData }); }); }); } /** * Get the one facility of a facility_type, check this.getFacilitiesByTypeMethod for more info * @param {object} params * @returns {Promise} - Promise of the facility */ getFacilityByType(_params) { const params = { ..._params }; // We first want to get all the facilities of the tye to order them by distance and get the closest one delete params.size; return this.getFacilitiesByType(params).then(({ data }) => { const [facility] = data; return { data: [facility] }; }); } /** * Get the one facility of a facility_type * @param {object} params * @returns {Promise} - Promise of the facility */ getFacilityByTypeAndId(params) { return new Promise((resolve, reject) => { const { ids } = params; this.getFacilitiesByType(params) .then(({ data }) => { if (!isEmpty(data)) { const facility = data.find(item => { const publidataFacility = instanciatePublidataObject( item, this.instance, this ); return publidataFacility.id === ids[0]; }); resolve({ data: [facility] }); } resolve({ data: [] }); }) .catch(err => reject(err)); }); } getServiceFacilityAggregations(params) { return new Promise((resolve, reject) => { let facilityType; const ids = params.services; this.getWasteCollectionById({ ids }) .then(({ data }) => { facilityType = data.reduce( (wasteCollectionAccumulator, wasteCollection) => { const publidataWasteCollection = instanciatePublidataObject( wasteCollection, this.instance, this ); return wasteCollectionAccumulator.concat( publidataWasteCollection.facilityTypes .filter(facilityTypeId => ALLOWED_FACILITY_TYPES.includes(facilityTypeId) ) .reduce( (publidataWasteCollectionAccumulator, facilityTypeId) => publidataWasteCollectionAccumulator.concat([ { key: facilityTypeId, doc_count: publidataWasteCollection._source.serviceables.length } ]), [] ) ); }, [] ); const total = facilityType.reduce( (acc, facilityType) => acc + facilityType.doc_count, 0 ); resolve({ data: [], facilityType, total }); }) .catch(err => reject(err)); }); } } module.exports = DataSourcePipedrive;