split utils, separate IRVE guess

This commit is contained in:
Tykayn 2025-04-11 15:53:23 +02:00 committed by tykayn
parent b4c28335b2
commit a732edc228
12 changed files with 460 additions and 363 deletions

View file

@ -19,7 +19,7 @@ const MappingIRVE: MappingConfigType = {
* select only certain points from the source
*/
filters: {
// offset: 1, // limiter à une feature pour faire des tests
// offset: 10, // limiter à une feature pour faire des tests
enable_coordinates_filter: false,
enable_properties_filter: true,
// filter_points_older_than_year: 2024,
@ -110,21 +110,25 @@ const MappingIRVE: MappingConfigType = {
key_converted: 'socket:typee',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
},
prise_type_2: {
key_converted: 'socket:type2',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
},
prise_type_combo_ccs: {
key_converted: 'socket:type2_combo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
},
prise_type_chademo: {
key_converted: 'socket:chademo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
keep_only_max_in_enum: true,
},
// ******** champs plus complexes
horaires: 'opening_hours', // déjà au bon format, enfin, en général. vérifier avec le validateur josm.

View file

@ -1,6 +1,10 @@
/**
* commerces adhérant à Ask Angela
* https://wiki.openstreetmap.org/wiki/Tag:healthcare:speciality%3Dfamily_planning
* détails en Français https://wiki.openstreetmap.org/wiki/FR:Tag:healthcare:speciality%3Dfamily_planning
*
* Site officiel:
* https://www.planning-familial.org/fr
*/
import MappingConfigType from "../mapping-config.type";
@ -14,7 +18,7 @@ const MappingPlanningFamlial: MappingConfigType = {
// source faite à partir de data scraping du site français
geojson_path: '',
url: 'https://www.planning-familial.org/fr',
overpass_query:`
overpass_query: `
[out:json][timeout:200];
{{geocodeArea:"France"}}->.searchArea;
nwr["healthcare:speciality"="family_planning"](area.searchArea);
@ -29,20 +33,20 @@ const MappingPlanningFamlial: MappingConfigType = {
tags_to_ignore_if_value_is: ['Non renseigne'],
tags: {
adresse: "addr:full",
nom : {
nom: {
key_converted: 'name',
convert_to_name: true,
},
telephone : {
telephone: {
key_converted: 'contact:phone',
convert_to_phone: true,
},
"contact:website":"contact:website",
"family_planning:handles:violences" : "family_planning:handles:violences",
"family_planning:handles:sexualities" : "family_planning:handles:sexualities",
"family_planning:handles:detection" : "family_planning:handles:detection",
"family_planning:handles:abortion" : "family_planning:handles:abortion",
"family_planning:handles:contraception" : "family_planning:handles:contraception",
"contact:website": "contact:website",
"family_planning:handles:violences": "family_planning:handles:violences",
"family_planning:handles:sexualities": "family_planning:handles:sexualities",
"family_planning:handles:detection": "family_planning:handles:detection",
"family_planning:handles:abortion": "family_planning:handles:abortion",
"family_planning:handles:contraception": "family_planning:handles:contraception",
// ******* opendata de toulouse END **************
}
}

View file

@ -1,34 +1,25 @@
import custom_utils from './utils'
import MappingConfigType from "./mapping-config.type";
import Formatters from "./formatters";
import config from "../config";
import custom_utils from "./utils";
import { detectSocketOutputFromFeaturePoint } from "./irve.utils";
const { debugLog, find_max_in_string, truncate_enums_to_limit } = custom_utils
let listOfBooleanKeys = [
"prise_type_ef",
"prise_type_2",
"prise_type_combo_ccs",
"prise_type_chademo",
"gratuit",
"paiement_acte",
"paiement_cb",
"cable_t2_attache"
]
function boolToAddable(someBooleanValue: boolean) {
return someBooleanValue ? 1 : 0
}
export default class {
/**
* Class that helps to convert values into predefined formats
*/
export default class MappingEngine {
mapping_config: any = {}
public stats: any;
truthyValues = [true, 'true', 'True', 'TRUE', '1', 'yes', 1]
falsyValues = [false, 'false', 'False', 'FALSE', '0', 'no', 0]
private jardinage = false;
private current_converted_geojson_point: any;
private current_geojson_point: any; // currently converting point
private list_of_points: any; // list of geojson points
constructor(mappingConfig: MappingConfigType) {
@ -55,12 +46,9 @@ export default class {
mapFeaturePoint(featurePointGeoJson: any) {
let geoJSONConvertedPoint: any = {}
geoJSONConvertedPoint.properties = { ...this.mapping_config.default_properties_of_point }
geoJSONConvertedPoint.type = featurePointGeoJson.type
geoJSONConvertedPoint.geometry = featurePointGeoJson.geometry
this.current_converted_geojson_point = geoJSONConvertedPoint
return geoJSONConvertedPoint
@ -73,7 +61,7 @@ export default class {
*/
isBooleanKey(pointKeyName: string): boolean {
return listOfBooleanKeys.indexOf(pointKeyName) !== -1
return config.listOfBooleanKeys.indexOf(pointKeyName) !== -1
}
/**
@ -205,7 +193,9 @@ export default class {
debugLog('mapElementFromConf: convert', pointKeyName)
debugLog('mapElementFromConf: mapping keys:', mappingKeys)
this.convertProperty(pointKeyName, mappingKeys, featurePoint, newProperties)
this.convertProperty({
pointKeyName, mappingKeys, featurePoint, newProperties
})
})
@ -217,13 +207,20 @@ export default class {
}
/**
* convertit une propriété en une autre selon la config de mapping
* convertit une propriété en une autre selon la config de mapping chargée
* @param pointKeyName
* @param mappingKeys
* @param featurePoint
* @param newProperties
*/
convertProperty(pointKeyName: string, mappingKeys: any, featurePoint: any, newProperties: any) {
convertProperty(options: {
pointKeyName: string,
mappingKeys: any,
featurePoint: any,
newProperties: any
}) {
const { pointKeyName, mappingKeys, featurePoint, newProperties } = options
this.current_geojson_point = featurePoint
let originalValue = ''
@ -234,7 +231,7 @@ export default class {
} else {
originalValue = featurePoint.properties[pointKeyName]
}
let intOriginalValue = parseInt(originalValue)
let mappingValueObject: any = '';
@ -343,12 +340,12 @@ export default class {
// on met donc truthy_value: '1'
debugLog('truthy_value', originalValue)
if (this.truthyValues.indexOf(originalValue) !== -1) {
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = configObject.truthy_value
}
}
if (configObject.falsy_value) {
if (this.falsyValues.indexOf(originalValue) !== -1) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = configObject.falsy_value
}
}
@ -369,93 +366,19 @@ export default class {
// avec une fonction de transformation des valeurs
// parmi le domaine du jeu de données
// nécessite une clé conditionnelle à la valeur true d'autres clés converties.
if (configObject.keep_only_max_in_enum) {
let max = custom_utils.find_max_in_string(originalValue)
if (max && max < 401) {
convertedValue = max + ' kW'
} else {
convertedValue = originalValue
}
}
if (configObject.socket_output_find_correspondances) {
// trouver à quel socket ça correspond
// si y'a plusieurs sockets, utiliser socket:max:output
let we_use_max_output = false;
let has_prise_type_2: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_2) || false
let has_prise_type_combo_ccs: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_combo_ccs) || false
let prise_type_chademo: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_chademo) || false
let prise_type_ef: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_ef) || false
let prise_type_e: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_e) || false
let prise_type_autre: boolean = this.isTruthyValue(this.current_geojson_point.properties.prise_type_autre) || false
let countOfSockets = (boolToAddable(has_prise_type_2) + boolToAddable(has_prise_type_combo_ccs) + boolToAddable(prise_type_chademo) +
boolToAddable(prise_type_ef) + boolToAddable(prise_type_autre) + boolToAddable(prise_type_e)
);
if (countOfSockets > 0) {
we_use_max_output = true;
}
// ajouter les tags de socket newProperties
let converted_value = find_max_in_string(originalValue.replaceAll('.00', '').replaceAll(',', '.'))
let max_output = 401
// do not limit accepted values
let out = ''
if (intOriginalValue < max_output) {
// rajouter l'unité de puissance kW dans la valeur
out = converted_value + ' kW'
} else {
// prise en charge des valeurs en Watts et non en kW.
debugLog('too high kW value detected', originalValue)
if (intOriginalValue > 1000 && intOriginalValue < 401000) {
let kilowatts = (converted_value / 1000).toFixed(2);
out = ('' + kilowatts + ' kW').replaceAll('.00', '')
debugLog('valeurs en Watts out', out, 'original:', originalValue)
this.stats.power_output++
}
}
out = (out).replaceAll('.00', '')
// debug land
if (has_prise_type_combo_ccs) {
newProperties['socket:type2_combo:output'] = out;
this.stats.power_output++
}
if (we_use_max_output) {
newProperties['charging_station:output'] = out;
} else {
if (has_prise_type_2 && prise_type_e) {
newProperties['socket:type_2:output'] = out;
this.stats.power_output++
debugLog('2 prises, attribuer la plus haute valeur à la type 2', out)
}
if (countOfSockets === 1) {
if (has_prise_type_2) {
newProperties['socket:type_2:output'] = out;
newProperties['socket:type_2'] = 1;
this.stats.power_output++
}
if (has_prise_type_combo_ccs) {
newProperties['socket:type2_combo:output'] = out;
newProperties['socket:type2_combo'] = 1;
this.stats.power_output++
}
if (prise_type_chademo) {
newProperties['socket:chademo:output'] = out;
newProperties['socket:chademo'] = 1;
this.stats.power_output++
}
if (prise_type_e) {
newProperties['socket:typee:output'] = out;
newProperties['socket:typee'] = 1;
this.stats.power_output++
}
} else {
debugLog('no sockets', this.current_geojson_point.properties.ref)
}
}
convertedValue = out;
return out
convertedValue = detectSocketOutputFromFeaturePoint({
pointKeyName, mappingKeys, featurePoint, newProperties, originalValue
})
}
if (configObject.invert_boolean_value) {
@ -486,10 +409,10 @@ export default class {
if (configObject.remove_original_key) {
remove_original_key = true
}
if (configObject.ignore_if_falsy && this.falsyValues.indexOf(originalValue) !== -1) {
if (configObject.ignore_if_falsy && custom_utils.falsyValues.indexOf(originalValue) !== -1) {
remove_original_key = true
}
if (configObject.ignore_if_truthy && this.truthyValues.indexOf(originalValue) !== -1) {
if (configObject.ignore_if_truthy && custom_utils.truthyValues.indexOf(originalValue) !== -1) {
remove_original_key = true
}
@ -542,12 +465,12 @@ export default class {
// convertir la valeur, si elle est truthy, la transformer en ce que donne la propriété truthy_value
// exemple: le jeu de données dit que la colonne cable_t2_attache vaut "True", mais on veut le convertir en "1".
// on met donc truthy_value: '1'
if (this.truthyValues.indexOf(originalValue) !== -1) {
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = conditionnalConfig.truthy_value
}
}
if (conditionnalConfig.falsy_value) {
if (this.falsyValues.indexOf(originalValue) !== -1) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = conditionnalConfig.falsy_value
}
}
@ -607,26 +530,16 @@ export default class {
return newProperties;
}
private isTruthyValue(someValue: string) {
let convertedValue;
if (this.truthyValues.indexOf(someValue) !== -1) {
convertedValue = true
}
if (this.falsyValues.indexOf(someValue) !== -1) {
convertedValue = false
}
return convertedValue
}
private convertToYesOrNo(originalValue: any) {
debugLog('convertProperty: ==========> original value', originalValue)
let convertedValue = '';
if (this.truthyValues.indexOf(originalValue) !== -1) {
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = 'yes'
} else {
debugLog('convertProperty: ==========> !!! NOT in truthy values', originalValue)
}
if (this.falsyValues.indexOf(originalValue) !== -1) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = 'no'
} else {
debugLog('convertProperty: ==========> !!! NOT in falsy values', originalValue)
@ -637,12 +550,12 @@ export default class {
private convertToBoolean(originalValue: any) {
debugLog('convertProperty: ==========> original value', originalValue)
let convertedValue;
if (this.truthyValues.indexOf(originalValue) !== -1) {
if (custom_utils.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = true
} else {
debugLog('convertProperty: ==========> !!! NOT in truthy values', originalValue)
}
if (this.falsyValues.indexOf(originalValue) !== -1) {
if (custom_utils.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = false
} else {
debugLog('convertProperty: ==========> !!! NOT in falsy values', originalValue)

109
mappings/irve.utils.ts Normal file
View file

@ -0,0 +1,109 @@
import config from "../config";
import custom_utils from "./utils";
const { debugLog, find_max_in_string, boolToAddable } = custom_utils
function detectSocketOutputFromFeaturePoint(options: {
pointKeyName: string,
mappingKeys: any,
featurePoint: any,
newProperties: any,
originalValue: string
}) {
const { pointKeyName, mappingKeys, featurePoint, newProperties, originalValue } = options
let intOriginalValue = parseInt(originalValue)
// trouver à quel socket ça correspond
// si y'a plusieurs sockets, utiliser socket:max:output
let we_use_max_output = false;
let has_prise_type_2: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_2) || false
let has_prise_type_combo_ccs: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_combo_ccs) || false
let prise_type_chademo: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_chademo) || false
let prise_type_ef: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_ef) || false
let prise_type_e: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_e) || false
let prise_type_autre: boolean = custom_utils.isTruthyValue(featurePoint.properties.prise_type_autre) || false
let countOfSockets = (boolToAddable(has_prise_type_2) + boolToAddable(has_prise_type_combo_ccs) + boolToAddable(prise_type_chademo) +
boolToAddable(prise_type_ef) + boolToAddable(prise_type_autre) + boolToAddable(prise_type_e)
);
if (countOfSockets > 0) {
we_use_max_output = true;
}
// ajouter les tags de socket newProperties
// certains producteurs de données donnent des énumérations de puissances
// on prend la valeur max
let converted_value = find_max_in_string(originalValue.replaceAll('.00', '').replaceAll(',', '.'))
// do not limit accepted values
let out = ''
let out_number = 0
if (intOriginalValue < config.irve_max_output) {
// rajouter l'unité de puissance kW dans la valeur
out_number = converted_value
out = converted_value + ' kW'
} else {
// prise en charge des valeurs en Watts et non en kW.
debugLog('too high kW value detected', originalValue)
if (intOriginalValue > 1000 && intOriginalValue < (config.irve_max_output * 1000)) {
let kilowatts = (converted_value / 1000).toFixed(2);
out = ('' + kilowatts + ' kW').replaceAll('.00', '')
debugLog('valeurs en Watts out', out, 'original:', originalValue)
}
}
out = (out).replaceAll('.0', '')
if (has_prise_type_combo_ccs && countOfSockets === 1) {
newProperties['socket:type2_combo:output'] = out;
}
if (we_use_max_output) {
newProperties['charging_station:output'] = out;
} else {
if (has_prise_type_2 && prise_type_e) {
newProperties['socket:type_2:output'] = out;
debugLog('2 prises, attribuer la plus haute valeur à la type 2', out)
}
// deviner les décomptes de sockets
if (countOfSockets === 1) {
if (has_prise_type_2) {
newProperties['socket:type_2:output'] = out;
newProperties['socket:type_2'] = 1;
}
if (has_prise_type_combo_ccs) {
newProperties['socket:type2_combo:output'] = out;
newProperties['socket:type2_combo'] = 1;
}
if (prise_type_chademo) {
newProperties['socket:chademo:output'] = out;
newProperties['socket:chademo'] = 1;
}
if (prise_type_e) {
newProperties['socket:typee:output'] = out;
newProperties['socket:typee'] = 1;
}
} else {
debugLog('no sockets')
}
}
return out
}
export {
detectSocketOutputFromFeaturePoint
}

View file

@ -77,6 +77,7 @@ export interface FeaturePropertyMappingConfigType {
truncate_enums_to_limit?: number,
conditional_values?: ConditionnalValuesConfigType,
transform_function?: Function,
keep_only_max_in_enum?:boolean,
[key: string]: any,
}

View file

@ -18,6 +18,8 @@ function debugLog(...args: any[]) {
}
}
const truthyValues = [true, 'true', 'True', 'TRUE', '1', 'yes', 1]
const falsyValues = [false, 'false', 'False', 'FALSE', '0', 'no', 0]
let listOfBooleanKeys = [
"prise_type_ef",
@ -31,6 +33,21 @@ let listOfBooleanKeys = [
]
function boolToAddable(someBooleanValue: boolean) {
return someBooleanValue ? 1 : 0
}
function isTruthyValue(someValue: string) {
let convertedValue;
if (truthyValues.indexOf(someValue) !== -1) {
convertedValue = true
}
if (falsyValues.indexOf(someValue) !== -1) {
convertedValue = false
}
return convertedValue
}
/**
*
* @param pointKeyName
@ -121,10 +138,20 @@ function truncate_enums_to_limit(str: string, limit: number = 255) {
}
export default {
// debug tools
debugLog,
// typing
boolToAddable,
isBooleanKey,
writeFile,
isTruthyValue,
truthyValues,
falsyValues,
// research
find_max_in_string,
// formatting
truncate_enums_to_limit,
prefix_phone_fr_only,
// file tools
writeFile,
}