diff --git a/server/src/common/actions/helpers/filters.ts b/server/src/common/actions/helpers/filters.ts index 1f9434d57..2f54be9f1 100644 --- a/server/src/common/actions/helpers/filters.ts +++ b/server/src/common/actions/helpers/filters.ts @@ -1,11 +1,5 @@ -import { subYears } from "date-fns"; -import { getAnneesScolaireListFromDate } from "shared"; import { z } from "zod"; -import { SIRET_REGEX } from "@/common/constants/validations"; -import { escapeRegExp } from "@/common/utils/regexUtils"; -import { isValidUAI } from "@/common/utils/validationUtils"; - export const organismeLookup = { from: "organismes", localField: "organisme_id", @@ -20,63 +14,22 @@ export interface FilterConfiguration { transformValue?: (value: any) => any; } -export const organismesFiltersSchema = { +export const territoireFiltersSchema = { organisme_regions: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), organisme_departements: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), organisme_academies: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), organisme_bassinsEmploi: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), }; -export type OrganismesFilters = z.infer>; - -export const organismesFiltersConfigurations: { [key in keyof Required]: FilterConfiguration } = { - organisme_departements: { - matchKey: "adresse.departement", - transformValue: (value) => ({ $in: value }), - }, - organisme_regions: { - matchKey: "adresse.region", - transformValue: (value) => ({ $in: value }), - }, - organisme_academies: { - matchKey: "adresse.academie", - transformValue: (value) => ({ $in: value }), - }, - organisme_bassinsEmploi: { - matchKey: "adresse.bassinEmploi", - transformValue: (value) => ({ $in: value }), - }, -}; +export type TerritoireFilters = z.infer>; -export const effectifsFiltersSchema = { - ...organismesFiltersSchema, - date: z.preprocess((str: any) => new Date(str), z.date()), +// Filtre des effectifs par territoire +export const effectifsFiltersTerritoireSchema = { + ...territoireFiltersSchema, + date: z.preprocess((str: any) => new Date(str ?? Date.now()), z.date()), }; -export type EffectifsFilters = z.infer>; - -export const effectifsFiltersConfigurations: { [key in keyof Required]: FilterConfiguration } = { - date: { - matchKey: "annee_scolaire", - transformValue: (value) => ({ $in: getAnneesScolaireListFromDate(value) }), - }, - organisme_departements: { - matchKey: "_computed.organisme.departement", - transformValue: (value) => ({ $in: value }), - }, - organisme_regions: { - matchKey: "_computed.organisme.region", - transformValue: (value) => ({ $in: value }), - }, - organisme_academies: { - matchKey: "_computed.organisme.academie", - transformValue: (value) => ({ $in: value }), - }, - organisme_bassinsEmploi: { - matchKey: "_computed.organisme.bassinEmploi", - transformValue: (value) => ({ $in: value }), - }, -}; +export type EffectifsFiltersTerritoire = z.infer>; // [min, max[ const intervalParTrancheAge = { @@ -90,7 +43,7 @@ const intervalParTrancheAge = { * Utilisé pour la recherche détaillée des indicateurs effectifs */ export const fullEffectifsFiltersSchema = { - ...effectifsFiltersSchema, + ...effectifsFiltersTerritoireSchema, organisme_search: z.string().optional(), organisme_reseaux: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), // apprenant_genre: z.string(), @@ -110,83 +63,3 @@ export const fullEffectifsFiltersSchema = { }; export type FullEffectifsFilters = z.infer>; - -export const fullEffectifsFiltersConfigurations: { - [key in keyof Required]: FilterConfiguration; -} = { - ...effectifsFiltersConfigurations, - organisme_search: { - matchKey: "$or", - transformValue: (value) => { - if (isValidUAI(value)) { - return [{ "_computed.organisme.uai": value }]; - } - if (SIRET_REGEX.test(value)) { - return [{ "_computed.organisme.siret": value }]; - } - if (/^\d{3,}$/.test(value)) { - return [{ "_computed.organisme.siret": new RegExp(escapeRegExp(value)) }]; - } - return [{ "_computed.organisme.nom": new RegExp(escapeRegExp(value)) }]; // TODO probablement ajouter un champ nom (enseigne + raison_sociale) de l'organisme - }, - }, - organisme_reseaux: { - matchKey: "_computed.organisme.reseaux", - transformValue: (value) => ({ $in: value }), - }, - - // apprenant_genre: { - // matchKey: "", // encore inconnu, INE ou civilité avec api v3 ? - // }, - apprenant_tranchesAge: { - matchKey: "$or", - transformValue: (keys) => - keys.map((key) => { - const [min, max] = intervalParTrancheAge[key]; - return { - "apprenant.date_de_naissance": { - $lt: subYears(new Date(), min), - $gte: subYears(new Date(), max), - }, - }; - }), - }, - // apprenant_rqth: { - // matchKey: "", // inconnu - // }, - - formation_annees: { - matchKey: "formation.annee", - transformValue: (value) => ({ $in: value }), - }, - formation_niveaux: { - matchKey: "formation.niveau", - transformValue: (value) => ({ $in: value }), - }, - formation_cfds: { - matchKey: "formation.cfd", - transformValue: (value) => ({ $in: value }), - }, - formation_secteursProfessionnels: { - matchKey: "_computed.formation.codes_rome", - transformValue: (value) => ({ $in: value }), - }, -}; - -export function buildMongoFilters< - Filters extends { [s: string]: any }, - FiltersConfiguration = { [key in keyof Required]: FilterConfiguration }, ->(filters: Filters, filtersConfiguration: FiltersConfiguration): any[] { - return Object.entries(filters).reduce((matchFilters, [filterName, filterValue]) => { - const filterConfiguration = filtersConfiguration[filterName]; - if (!filterConfiguration) { - return matchFilters; - } - return [ - ...matchFilters, - { - [filterConfiguration.matchKey]: filterConfiguration.transformValue?.(filterValue) ?? filterValue, - }, - ]; - }, [] as any[]); -} diff --git a/server/src/common/actions/indicateurs/effectifs/effectifs-filters.test.ts b/server/src/common/actions/indicateurs/effectifs/effectifs-filters.test.ts new file mode 100644 index 000000000..b4e495860 --- /dev/null +++ b/server/src/common/actions/indicateurs/effectifs/effectifs-filters.test.ts @@ -0,0 +1,126 @@ +import { strict as assert } from "assert"; + +import { buildEffectifMongoFilters } from "./effectifs-filters"; + +const currentDate = new Date("2023-02-14T10:00:00Z"); + +describe("Filtres Indicateurs", () => { + describe("buildEffectifMongoFilters()", () => { + it("Gère le filtre date uniquement", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + }); + }); + + it("Gère le filtre organisme_departements", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + organisme_departements: ["56"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "_computed.organisme.departement": { + $in: ["56"], + }, + }); + }); + + it("Gère le filtre organisme_regions", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + organisme_regions: ["25"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "_computed.organisme.region": { + $in: ["25"], + }, + }); + }); + + it("Gère le filtre organisme_reseaux", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + organisme_reseaux: ["AGRI"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "_computed.organisme.reseaux": { + $in: ["AGRI"], + }, + }); + }); + + it("Gère le filtre formation_cfds", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + formation_cfds: ["25021000"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "formation.cfd": { + $in: ["25021000"], + }, + }); + }); + + it("Gère le filtre formation_niveaux", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + formation_niveaux: ["2"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "formation.niveau": { + $in: ["2"], + }, + }); + }); + + it("Gère tous les filtres en même temps", () => { + const stages = buildEffectifMongoFilters({ + date: currentDate, + organisme_regions: ["25"], + organisme_departements: ["56"], + organisme_reseaux: ["AGRI"], + formation_cfds: ["25021000"], + formation_niveaux: ["2"], + }); + assert.deepStrictEqual(stages, { + annee_scolaire: { + $in: ["2023-2023", "2022-2023"], + }, + "_computed.organisme.region": { + $in: ["25"], + }, + "_computed.organisme.departement": { + $in: ["56"], + }, + "_computed.organisme.reseaux": { + $in: ["AGRI"], + }, + "formation.cfd": { + $in: ["25021000"], + }, + "formation.niveau": { + $in: ["2"], + }, + }); + }); + }); +}); diff --git a/server/src/common/actions/indicateurs/effectifs/effectifs-filters.ts b/server/src/common/actions/indicateurs/effectifs/effectifs-filters.ts new file mode 100644 index 000000000..ac3008f34 --- /dev/null +++ b/server/src/common/actions/indicateurs/effectifs/effectifs-filters.ts @@ -0,0 +1,86 @@ +import { subYears } from "date-fns"; +import { Filter } from "mongodb"; +import { assertUnreachable, entries, getAnneesScolaireListFromDate } from "shared"; + +import { SIRET_REGEX } from "@/common/constants/validations"; +import { Effectif } from "@/common/model/@types"; +import { escapeRegExp } from "@/common/utils/regexUtils"; +import { isValidUAI } from "@/common/utils/validationUtils"; + +import { FullEffectifsFilters } from "../../helpers/filters"; + +// [min, max[ +const intervalParTrancheAge = { + "-18": [0, 18], + "18-20": [18, 21], + "21-25": [21, 26], + "26+": [26, 999], +}; + +function buildOrganismeSearchCondition(value: string) { + if (isValidUAI(value)) { + return [{ "_computed.organisme.uai": value }]; + } + if (SIRET_REGEX.test(value)) { + return [{ "_computed.organisme.siret": value }]; + } + if (/^\d{3,}$/.test(value)) { + return [{ "_computed.organisme.siret": new RegExp(escapeRegExp(value)) }]; + } + return [{ "_computed.organisme.nom": new RegExp(escapeRegExp(value)) }]; // TODO probablement ajouter un champ nom (enseigne + raison_sociale) de l'organisme +} + +export function buildEffectifMongoFilters(filters: FullEffectifsFilters): Filter { + return entries(filters).reduce((acc: Filter, [key, value]) => { + switch (key) { + case "date": + acc["annee_scolaire"] = { $in: getAnneesScolaireListFromDate(value) }; + break; + case "organisme_regions": + acc["_computed.organisme.region"] = { $in: value }; + break; + case "organisme_departements": + acc["_computed.organisme.departement"] = { $in: value }; + break; + case "organisme_academies": + acc["_computed.organisme.academie"] = { $in: value }; + break; + case "organisme_bassinsEmploi": + acc["_computed.organisme.bassinEmploi"] = { $in: value }; + break; + case "organisme_search": + acc["$or"] = buildOrganismeSearchCondition(value); + break; + case "organisme_reseaux": + acc["_computed.organisme.reseaux"] = { $in: value }; + break; + case "apprenant_tranchesAge": + acc["$or"] = value.map((key) => { + const [min, max] = intervalParTrancheAge[key]; + return { + "apprenant.date_de_naissance": { + $lt: subYears(new Date(), min), + $gte: subYears(new Date(), max), + }, + }; + }); + break; + case "formation_annees": + acc["formation.annee"] = { $in: value }; + break; + case "formation_niveaux": + acc["formation.niveau"] = { $in: value }; + break; + case "formation_cfds": + acc["formation.cfd"] = { $in: value }; + break; + case "formation_secteursProfessionnels": + acc["_computed.formation.codes_rome"] = { $in: value }; + break; + default: + assertUnreachable(key); + } + + return acc; + }, {}); +} diff --git a/server/src/common/actions/indicateurs/indicateurs-national.actions.ts b/server/src/common/actions/indicateurs/indicateurs-national.actions.ts index bbef97ddb..75a52402f 100644 --- a/server/src/common/actions/indicateurs/indicateurs-national.actions.ts +++ b/server/src/common/actions/indicateurs/indicateurs-national.actions.ts @@ -5,20 +5,23 @@ import { organismesDb } from "@/common/model/collections"; import { AuthContext } from "@/common/model/internal/AuthContext"; import { tryCachedExecution } from "@/common/utils/cacheUtils"; -import { OrganismesFilters, buildMongoFilters, organismesFiltersConfigurations } from "../helpers/filters"; +import { TerritoireFilters } from "../helpers/filters"; import { getIndicateursEffectifsParDepartement } from "./indicateurs.actions"; +import { buildOrganismeMongoFilters } from "./organismes/organismes-filters"; const indicateursNationalCacheExpirationMs = 3600 * 1000; // 1 hour export const indicateursNationalFiltersSchema = { - date: z.preprocess((str: any) => new Date(str), z.date()), + date: z.preprocess((str: any) => new Date(str ?? Date.now()), z.date()), organisme_regions: z.preprocess((str: any) => str.split(","), z.array(z.string())).optional(), }; export type IndicateursNationalFilters = z.infer>; export async function getIndicateursNational(filters: IndicateursNationalFilters) { + const { date, ...territoireFilter } = filters; + return await tryCachedExecution( `indicateurs-national:${format(filters.date, "yyyy-MM-dd")}:${filters.organisme_regions?.join(",")}`, indicateursNationalCacheExpirationMs, @@ -26,7 +29,7 @@ export async function getIndicateursNational(filters: IndicateursNationalFilters const ctx = { organisation: { type: "ADMINISTRATEUR" } } as AuthContext; // Hack le temps de refactorer const [indicateursEffectifs, indicateursOrganismes] = await Promise.all([ getIndicateursEffectifsParDepartement(ctx, filters), - getIndicateursOrganismesNature(filters), + getIndicateursOrganismesNature(territoireFilter), ]); return { indicateursEffectifs, indicateursOrganismes }; } @@ -41,13 +44,13 @@ interface IndicateursOrganismesNature { formateurs: number; } -export async function getIndicateursOrganismesNature(filters: OrganismesFilters): Promise { +export async function getIndicateursOrganismesNature(filters: TerritoireFilters): Promise { const indicateurs = (await organismesDb() .aggregate([ { $match: { + ...buildOrganismeMongoFilters(filters), $and: [ - ...buildMongoFilters(filters, organismesFiltersConfigurations), { fiabilisation_statut: "FIABLE", ferme: false, diff --git a/server/src/common/actions/indicateurs/indicateurs.actions.ts b/server/src/common/actions/indicateurs/indicateurs.actions.ts index 917779687..2d4a4089c 100644 --- a/server/src/common/actions/indicateurs/indicateurs.actions.ts +++ b/server/src/common/actions/indicateurs/indicateurs.actions.ts @@ -3,15 +3,7 @@ import { ObjectId } from "mongodb"; import { CODES_STATUT_APPRENANT } from "shared"; import { TypeEffectifNominatif } from "shared/constants/indicateurs"; -import { - EffectifsFilters, - FullEffectifsFilters, - OrganismesFilters, - buildMongoFilters, - effectifsFiltersConfigurations, - fullEffectifsFiltersConfigurations, - organismesFiltersConfigurations, -} from "@/common/actions/helpers/filters"; +import { EffectifsFiltersTerritoire, FullEffectifsFilters, TerritoireFilters } from "@/common/actions/helpers/filters"; import { findOrganismesFormateursIdsOfOrganisme } from "@/common/actions/helpers/permissions"; import { effectifsDb, organismesDb } from "@/common/model/collections"; import { AuthContext } from "@/common/model/internal/AuthContext"; @@ -19,6 +11,7 @@ import { AuthContext } from "@/common/model/internal/AuthContext"; import { getPermissionOrganisationQueryFilter } from "../helpers/permissions-organisation"; import { getOrganismeIndicateursEffectifsRestriction } from "../helpers/permissions-organisme"; +import { buildEffectifMongoFilters } from "./effectifs/effectifs-filters"; import { IndicateursEffectifs, IndicateursEffectifsAvecDepartement, @@ -27,19 +20,18 @@ import { IndicateursOrganismes, IndicateursOrganismesAvecDepartement, } from "./indicateurs"; +import { buildOrganismeMongoFilters } from "./organismes/organismes-filters"; export async function getIndicateursEffectifsParDepartement( ctx: AuthContext, - filters: EffectifsFilters + filters: FullEffectifsFilters ): Promise { - const indicateurs = (await effectifsDb() + const indicateurs = await effectifsDb() .aggregate([ { $match: { - $and: [ - await getPermissionOrganisationQueryFilter(ctx, "IndicateursEffectifsParDepartement"), - ...buildMongoFilters(filters, effectifsFiltersConfigurations), - ], + $and: [await getPermissionOrganisationQueryFilter(ctx, "IndicateursEffectifsParDepartement")], + ...buildEffectifMongoFilters(filters), "_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables }, }, @@ -190,22 +182,20 @@ export async function getIndicateursEffectifsParDepartement( }, }, ]) - .toArray()) as IndicateursEffectifsAvecDepartement[]; - return indicateurs; + .toArray(); + return indicateurs as IndicateursEffectifsAvecDepartement[]; } export async function getIndicateursOrganismesParDepartement( ctx: AuthContext, - filters: OrganismesFilters + filters: TerritoireFilters ): Promise { const indicateurs = (await organismesDb() .aggregate([ { $match: { - $and: [ - await getPermissionOrganisationQueryFilter(ctx, "IndicateursOrganismesParDepartement"), - ...buildMongoFilters(filters, organismesFiltersConfigurations), - ], + $and: [await getPermissionOrganisationQueryFilter(ctx, "IndicateursOrganismesParDepartement")], + ...buildOrganismeMongoFilters(filters), fiabilisation_statut: "FIABLE", ferme: false, }, @@ -255,8 +245,8 @@ export async function getIndicateursEffectifsParOrganisme( $and: [ await getOrganismeRestriction(organismeId), await getPermissionOrganisationQueryFilter(ctx, "IndicateursEffectifsParOrganisme"), - ...buildMongoFilters(filters, fullEffectifsFiltersConfigurations), ], + ...buildEffectifMongoFilters(filters), "_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables }, }, @@ -453,11 +443,8 @@ export async function getOrganismeIndicateursEffectifsParFormation( .aggregate([ { $match: { - $and: [ - await getOrganismeRestriction(organismeId), - await getOrganismeIndicateursEffectifsRestriction(ctx), - ...buildMongoFilters(filters, effectifsFiltersConfigurations), - ], + $and: [await getOrganismeRestriction(organismeId), await getOrganismeIndicateursEffectifsRestriction(ctx)], + ...buildEffectifMongoFilters(filters), "_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables }, }, @@ -649,11 +636,8 @@ export async function getEffectifsNominatifs( .aggregate([ { $match: { - $and: [ - await getOrganismeRestriction(organismeId), - permissionRestriction, - ...buildMongoFilters(filters, fullEffectifsFiltersConfigurations), - ], + $and: [await getOrganismeRestriction(organismeId), permissionRestriction], + ...buildEffectifMongoFilters(filters), "_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables et à modifier si on veut masquer les effectifs des OF inconnus }, }, @@ -798,17 +782,14 @@ export async function getEffectifsNominatifs( export async function getOrganismeIndicateursEffectifs( ctx: AuthContext, organismeId: ObjectId, - filters: EffectifsFilters + filters: EffectifsFiltersTerritoire ): Promise { const indicateurs = (await effectifsDb() .aggregate([ { $match: { - $and: [ - await getOrganismeRestriction(organismeId), - await getOrganismeIndicateursEffectifsRestriction(ctx), - ...buildMongoFilters(filters, effectifsFiltersConfigurations), - ], + $and: [await getOrganismeRestriction(organismeId), await getOrganismeIndicateursEffectifsRestriction(ctx)], + ...buildEffectifMongoFilters(filters), }, }, { diff --git a/server/src/common/actions/indicateurs/organismes/organismes-filters.ts b/server/src/common/actions/indicateurs/organismes/organismes-filters.ts new file mode 100644 index 000000000..de789de55 --- /dev/null +++ b/server/src/common/actions/indicateurs/organismes/organismes-filters.ts @@ -0,0 +1,29 @@ +import { Filter } from "mongodb"; +import { assertUnreachable, entries } from "shared"; + +import { Organisme } from "@/common/model/@types"; + +import { TerritoireFilters } from "../../helpers/filters"; + +export function buildOrganismeMongoFilters(filters: TerritoireFilters): Filter { + return entries(filters).reduce((acc: Filter, [key, value]) => { + switch (key) { + case "organisme_regions": + acc["adresse.region"] = { $in: value }; + break; + case "organisme_departements": + acc["adresse.departement"] = { $in: value }; + break; + case "organisme_academies": + acc["adresse.academie"] = { $in: value }; + break; + case "organisme_bassinsEmploi": + acc["adresse.bassinEmploi"] = { $in: value }; + break; + default: + assertUnreachable(key); + } + + return acc; + }, {}); +} diff --git a/server/src/http/server.ts b/server/src/http/server.ts index 9cb1f1276..387b6ba14 100644 --- a/server/src/http/server.ts +++ b/server/src/http/server.ts @@ -25,9 +25,9 @@ import { import { getEffectifForm, updateEffectifFromForm } from "@/common/actions/effectifs.actions"; import { getDuplicatesEffectifsForOrganismeId } from "@/common/actions/effectifs.duplicates.actions"; import { - effectifsFiltersSchema, + effectifsFiltersTerritoireSchema, fullEffectifsFiltersSchema, - organismesFiltersSchema, + territoireFiltersSchema, } from "@/common/actions/helpers/filters"; import { getPermissionOrganisationContext } from "@/common/actions/helpers/permissions-organisation"; import { getOrganismePermission } from "@/common/actions/helpers/permissions-organisme"; @@ -445,7 +445,7 @@ function setupRoutes(app: Application) { "/indicateurs/effectifs", requireOrganismePermission("indicateursEffectifs"), returnResult(async (req, res) => { - const filters = await validateFullZodObjectSchema(req.query, effectifsFiltersSchema); + const filters = await validateFullZodObjectSchema(req.query, effectifsFiltersTerritoireSchema); return await getOrganismeIndicateursEffectifs(req.user, res.locals.organismeId, filters); }) ) @@ -615,7 +615,7 @@ function setupRoutes(app: Application) { .get( "/api/v1/indicateurs/effectifs/par-departement", returnResult(async (req) => { - const filters = await validateFullZodObjectSchema(req.query, effectifsFiltersSchema); + const filters = await validateFullZodObjectSchema(req.query, effectifsFiltersTerritoireSchema); return await getIndicateursEffectifsParDepartement(req.user, filters); }) ) @@ -642,7 +642,7 @@ function setupRoutes(app: Application) { .get( "/api/v1/indicateurs/organismes/par-departement", returnResult(async (req) => { - const filters = await validateFullZodObjectSchema(req.query, organismesFiltersSchema); + const filters = await validateFullZodObjectSchema(req.query, territoireFiltersSchema); return await getIndicateursOrganismesParDepartement(req.user, filters); }) ) diff --git a/server/tests/integration/common/actions/helpers/filters.test.ts b/server/tests/integration/common/actions/helpers/filters.test.ts deleted file mode 100644 index 1411e322b..000000000 --- a/server/tests/integration/common/actions/helpers/filters.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { strict as assert } from "assert"; - -import { buildMongoFilters, fullEffectifsFiltersConfigurations } from "@/common/actions/helpers/filters"; - -const currentDate = new Date("2023-02-14T10:00:00Z"); - -describe("Filtres Indicateurs", () => { - describe("buildMongoFilters()", () => { - it("Gère le filtre date uniquement", () => { - const stages = buildMongoFilters( - { - date: currentDate, - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - ]); - }); - - it("Gère le filtre organisme_departements", () => { - const stages = buildMongoFilters( - { - date: currentDate, - organisme_departements: ["56"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "_computed.organisme.departement": { - $in: ["56"], - }, - }, - ]); - }); - - it("Gère le filtre organisme_regions", () => { - const stages = buildMongoFilters( - { - date: currentDate, - organisme_regions: ["25"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "_computed.organisme.region": { - $in: ["25"], - }, - }, - ]); - }); - - it("Gère le filtre organisme_reseaux", () => { - const stages = buildMongoFilters( - { - date: currentDate, - organisme_reseaux: ["AGRI"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "_computed.organisme.reseaux": { - $in: ["AGRI"], - }, - }, - ]); - }); - - it("Gère le filtre formation_cfds", () => { - const stages = buildMongoFilters( - { - date: currentDate, - formation_cfds: ["25021000"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "formation.cfd": { - $in: ["25021000"], - }, - }, - ]); - }); - - it("Gère le filtre formation_niveaux", () => { - const stages = buildMongoFilters( - { - date: currentDate, - formation_niveaux: ["2"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "formation.niveau": { - $in: ["2"], - }, - }, - ]); - }); - - it("Gère tous les filtres en même temps", () => { - const stages = buildMongoFilters( - { - date: currentDate, - organisme_regions: ["25"], - organisme_departements: ["56"], - organisme_reseaux: ["AGRI"], - formation_cfds: ["25021000"], - formation_niveaux: ["2"], - }, - fullEffectifsFiltersConfigurations - ); - assert.deepStrictEqual(stages, [ - { - annee_scolaire: { - $in: ["2023-2023", "2022-2023"], - }, - }, - { - "_computed.organisme.region": { - $in: ["25"], - }, - }, - { - "_computed.organisme.departement": { - $in: ["56"], - }, - }, - { - "_computed.organisme.reseaux": { - $in: ["AGRI"], - }, - }, - { - "formation.cfd": { - $in: ["25021000"], - }, - }, - { - "formation.niveau": { - $in: ["2"], - }, - }, - ]); - }); - }); -}); diff --git a/shared/utils/tsHelper.ts b/shared/utils/tsHelper.ts index 8820f9f32..60d33eef7 100644 --- a/shared/utils/tsHelper.ts +++ b/shared/utils/tsHelper.ts @@ -1,11 +1,13 @@ -export function throwUnexpectedError(): never { - throw new Error("Unexpected Error"); +export function throwUnexpectedError(message: string = "Unexpected Error"): never { + throw new Error(message); } -export function assertUnreachable(_key: never): never { - throwUnexpectedError(); +export function assertUnreachable(key: never): never { + throwUnexpectedError(`Unexpected case ${JSON.stringify(key)}`); } +export function ignoretUnreachable(_key: never): void {} + type ObjectEntry = { [K in keyof T]: [K, Required[K]] }[keyof T] extends infer E ? E extends [infer K, infer V] ? K extends string | number