feat: check db prop options outside data consistency

This commit is contained in:
Sébastien Arod 2024-09-06 14:34:14 +02:00
parent f54a860359
commit a6c42aef80
6 changed files with 133 additions and 71 deletions

View file

@ -1,6 +1,9 @@
export type ContexteEntreeDC = export const contexteEntreeDCs = [
| "Pas de demande (Plein droit)" "Pas de demande (Plein droit)",
| "Pas de demande" "Pas de demande",
| "Après refus" "Après refus",
| "Après mise en demeure" "Après mise en demeure",
| "Après poursuite procureur"; "Après poursuite procureur",
] as const;
export type ContexteEntreeDC = (typeof contexteEntreeDCs)[number];

View file

@ -1,10 +1,13 @@
export type StatutFamille = export const statutsFamille = [
| "Résistant.e" "Résistant.e",
| "Ex résistant·e·s" "Ex résistant·e·s",
| "À préciser" "À préciser",
| "Se questionne" "Se questionne",
| "Désobéissence décidée" "Désobéissance décidée",
| "Rédaction Déclaration" "Rédaction Déclaration",
| "Déclaration Validée - Attente éléments" "Déclaration validée - Attente éléments",
| "Abdandon" "Abandon",
| "Incompatible"; "Incompatible",
] as const;
export type StatutFamille = (typeof statutsFamille)[number];

View file

@ -1,34 +1,37 @@
export type TypeEvenement = export const typesEvenements = [
| "Récidive gendarmerie" "Récidive gendarmerie",
| "Appel du jugement" "Appel du jugement",
| "Tribunal de police judiciaire" "Tribunal de police judiciaire",
| "Signalement au procureur" "Signalement au procureur",
| "Mise en demeure de scolarisation" "Mise en demeure de scolarisation",
| "Signalement" "Signalement",
| "Audition gendarmerie / police" "Audition gendarmerie / police",
| "Convocation procureur" "Convocation procureur",
| "Audition procureur" "Audition procureur",
| "Composition pénale refusée" "Composition pénale refusée",
| "Composition pénale acceptée" "Composition pénale acceptée",
| "Classement social sans suite" "Classement social sans suite",
| "Classement pénal sans suite" "Classement pénal sans suite",
| "Enquête sociale" "Enquête sociale",
| "Information préoccupante" "Information préoccupante",
| "Juge pour enfants" "Juge pour enfants",
| "Tribunal correctionnel" "Tribunal correctionnel",
| "Convocation CRPC" "Convocation CRPC",
| "Plaidoirie" "Plaidoirie",
| "Audience CRPC" "Audience CRPC",
| "Refus CRPC" "Refus CRPC",
| "Acceptation CRPC" // PLaceholder see does not exist in Notion yet // See https://discord.com/channels/990921361121746984/1245360366322585691/1248260713634336839 "Acceptation CRPC", // PLaceholder see does not exist in Notion yet // See https://discord.com/channels/990921361121746984/1245360366322585691/1248260713634336839
| "Audition des enfants" "Audition des enfants",
| "Assistance éducative" "Assistance éducative",
| "Contrôle forcé" "Contrôle forcé",
| "Refus de contrôle" "Refus de contrôle",
| "Rappel à la loi" "Rappel à la loi",
| "Passage police municipale" "Passage police municipale",
| "Administrateur AD'HOC" "Administrateur AD'HOC",
| "Validation désobéissance" "Validation désobéissance",
| "Contrôle URSSAF" "Contrôle URSSAF",
| "Contrôle fiscal" "Contrôle fiscal",
| "Gendarmerie/Forces de l'ordre"; "Gendarmerie/Forces de l'ordre",
] as const;
export type TypeEvenement = (typeof typesEvenements)[number];

View file

