diff --git a/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.spec.ts b/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.spec.ts index 27f759b6..a1e325dc 100644 --- a/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.spec.ts +++ b/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.spec.ts @@ -7,6 +7,7 @@ import { ModaliteAccompagnement, PriseEnChargeSpecifique, PublicSpecifiquementAdresse, + SchemaLieuMediationNumerique, Service, Typologie } from '@gouvfr-anct/lieux-de-mediation-numerique'; @@ -170,6 +171,26 @@ describe('output', (): void => { ); }); + it('should convert schema de la médiation numérique single data to CSV with extra field out of schema', (): void => { + const csv: string = mediationNumeriqueToCsv([ + { + adresse: '51 rue de la république', + code_postal: '75013', + commune: 'Paris', + date_maj: '2022-11-07', + id: 'structure-2', + nom: 'Médiation république', + pivot: '43497452600012', + extraField: 'extra' + } as SchemaLieuMediationNumerique + ]); + + expect(csv).toBe( + '"id","pivot","nom","commune","code_postal","code_insee","adresse","complement_adresse","latitude","longitude","typologie","telephone","courriels","site_web","horaires","presentation_resume","presentation_detail","source","itinerance","structure_parente","date_maj","services","publics_specifiquement_adresses","prise_en_charge_specifique","frais_a_charge","dispositif_programmes_nationaux","formations_labels","autres_formations_labels","modalites_acces","modalites_accompagnement","fiche_acces_libre","prise_rdv","extraField"\n' + + '"structure-2","43497452600012","Médiation république","Paris","75013",,"51 rue de la république",,,,,,,,,,,,,,"2022-11-07",,,,,,,,,,,,"extra"' + ); + }); + it('should convert schema de la médiation numérique single data to CSV with headers and no offset cause of double quote', (): void => { const csv: string = mediationNumeriqueToCsv([ { diff --git a/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.ts b/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.ts index e15f4b4f..d8655ff7 100644 --- a/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.ts +++ b/src/common/mediation-numerique/to-csv/mediation-numerique.to-csv.ts @@ -74,8 +74,27 @@ const fieldsArrayFrom = (lieuMediationNumerique: SchemaLieuMediationNumerique): export const csvLineFrom = (cells: (string | undefined)[]): string => cells.map(toDoubleQuoted).join(','); -const toLieuMediationNumeriqueCsvLine = (lieuMediationNumerique: SchemaLieuMediationNumerique): string => - csvLineFrom(fieldsArrayFrom(lieuMediationNumerique)); +const toExtraFieldValueFrom = + (lieuMediationNumerique: Record) => + (field: string): string => + String(lieuMediationNumerique[field]); -export const mediationNumeriqueToCsv = (lieuxMediationNumerique: SchemaLieuMediationNumerique[]): string => - `${csvLineFrom(HEADERS)}\n${lieuxMediationNumerique.map(toLieuMediationNumeriqueCsvLine).join('\n')}`; +const toLieuMediationNumeriqueCsvLine = + (extraFields: string[]) => + (lieuMediationNumerique: SchemaLieuMediationNumerique): string => + csvLineFrom([ + ...fieldsArrayFrom(lieuMediationNumerique), + ...extraFields.map(toExtraFieldValueFrom(lieuMediationNumerique)) + ]); + +const notInSchemaLieuMediationNumerique = (field: string) => !(HEADERS as string[]).includes(field); + +const toObjectFields = (fields: string[], obj: Record) => [...fields, ...Object.keys(obj)]; + +const extraFieldsFor = (lieuxMediationNumerique: SchemaLieuMediationNumerique[]): string[] => + Array.from(new Set(lieuxMediationNumerique.reduce(toObjectFields, []).filter(notInSchemaLieuMediationNumerique))); + +export const mediationNumeriqueToCsv = (lieuxMediationNumerique: SchemaLieuMediationNumerique[]): string => { + const extraFields: string[] = extraFieldsFor(lieuxMediationNumerique); + return `${csvLineFrom([...HEADERS, ...extraFields])}\n${lieuxMediationNumerique.map(toLieuMediationNumeriqueCsvLine(extraFields)).join('\n')}`; +};