@gouvfr-anct/mednum
Version:
✨ Permet de transformer une source de données vers le schéma des lieux de mediation numerique
71 lines (70 loc) • 5.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.findDuplicates = void 0;
const lieux_de_mediation_numerique_1 = require("@gouvfr-anct/lieux-de-mediation-numerique");
const fuzzball_1 = require("fuzzball");
const sameSource = (lieu, lieuToDeduplicate) => lieu.source === lieuToDeduplicate.source;
const sameId = (lieu, lieuToDeduplicate) => lieu.id === lieuToDeduplicate.id;
const sameCodeInsee = (lieu, lieuToDeduplicate) => lieu.code_insee === lieuToDeduplicate.code_insee;
const compatibleTypologies = [[lieux_de_mediation_numerique_1.Typologie.RFS, lieux_de_mediation_numerique_1.Typologie.PIMMS]];
const toTypologies = ({ typologie }) => (0, lieux_de_mediation_numerique_1.Typologies)(typologie?.split('|') ?? []);
const allEmpty = (lieuTypologies, lieuToDeduplicateTypologies) => lieuTypologies.length === 0 && lieuToDeduplicateTypologies.length === 0;
const hasSameTypologieIn = (lieuToDeduplicateTypologies) => (typologie) => lieuToDeduplicateTypologies.includes(typologie);
const hasCompatibleTypologiesFor = (lieuTypologies, lieuToDeduplicateTypologies) => ([typologyA, typologyB]) => (lieuTypologies.includes(typologyA) && lieuToDeduplicateTypologies.includes(typologyB)) ||
(lieuTypologies.includes(typologyB) && lieuToDeduplicateTypologies.includes(typologyA));
const sameTypologie = (lieuTypologies, lieuToDeduplicateTypologies) => allEmpty(lieuTypologies, lieuToDeduplicateTypologies) ||
lieuTypologies.some(hasSameTypologieIn(lieuToDeduplicateTypologies)) ||
compatibleTypologies.some(hasCompatibleTypologiesFor(lieuTypologies, lieuToDeduplicateTypologies));
const onlyPotentialDuplicates = (lieuToDeduplicate, allowInternalMerge) => (lieu) => sameCodeInsee(lieu, lieuToDeduplicate) &&
!sameId(lieu, lieuToDeduplicate) &&
(allowInternalMerge || !sameSource(lieu, lieuToDeduplicate)) &&
sameTypologie(toTypologies(lieu), toTypologies(lieuToDeduplicate));
const MINIMAL_CARTESIAN_DISTANCE = 0.0004;
const computeDistanceScore = (cartesianDistance) => 100 / (cartesianDistance * 1000 + 1);
const distanceScore = (cartesianDistance) => Math.trunc(cartesianDistance < MINIMAL_CARTESIAN_DISTANCE ? 100 : computeDistanceScore(cartesianDistance));
const hasDefinedCoordinates = (lieu) => lieu.latitude != null && lieu.longitude != null;
const pythagore = (x1, x2, y1, y2) => Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
const cartesianDistanceBetween = (lieu, cible) => hasDefinedCoordinates(lieu) && hasDefinedCoordinates(cible)
? pythagore(lieu.latitude, cible.latitude, lieu.longitude, cible.longitude)
: NaN;
const duplicatesWithScores = (lieux) => (lieuToDeduplicate, allowInternalMerge) => lieux.filter(onlyPotentialDuplicates(lieuToDeduplicate, allowInternalMerge)).map((lieu) => ({
id: lieu.id,
distanceScore: distanceScore(cartesianDistanceBetween(lieu, lieuToDeduplicate)),
nomFuzzyScore: (0, fuzzball_1.ratio)(lieu.nom, lieuToDeduplicate.nom),
voieFuzzyScore: (0, fuzzball_1.ratio)(lieu.adresse, lieuToDeduplicate.adresse)
}));
const toLieuDuplications = (lieu, lieux, allowInternalMerge) => ({ id: lieu.id, duplicates: duplicatesWithScores(lieux)(lieu, allowInternalMerge) });
const appendCommuneDuplications = (lieux) => (lieuToDeduplicate, duplications, allowInternalMerge) => lieuToDeduplicate.code_insee != null
? [
...duplications,
{
code_insee: lieuToDeduplicate.code_insee,
lieux: [toLieuDuplications(lieuToDeduplicate, lieux, allowInternalMerge)]
}
]
: duplications;
const toUpdatedCommuneDuplications = (lieux) => (lieu, duplicationsWithSameCodeInsee, allowInternalMerge) => (communeDuplications) => communeDuplications.code_insee === lieu.code_insee
? {
code_insee: lieu.code_insee,
lieux: [...duplicationsWithSameCodeInsee.lieux, toLieuDuplications(lieu, lieux, allowInternalMerge)]
}
: communeDuplications;
const withSameCodeInsee = (lieu) => ({ code_insee }) => code_insee === lieu.code_insee;
const toCommunesDuplications = (lieux, allowInternalMerge) => (duplications, lieuToDeduplicate) => ((duplicationsWithSameCodeInsee) => duplicationsWithSameCodeInsee == null
? appendCommuneDuplications(lieux)(lieuToDeduplicate, duplications, allowInternalMerge)
: duplications.map(toUpdatedCommuneDuplications(lieux)(lieuToDeduplicate, duplicationsWithSameCodeInsee, allowInternalMerge)))(duplications.find(withSameCodeInsee(lieuToDeduplicate)));
const onlyWithDuplicates = ({ duplicates }) => duplicates.length > 0;
const onlyWithoutDuplicates = ({ duplicates }) => duplicates.length === 0;
const toDuplicatesWithout = (noDuplicatesIds) => ({ id, duplicates }) => ({
id,
duplicates: duplicates.filter((duplicate) => !noDuplicatesIds.includes(duplicate.id))
});
const invalidDuplicatesIds = ({ lieux }) => lieux.filter(onlyWithoutDuplicates).map((lieu) => lieu.id);
const removeLieuxFrom = ({ code_insee, lieux }, ids) => ({
code_insee,
lieux: lieux.map(toDuplicatesWithout(ids)).filter(onlyWithDuplicates)
});
const toValidDuplicates = (communeDuplications) => removeLieuxFrom(communeDuplications, invalidDuplicatesIds(communeDuplications));
const onlyWithLieux = (communeDuplications) => communeDuplications.lieux.length > 0;
const findDuplicates = (lieux, allowInternalMerge, lieuxToDeduplicate = lieux) => lieuxToDeduplicate.reduce(toCommunesDuplications(lieux, allowInternalMerge), []).map(toValidDuplicates).filter(onlyWithLieux);
exports.findDuplicates = findDuplicates;