@ -49,7 +49,11 @@ function checkFamilyDataConsistency(family: Famille): ConsistencyReport {
issueType: "Ex résistant.e.s sans date Sortie", issueType: "Ex résistant.e.s sans date Sortie",
}); });
} }
if (family.Integration && family.Sortie && family.Integration > family.Sortie) { if (
family.Integration &&
family.Sortie &&
family.Integration > family.Sortie
) {
consistencyErrors.push({ consistencyErrors.push({
familyId: family.Titre, familyId: family.Titre,
issueType: "Date Intégration > date Sortie ", issueType: "Date Intégration > date Sortie ",
@ -77,14 +81,7 @@ function checkFamilyDataConsistency(family: Famille): ConsistencyReport {
}); });
} }
} }
consistencyWarnings.push(
...family.Evenements.filter((e) => !isValidEvenementFamille(e.Type)).map(
(e) => ({
familyId: family.Titre,
issueType: `Evenement ${e.notionId} a un Type non géré: "${e.Type}"`,
})
)
);
consistencyWarnings.push( consistencyWarnings.push(
...family.Evenements.filter((e) => e.Type !== null && e.Date === null).map( ...family.Evenements.filter((e) => e.Type !== null && e.Date === null).map(
(e) => ({ (e) => ({

View file

@ -0,0 +1,39 @@
import { GetDatabaseResponse } from "@notionhq/client/build/src/api-endpoints";
export function checkDbPropertyOptionsMatchesType(
db: GetDatabaseResponse,
propName: string,
typeOptions: readonly string[]
) {
function diff(list1: readonly string[], list2: readonly string[]): string[] {
const set = new Set(list1);
list2.forEach((item) => set.delete(item));
return [...set];
}
const dbPropOptions = propOptions(db.properties[propName]);
const notInType = diff(dbPropOptions, typeOptions);
const notInDb = diff(typeOptions, dbPropOptions);
if (notInType.length > 0) {
console.warn(
`Options for DB Property ${propName} not in Type Options: ${notInType}`
);
}
if (notInDb.length > 0) {
console.warn(`Type Options not in for DB Property ${propName}: ${notInDb}`);
}
function propOptions(
prop: GetDatabaseResponse["properties"][string]
): string[] {
if (prop.type === "select") {
return prop.select.options.map((o) => o.name);
} else if (prop.type === "status") {
return prop.status.options.map((o) => o.name);
} else if (prop.type === "multi_select") {
return prop.multi_select.options.map((o) => o.name);
} else {
return [];
}
}
}

View file

@ -1,10 +1,13 @@
import { Client, isFullPage } from "@notionhq/client"; import { Client, isFullPage } from "@notionhq/client";
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints"; import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
import { ContexteEntreeDC } from "../../data/ContexteEntreeDC"; import {
ContexteEntreeDC,
contexteEntreeDCs,
} from "../../data/ContexteEntreeDC";
import { EvenementFamille } from "../../data/EvenementFamille"; import { EvenementFamille } from "../../data/EvenementFamille";
import { Famille } from "../../data/Famille"; import { Famille } from "../../data/Famille";
import { StatutFamille } from "../../data/StatutFamille"; import { StatutFamille, statutsFamille } from "../../data/StatutFamille";
import { TypeEvenement } from "../../data/TypeEvenement"; import { TypeEvenement, typesEvenements } from "../../data/TypeEvenement";
import { datePropertyToDate } from "../utils/properties/datePropertyToDate"; import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId"; import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPageId";
import { selectPropertyToText } from "../utils/properties/selectPropertyToText"; import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
@ -12,6 +15,9 @@ import { statusPropertyToText } from "../utils/properties/statusPropertyToText";
import { titlePropertyToText } from "../utils/properties/titlePropertyToText"; import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
import { queryAllDbResults } from "../utils/queryAllDbResults"; import { queryAllDbResults } from "../utils/queryAllDbResults";
import { richTextPropertyToPlainText } from "../utils/text/richTextPropertyToPlainText"; import { richTextPropertyToPlainText } from "../utils/text/richTextPropertyToPlainText";
import { checkDbPropertyOptionsMatchesType } from "./checkDbPropertyOptionsMatchesType";
const contexteEntreeDCPropName = "Contexte dentrée DC";
export async function fetchFamiliesWithEventsFromNotion( export async function fetchFamiliesWithEventsFromNotion(
notionClient: Client notionClient: Client
@ -19,14 +25,25 @@ export async function fetchFamiliesWithEventsFromNotion(
const familiesDbId: string = "5b69e02b296d4a578f8c8ab7fe8b05da"; const familiesDbId: string = "5b69e02b296d4a578f8c8ab7fe8b05da";
const familEventsDbId: string = "c4d434b4603c4481a4d445618ecdf999"; const familEventsDbId: string = "c4d434b4603c4481a4d445618ecdf999";
const familyDb = await notionClient.databases.retrieve({
database_id: familiesDbId,
});
checkDbPropertyOptionsMatchesType(familyDb, "Statut", statutsFamille);
checkDbPropertyOptionsMatchesType(
familyDb,
contexteEntreeDCPropName,
contexteEntreeDCs
);
const eventsDb = await notionClient.databases.retrieve({
database_id: familEventsDbId,
});
checkDbPropertyOptionsMatchesType(eventsDb, "Type", typesEvenements);
const eventPages = ( const eventPages = (
await queryAllDbResults(notionClient, { await queryAllDbResults(notionClient, {
database_id: familEventsDbId, database_id: familEventsDbId,
sorts: [ sorts: [{ property: "Date", direction: "ascending" }],
{property: "Date",
direction: "ascending"
}
]
}) })
).filter(isFullPage); ).filter(isFullPage);
const familyPages = ( const familyPages = (
@ -45,7 +62,7 @@ export async function fetchFamiliesWithEventsFromNotion(
}) })
); );
// Fix to remove the empty "Famille de résistant" page that is often created by mistake // Fix to remove the empty "Famille de résistant" page that is often created by mistake
const filtered = familles.filter(f => f.Titre !== "Famille de résistant"); const filtered = familles.filter((f) => f.Titre !== "Famille de résistant");
return filtered; return filtered;
} }
@ -78,7 +95,7 @@ function buildFamily(
Statut: statusPropertyToText(pageProperties, "Statut") as StatutFamille, Statut: statusPropertyToText(pageProperties, "Statut") as StatutFamille,
ContexteEntree: selectPropertyToText( ContexteEntree: selectPropertyToText(
pageProperties, pageProperties,
"Contexte dentrée DC" contexteEntreeDCPropName
) as ContexteEntreeDC, ) as ContexteEntreeDC,
Integration: datePropertyToDate(pageProperties, "Intégration"), Integration: datePropertyToDate(pageProperties, "Intégration"),
Sortie: datePropertyToDate(pageProperties, "Sortie"), Sortie: datePropertyToDate(pageProperties, "Sortie"),