refactor: revue nettoyage des données
parent
4064b0f513
commit
5c0aebbcc3
|
@ -0,0 +1,25 @@
|
||||||
|
export type MessageDeNettoyage = {
|
||||||
|
message: string;
|
||||||
|
severite:
|
||||||
|
| "Donnée ignorée"
|
||||||
|
| "Donnée suspecte"
|
||||||
|
| "Donnée incohérente bloquante";
|
||||||
|
};
|
||||||
|
export function msgDonneeIgnoree(message: string): MessageDeNettoyage {
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
severite: "Donnée ignorée",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function msgDonneeSuspecte(message: string): MessageDeNettoyage {
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
severite: "Donnée suspecte",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function msgDonneeBloquante(message: string): MessageDeNettoyage {
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
severite: "Donnée incohérente bloquante",
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { Famille, isExResistant, isResistant } from "./Famille";
|
import { Famille, isExResistant, isResistant } from "../Famille";
|
||||||
|
|
||||||
export function checkDataConsistency(families: Famille[]): ConsistencyReport {
|
export function checkDataConsistency(families: Famille[]): ConsistencyReport {
|
||||||
const reports = families.map((family) => {
|
const reports = families.map((family) => {
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { Famille } from "../Famille";
|
||||||
|
import { checkDataConsistency } from "./checkDataConsistency";
|
||||||
|
import {
|
||||||
|
MessageDeNettoyage,
|
||||||
|
msgDonneeBloquante,
|
||||||
|
msgDonneeIgnoree,
|
||||||
|
msgDonneeSuspecte,
|
||||||
|
} from "./MessageDeNettoyage";
|
||||||
|
|
||||||
|
type DonneesNettoyees = {
|
||||||
|
familles: Famille[];
|
||||||
|
messages: MessageDeNettoyage[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function nettoyerDonneesFamilles(
|
||||||
|
donneesFamillesBrutes: Famille[]
|
||||||
|
): DonneesNettoyees {
|
||||||
|
let familles = donneesFamillesBrutes;
|
||||||
|
|
||||||
|
let messages: MessageDeNettoyage[] = [];
|
||||||
|
|
||||||
|
const output = supprimerLesEntreesVide(familles);
|
||||||
|
messages = [...messages, ...output.messages];
|
||||||
|
familles = output.familles;
|
||||||
|
|
||||||
|
// TODO convert checkDataConsistency to filters
|
||||||
|
const consistencyReport = checkDataConsistency(familles);
|
||||||
|
|
||||||
|
// Adapte les message
|
||||||
|
const errorMessages: MessageDeNettoyage[] = consistencyReport.errors.map(
|
||||||
|
(e) => msgDonneeBloquante(`${e.familyId} - ${e.issueType}`)
|
||||||
|
);
|
||||||
|
const warnings: MessageDeNettoyage[] = consistencyReport.warnings.map((e) =>
|
||||||
|
msgDonneeSuspecte(`${e.familyId} - ${e.issueType}`)
|
||||||
|
);
|
||||||
|
|
||||||
|
messages = [...messages, ...errorMessages, ...warnings];
|
||||||
|
|
||||||
|
return {
|
||||||
|
familles,
|
||||||
|
messages,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime "Famille de résistant" qui sont souvent créé par erreur
|
||||||
|
*/
|
||||||
|
function supprimerLesEntreesVide(familles: Famille[]): DonneesNettoyees {
|
||||||
|
const nettoyees = familles.filter((f) => f.Titre !== "Famille de résistant");
|
||||||
|
const ignorees = familles.filter((f) => f.Titre === "Famille de résistant");
|
||||||
|
if (ignorees.length > 0) {
|
||||||
|
return {
|
||||||
|
familles: nettoyees,
|
||||||
|
messages: [
|
||||||
|
msgDonneeIgnoree(
|
||||||
|
`${
|
||||||
|
nettoyees.length - familles.length
|
||||||
|
} enregistrement(s) famille "vide" ignoré(s)`
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
familles: nettoyees,
|
||||||
|
messages: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
51
src/index.ts
51
src/index.ts
|
@ -1,6 +1,5 @@
|
||||||
import { Client } from "@notionhq/client";
|
import { Client } from "@notionhq/client";
|
||||||
import { writeFileSync } from "fs";
|
import { writeFileSync } from "fs";
|
||||||
import { checkDataConsistency } from "./data/checkDataConsistency";
|
|
||||||
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
import { fetchFamiliesWithEventsFromNotion } from "./notion/fetch/fetchFamiliesWithEventsFromNotion";
|
||||||
import { publishStatisticsToNotion } from "./notion/publish/v1/publishStatisticsToNotion";
|
import { publishStatisticsToNotion } from "./notion/publish/v1/publishStatisticsToNotion";
|
||||||
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
import { publishStatsToPage } from "./notion/publish/v2/publishStatsToPage";
|
||||||
|
@ -17,6 +16,7 @@ import { formatDate } from "date-fns";
|
||||||
import { computeStatsGeneralesMensuelles } from "./statistiques/v2/generales/computeStatsGeneralesMensuelles";
|
import { computeStatsGeneralesMensuelles } from "./statistiques/v2/generales/computeStatsGeneralesMensuelles";
|
||||||
import { mermaidDiagramStatsGeneralesMensuelles } from "./statistiques/v2/generales/mermaidDiagramStatsGeneralesMensuelles";
|
import { mermaidDiagramStatsGeneralesMensuelles } from "./statistiques/v2/generales/mermaidDiagramStatsGeneralesMensuelles";
|
||||||
import { publishStatsGenerales } from "./notion/publish/v2/publishStatsGenerales";
|
import { publishStatsGenerales } from "./notion/publish/v2/publishStatsGenerales";
|
||||||
|
import { nettoyerDonneesFamilles } from "./data/nettoyage/nettoyerDonneesFamilles";
|
||||||
|
|
||||||
type ProcessOptions = {
|
type ProcessOptions = {
|
||||||
dryRun: boolean;
|
dryRun: boolean;
|
||||||
|
@ -45,35 +45,54 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
auth: options.notionApiToken,
|
auth: options.notionApiToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Checking DB schemas...");
|
console.log("Vérification schéma des bases Notion...");
|
||||||
await checkDbSchemas(notionClient);
|
await checkDbSchemas(notionClient);
|
||||||
|
|
||||||
console.log("Fetching families...");
|
console.log("Téléchargement des familles...");
|
||||||
const doFetch = true;
|
const doFetch = true;
|
||||||
|
|
||||||
const familles = doFetch
|
const donneesFamillesBrutes = doFetch
|
||||||
? await fetchFamiliesWithEventsFromNotion(notionClient)
|
? await fetchFamiliesWithEventsFromNotion(notionClient)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
console.log("Checking Data Consistency issues...");
|
console.log("Nettoyage des données brutes...");
|
||||||
const consistencyReport = checkDataConsistency(familles);
|
const { familles, messages } = nettoyerDonneesFamilles(donneesFamillesBrutes);
|
||||||
if (consistencyReport.errors.length > 0) {
|
|
||||||
|
const donneesBloquantes = messages.filter(
|
||||||
|
(m) => m.severite === "Donnée incohérente bloquante"
|
||||||
|
);
|
||||||
|
const donneesSuspectes = messages.filter(
|
||||||
|
(m) => m.severite === "Donnée suspecte"
|
||||||
|
);
|
||||||
|
const donneesIgnorees = messages.filter(
|
||||||
|
(m) => m.severite === "Donnée ignorée"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (donneesBloquantes.length > 0) {
|
||||||
console.error(
|
console.error(
|
||||||
`Found ${consistencyReport.errors.length} consistency error(s) that prevent building stats:`
|
`${donneesBloquantes.length} Données bloquantes empêche de calculer les statistiques:`
|
||||||
);
|
);
|
||||||
console.error(consistencyReport.errors);
|
donneesBloquantes.forEach((e) => {
|
||||||
|
console.warn(" - " + e.message);
|
||||||
|
});
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (consistencyReport.warnings.length > 0) {
|
if (donneesSuspectes.length > 0) {
|
||||||
console.warn(
|
console.warn(`${donneesSuspectes.length} Données suspectes trouvées:`);
|
||||||
`Found ${consistencyReport.warnings.length} non blocking consistency warning(s):`
|
donneesSuspectes.forEach((e) => {
|
||||||
);
|
console.warn(" - " + e.message);
|
||||||
console.warn(consistencyReport.warnings);
|
});
|
||||||
|
}
|
||||||
|
if (donneesIgnorees.length > 0) {
|
||||||
|
console.warn(`${donneesIgnorees.length} Données ignorées:`);
|
||||||
|
donneesIgnorees.forEach((e) => {
|
||||||
|
console.warn(" - " + e.message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentDate = new Date(Date.now());
|
const currentDate = new Date(Date.now());
|
||||||
|
|
||||||
console.log("Building statistics...");
|
console.log("Calcul des statistiques...");
|
||||||
const elStats = computeELStats(familles, currentDate);
|
const elStats = computeELStats(familles, currentDate);
|
||||||
|
|
||||||
const statsGenerales = computeStatsGenerales(familles);
|
const statsGenerales = computeStatsGenerales(familles);
|
||||||
|
@ -93,7 +112,7 @@ function buildProcessOptions(): ProcessOptions {
|
||||||
);
|
);
|
||||||
if (options.dryRun) {
|
if (options.dryRun) {
|
||||||
console.log(
|
console.log(
|
||||||
"Dry run => Skip Publishing. Stats are dumped in file el-stats-xxx.json"
|
"Dry run => Pas de publication. Les stats sont écrite localement dans el-stats-xxx"
|
||||||
);
|
);
|
||||||
writeFileSync("./el-stats-v1.json", JSON.stringify(elStats, null, " "));
|
writeFileSync("./el-stats-v1.json", JSON.stringify(elStats, null, " "));
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,7 @@ export async function fetchFamiliesWithEventsFromNotion(
|
||||||
return buildFamily(pageObjectResponse, familyEvents);
|
return buildFamily(pageObjectResponse, familyEvents);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// Fix to remove the empty "Famille de résistant" page that is often created by mistake
|
return familles;
|
||||||
const filtered = familles.filter((f) => f.Titre !== "Famille de résistant");
|
|
||||||
return filtered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildFamilyEvent(page: PageObjectResponse): EvenementFamille {
|
function buildFamilyEvent(page: PageObjectResponse): EvenementFamille {
|
||||||
|
|
Loading…
Reference in New Issue