Skip to content

Commit

Permalink
Import fuse dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
amandinejacquelin committed Feb 6, 2025
1 parent 2d67d74 commit 8e0c449
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 47 deletions.
113 changes: 85 additions & 28 deletions backend/src/plans/fiches/import/import-plan-clean.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
Statut,
statutsEnumValues,
} from '@/backend/plans/fiches';
import Fuse from 'fuse.js';
import { TagEnum, TagType } from '@/backend/collectivites';
import {
PersonneImport,
TagImport,
} from '@/backend/plans/fiches/import/import-plan.dto';
import { getFuse } from '@/backend/utils/fuse/fuse.utils';

/** Regex to detect spaces */
const regexEspace = /\\t|\\r|\\n/;
Expand All @@ -34,6 +34,8 @@ const niveauxPriorites =

@Injectable()
export class ImportPlanCleanService {
private fuseInstances: Record<string, any> = {};

/**
* Clean a text
* @param text
Expand All @@ -58,7 +60,9 @@ export class ImportPlanCleanService {
const toReturn = parseInt(integer);
if (isNaN(toReturn)) {
throw new Error(
`Le montant ${String(integer)} est incorrect, les montants ne doivent contenir que des chiffres.`
`Le montant ${String(
integer
)} est incorrect, les montants ne doivent contenir que des chiffres.`
);
}
return toReturn;
Expand Down Expand Up @@ -120,19 +124,22 @@ export class ImportPlanCleanService {
* @param members
* @return list of user ids and tags
*/
persons(
async persons(
personnes: string | undefined,
existingTags: Set<TagImport>,
members: Record<string, string>
): PersonneImport[] {
if(!personnes) return [];
): Promise<PersonneImport[]> {
if (!personnes) return [];
const toReturn: PersonneImport[] = [];
const tab: string[] = String(personnes).split(regexSplit);
const fuse = new Fuse(Array.from(Object.keys(members)));
if (!this.fuseInstances.members) {
const Fuse = await getFuse();
this.fuseInstances.members = new Fuse(Array.from(Object.keys(members)));
}
for (const element of tab) {
const cleaned = this.text(element);
if (cleaned && !cleaned.match(regexSplit)) {
const found = fuse.search(cleaned)?.[0]?.item;
const found = this.fuseInstances.members.search(cleaned)?.[0]?.item;
let tag: TagImport | undefined;
let userId: string | undefined;
if (found) {
Expand Down Expand Up @@ -162,7 +169,7 @@ export class ImportPlanCleanService {
const toReturn: TagImport[] = [];
const tab: string[] = String(tags).split(regexSplit);
for (const element of tab) {
if(element && !element.match(regexSplit)) {
if (element && !element.match(regexSplit)) {
const tag = this.getOrCreateTag(
this.text(element, true),
tagType,
Expand Down Expand Up @@ -206,12 +213,15 @@ export class ImportPlanCleanService {
* @param cible
* @return cleaned "cible"
*/
cible(cible: string): Cible | undefined {
async cible(cible: string): Promise<Cible | undefined> {
if (!cible) return undefined;
const fuse = new Fuse(ciblesEnumValues);
if (!this.fuseInstances.cibles) {
const Fuse = await getFuse();
this.fuseInstances.cibles = new Fuse(ciblesEnumValues);
}
const cleaned = this.text(cible);
if (!cleaned) return undefined;
return fuse.search(cleaned)?.[0]?.item;
return this.fuseInstances.cibles.search(cleaned)?.[0]?.item;
}

/**
Expand All @@ -220,15 +230,20 @@ export class ImportPlanCleanService {
* @param effetsAttendus
* @return associated id
*/
effetAttendu(
async effetAttendu(
effetAttendu: string,
effetsAttendus: Record<string, number>
): number | undefined {
): Promise<number | undefined> {
if (!effetAttendu) return undefined;
const fuse = new Fuse(Array.from(Object.keys(effetsAttendus)));
if (!this.fuseInstances.effetsAttendus) {
const Fuse = await getFuse();
this.fuseInstances.effetsAttendus = new Fuse(
Array.from(Object.keys(effetsAttendus))
);
}
const cleaned = this.text(effetAttendu);
if (!cleaned) return undefined;
const found = fuse.search(cleaned)?.[0]?.item;
const found = this.fuseInstances.effetsAttendus.search(cleaned)?.[0]?.item;
if (!found) return undefined;
return effetsAttendus[found];
}
Expand All @@ -238,38 +253,52 @@ export class ImportPlanCleanService {
* @param participation
* @return cleaned "participation citoyenne"
*/
participation(participation: string): ParticipationCitoyenne | undefined {
async participation(
participation: string
): Promise<ParticipationCitoyenne | undefined> {
if (!participation) return undefined;
const fuse = new Fuse(participationCitoyenneEnumValues);
if (!this.fuseInstances.participation) {
const Fuse = await getFuse();
this.fuseInstances.participation = new Fuse(
participationCitoyenneEnumValues
);
}
const cleaned = this.text(participation);
if (!cleaned) return undefined;
return fuse.search(cleaned)?.[0]?.item;
return this.fuseInstances.participation.search(cleaned)?.[0]?.item;
}

/**
* Clean a "statut"
* @param statut
* @return cleaned "statut"
*/
statut(statut: string): Statut | undefined {
async statut(statut: string): Promise<Statut | undefined> {
if (!statut) return undefined;
const fuse = new Fuse(statutsEnumValues);
if (!this.fuseInstances.statut) {
const Fuse = await getFuse();
this.fuseInstances.statut = new Fuse(statutsEnumValues);
}
const cleaned = this.text(statut);
if (!cleaned) return undefined;
return fuse.search(cleaned)?.[0]?.item;
return this.fuseInstances.statut.search(cleaned)?.[0]?.item;
}

/**
* Clean a "niveau de priorite"
* @param priorite
* @return cleaned "niveau de priorite"
*/
priorite(priorite: string): Priorite | undefined {
async priorite(priorite: string): Promise<Priorite | undefined> {
if (!priorite) return undefined;
const fuse = new Fuse(niveauxPriorites);
if (!this.fuseInstances.niveauxPriorites) {
const Fuse = await getFuse();
this.fuseInstances.niveauxPriorites = new Fuse(niveauxPriorites);
}
const cleaned = this.text(priorite);
if (!cleaned) return undefined;
const found = fuse.search(cleaned)?.[0]?.item;
const found =
this.fuseInstances.niveauxPriorites.search(cleaned)?.[0]?.item;
if (!found) return undefined;
return (niveauxPrioritesSynonyme[found] || found) as Priorite;
}
Expand All @@ -280,17 +309,45 @@ export class ImportPlanCleanService {
* @param thematiques
* @return associated id
*/
thematique(
async thematique(
thematique: string,
thematiques: Record<string, number>
): number | undefined {
): Promise<number | undefined> {
if (!thematique) return undefined;
const fuse = new Fuse(Array.from(Object.keys(thematiques)));
if (!this.fuseInstances.thematiques) {
const Fuse = await getFuse();
this.fuseInstances.thematiques = new Fuse(
Array.from(Object.keys(thematiques))
);
}
const cleaned = this.text(thematique);
if (!cleaned) return undefined;
const found = fuse.search(cleaned)?.[0]?.item;
const found = this.fuseInstances.thematiques.search(cleaned)?.[0]?.item;
if (!found) return undefined;
return thematiques[found];
}

/**
* Clean a "sous-thematique"
* @param thematique
* @param thematiques
* @return associated id
*/
async sousThematique(
thematique: string,
thematiques: Record<string, number>
): Promise<number | undefined> {
if (!thematique) return undefined;
if (!this.fuseInstances.sousThematiques) {
const Fuse = await getFuse();
this.fuseInstances.sousThematiques = new Fuse(
Array.from(Object.keys(thematiques))
);
}
const cleaned = this.text(thematique);
if (!cleaned) return undefined;
const found = this.fuseInstances.sousThematiques.search(cleaned)?.[0]?.item;
if (!found) return undefined;
return thematiques[found];
}
}
50 changes: 31 additions & 19 deletions backend/src/plans/fiches/import/import-plan.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,23 @@ export class ImportPlanService {
const memoryData = await this.fetchData(collectiviteId, plan);

// Browse the file and retrieve the data
// Do not execute the code directly in 'eachRow' because it does not work with getFuse
const errors: string[] = [];
worksheet.eachRow(async (row, rowNumber) => {
if (rowNumber === 1 || rowNumber === 2) return; // Ignorer the header
const rows: ExcelJS.Row[] = [];
worksheet.eachRow((row) => {
rows.push(row);
});
for (const row of rows) {
const rowNumber = row.number;
if (rowNumber === 1 || rowNumber === 2) continue; // Ignorer the header
const rowData = row.values as any[];
rowData.shift(); // data start at [1]
try {
this.createAxes(rowData, plan, memoryData);
await this.createAxes(rowData, plan, memoryData);
} catch (e) {
errors.push(`Ligne ${rowNumber} : ${e as string}`);
}
});
}

if (errors.length > 0) {
throw new Error(`Erreur(s) rencontrée(s) dans le fichier Excel :
Expand Down Expand Up @@ -175,11 +181,11 @@ export class ImportPlanService {
* @param memory
* @private
*/
private createAxes(
private async createAxes(
rowData: any[],
plan: AxeImport,
memory: MemoryImport
): void {
): Promise<void> {
const axeNames = [
this.clean.text(rowData[columnIndexes[ColumnNames.Axe]], true),
this.clean.text(rowData[columnIndexes[ColumnNames.SousAxe]], true),
Expand All @@ -197,7 +203,7 @@ export class ImportPlanService {
}

const axeFiche = currentAxe ?? plan;
const fiche = this.createFiche(rowData, memory);
const fiche = await this.createFiche(rowData, memory);
if (fiche) {
axeFiche.fiches.push(fiche);
memory.fiches.add(fiche);
Expand Down Expand Up @@ -241,27 +247,28 @@ export class ImportPlanService {
* @param memory
* @private
*/
private createFiche(
private async createFiche(
rowData: any[],
memory: MemoryImport
): FicheImport | null {
): Promise<FicheImport | null> {
const title = this.clean.text(
rowData[columnIndexes[ColumnNames.TitreFicheAction]],
true
);
if (!title || title.includes('Champ obligatoire')) {
return null;
}
return {

const toReturn = {
titre: title,
description: this.clean.text(
rowData[columnIndexes[ColumnNames.Descriptif]]
),
thematique: this.clean.thematique(
thematique: await this.clean.thematique(
rowData[columnIndexes[ColumnNames.ThematiquePrincipale]],
memory.thematiques
),
sousThematique: this.clean.thematique(
sousThematique: await this.clean.sousThematique(
rowData[columnIndexes[ColumnNames.SousThematiques]],
memory.sousThematiques
),
Expand All @@ -270,11 +277,13 @@ export class ImportPlanService {
),
objectifs: this.clean.text(rowData[columnIndexes[ColumnNames.Objectifs]]),
indicateurs: undefined, // unavailable
resultats: this.clean.effetAttendu(
resultats: await this.clean.effetAttendu(
rowData[columnIndexes[ColumnNames.ResultatsAttendus]],
memory.effetsAttendu
),
cibles: this.clean.cible(rowData[columnIndexes[ColumnNames.Cibles]]),
cibles: await this.clean.cible(
rowData[columnIndexes[ColumnNames.Cibles]]
),
structures: this.clean.tags(
rowData[columnIndexes[ColumnNames.StructurePilote]],
TagEnum.Structure,
Expand All @@ -293,17 +302,17 @@ export class ImportPlanService {
TagEnum.Service,
memory.tags
),
pilotes: this.clean.persons(
pilotes: await this.clean.persons(
rowData[columnIndexes[ColumnNames.PersonnePilote]],
memory.tags,
memory.members
),
referents: this.clean.persons(
referents: await this.clean.persons(
rowData[columnIndexes[ColumnNames.EluReferent]],
memory.tags,
memory.members
),
participation: this.clean.participation(
participation: await this.clean.participation(
rowData[columnIndexes[ColumnNames.ParticipationCitoyenne]]
),
financements: this.clean.text(
Expand All @@ -313,8 +322,10 @@ export class ImportPlanService {
budget: this.clean.int(
rowData[columnIndexes[ColumnNames.BudgetPrevisionnel]]
),
statut: this.clean.statut(rowData[columnIndexes[ColumnNames.Statut]]),
priorite: this.clean.priorite(
statut: await this.clean.statut(
rowData[columnIndexes[ColumnNames.Statut]]
),
priorite: await this.clean.priorite(
rowData[columnIndexes[ColumnNames.NiveauPriorite]]
),
dateDebut: this.clean.date(rowData[columnIndexes[ColumnNames.DateDebut]]),
Expand All @@ -334,6 +345,7 @@ export class ImportPlanService {
),
annexes: undefined, // unavailable
};
return toReturn;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions backend/src/utils/fuse/fuse.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getFuse } from '@/backend/utils/fuse/fuse.utils';

test('should load Fuse', async () => {
const Fuse = await getFuse();
console.log(Fuse.version);
expect(Fuse).toBeDefined();
});
4 changes: 4 additions & 0 deletions backend/src/utils/fuse/fuse.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const getFuse = async () => {
const { default: Fuse } = await import('fuse.js');
return Fuse;
};

0 comments on commit 8e0c449

Please sign in to comment.