Skip to content

Commit

Permalink
SAVE
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasduteil committed Dec 18, 2024
1 parent 818bc54 commit a809688
Show file tree
Hide file tree
Showing 30 changed files with 493 additions and 280 deletions.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/identite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"scripts": {
"build": "tsc --project tsconfig.lib.json",
"clean": "rm -rf dist tsconfig*.tsbuildinfo",
"check": "npm run build -- --noEmit",
"dev": "npm run build -- --watch --preserveWatchOutput",
"test": "mocha"
Expand All @@ -44,7 +45,9 @@
],
"spec": "src/**/*.test.ts"
},
"dependencies": {},
"dependencies": {
"sql-template-tag": "^5.2.1"
},
"devDependencies": {
"@electric-sql/pglite": "^0.2.15",
"@gouvfr-lasuite/proconnect.core": "^0.2.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/identite/src/organization/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//

export * from "./upsert.js";
140 changes: 140 additions & 0 deletions packages/identite/src/organization/upsert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//

import type {
DatabaseContext,
Organization,
OrganizationInfo,
} from "#src/types";
import type { QueryResult } from "pg";

//

export function upsertFactory({ pg }: DatabaseContext) {
return async function upsert({
siret,
organizationInfo: {
libelle: cached_libelle,
nomComplet: cached_nom_complet,
enseigne: cached_enseigne,
trancheEffectifs: cached_tranche_effectifs,
trancheEffectifsUniteLegale: cached_tranche_effectifs_unite_legale,
libelleTrancheEffectif: cached_libelle_tranche_effectif,
etatAdministratif: cached_etat_administratif,
estActive: cached_est_active,
statutDiffusion: cached_statut_diffusion,
estDiffusible: cached_est_diffusible,
adresse: cached_adresse,
codePostal: cached_code_postal,
codeOfficielGeographique: cached_code_officiel_geographique,
activitePrincipale: cached_activite_principale,
libelleActivitePrincipale: cached_libelle_activite_principale,
categorieJuridique: cached_categorie_juridique,
libelleCategorieJuridique: cached_libelle_categorie_juridique,
},
}: {
siret: string;
organizationInfo: OrganizationInfo;
}) {
const { rows }: QueryResult<Organization> = await pg.query(
`
INSERT INTO organizations
(
siret,
cached_libelle,
cached_nom_complet,
cached_enseigne,
cached_tranche_effectifs,
cached_tranche_effectifs_unite_legale,
cached_libelle_tranche_effectif,
cached_etat_administratif,
cached_est_active,
cached_statut_diffusion,
cached_est_diffusible,
cached_adresse,
cached_code_postal,
cached_code_officiel_geographique,
cached_activite_principale,
cached_libelle_activite_principale,
cached_categorie_juridique,
cached_libelle_categorie_juridique,
organization_info_fetched_at,
updated_at,
created_at
)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)
ON CONFLICT (siret)
DO UPDATE
SET (
siret,
cached_libelle,
cached_nom_complet,
cached_enseigne,
cached_tranche_effectifs,
cached_tranche_effectifs_unite_legale,
cached_libelle_tranche_effectif,
cached_etat_administratif,
cached_est_active,
cached_statut_diffusion,
cached_est_diffusible,
cached_adresse,
cached_code_postal,
cached_code_officiel_geographique,
cached_activite_principale,
cached_libelle_activite_principale,
cached_categorie_juridique,
cached_libelle_categorie_juridique,
organization_info_fetched_at,
updated_at
) = (
EXCLUDED.siret,
EXCLUDED.cached_libelle,
EXCLUDED.cached_nom_complet,
EXCLUDED.cached_enseigne,
EXCLUDED.cached_tranche_effectifs,
EXCLUDED.cached_tranche_effectifs_unite_legale,
EXCLUDED.cached_libelle_tranche_effectif,
EXCLUDED.cached_etat_administratif,
EXCLUDED.cached_est_active,
EXCLUDED.cached_statut_diffusion,
EXCLUDED.cached_est_diffusible,
EXCLUDED.cached_adresse,
EXCLUDED.cached_code_postal,
EXCLUDED.cached_code_officiel_geographique,
EXCLUDED.cached_activite_principale,
EXCLUDED.cached_libelle_activite_principale,
EXCLUDED.cached_categorie_juridique,
EXCLUDED.cached_libelle_categorie_juridique,
EXCLUDED.organization_info_fetched_at,
EXCLUDED.updated_at
)
RETURNING *
`,
[
siret,
cached_libelle,
cached_nom_complet,
cached_enseigne,
cached_tranche_effectifs,
cached_tranche_effectifs_unite_legale,
cached_libelle_tranche_effectif,
cached_etat_administratif,
cached_est_active,
cached_statut_diffusion,
cached_est_diffusible,
cached_adresse,
cached_code_postal,
cached_code_officiel_geographique,
cached_activite_principale,
cached_libelle_activite_principale,
cached_categorie_juridique,
cached_libelle_categorie_juridique,
new Date(),
new Date(),
new Date(),
],
);

return rows.shift()!;
};
}
54 changes: 54 additions & 0 deletions packages/identite/src/organization/upset.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//

import { PGlite } from "@electric-sql/pglite";
import { expect } from "chai";
import { noop } from "lodash-es";
import { before, describe, it } from "mocha";
import { runner } from "node-pg-migrate";
import { join } from "path";
import { upsertFactory } from "./upsert.js";

//

const pg = new PGlite();
const upset = upsertFactory({ pg: pg as any });

before(async function migrate() {
await runner({
dbClient: pg as any,
dir: join(import.meta.dirname, "../../../../migrations"),
direction: "up",
migrationsTable: "pg-migrate",
log: noop,
});
});

describe("upset", () => {
it("should create the Tau Empire organization", async () => {
const organization = await upset({
organizationInfo: {
libelle: "Tau Empire",
nomComplet: "Tau Empire",
} as any,
siret: "👽️",
});
expect(organization.created_at).to.deep.equal(organization.updated_at);
});

it("should update the Necron organization", async () => {
await pg.sql`insert into organizations
(siret, created_at, updated_at)
VALUES
('⚰️', '1967-12-19', '1967-12-19');
`;
const organization = await upset({
organizationInfo: {
libelle: "Necron",
nomComplet: "Necrontyr",
} as any,
siret: "⚰️",
});
expect(organization.created_at).to.not.deep.equal(organization.updated_at);
expect(organization.cached_libelle).to.equal("Necron");
});
});
34 changes: 34 additions & 0 deletions packages/identite/src/services/hash-to-postgres-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//

import { chain } from "lodash-es";

//

export function hashToPostgresParams<T>(fieldsToUpdate: Partial<T>): {
// postgres column-list syntax
paramsString: string;
// postgres column-list syntax for prepared statement
valuesString: string;
values: any[];
} {
const paramsString = "(" + Object.keys(fieldsToUpdate).join(", ") + ")";
// 'email, encrypted_password'

const valuesString =
"(" +
chain(fieldsToUpdate)
// { email: '[email protected]', encrypted_password: 'hash' }
.toPairs()
// [[ 'email', '[email protected]'], ['encrypted_password', 'hash' ]]
.map((_value, index) => `$${index + 1}`)
// [ '$1', '$2' ]
.join(", ")
// '$1, $2'
.value() +
")";

const values = Object.values(fieldsToUpdate);
// [ '[email protected]', 'hash' ]

return { paramsString, valuesString, values };
}
3 changes: 3 additions & 0 deletions packages/identite/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//

export * from "./hash-to-postgres-params.js";
3 changes: 3 additions & 0 deletions packages/identite/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//

export * from "./contexts.js";
export * from "./organization-info.js";
export * from "./organization.js";
export * from "./tranche-effectifs.js";
export * from "./user.js";
26 changes: 26 additions & 0 deletions packages/identite/src/types/organization-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//

import type { TrancheEffectifs } from "./tranche-effectifs.js";

//

export interface OrganizationInfo {
siret: string;
libelle: string;
nomComplet: string;
enseigne: string;
trancheEffectifs: TrancheEffectifs;
trancheEffectifsUniteLegale: TrancheEffectifs;
libelleTrancheEffectif: string;
etatAdministratif: string;
estActive: boolean;
statutDiffusion: string;
estDiffusible: boolean;
adresse: string;
codePostal: string;
codeOfficielGeographique: string;
activitePrincipale: string;
libelleActivitePrincipale: string;
categorieJuridique: string;
libelleCategorieJuridique: string;
}
30 changes: 30 additions & 0 deletions packages/identite/src/types/organization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//

import type { TrancheEffectifs } from "./tranche-effectifs.js";

//

export interface Organization {
id: number;
siret: string;
created_at: Date;
updated_at: Date;
cached_libelle: string | null;
cached_nom_complet: string | null;
cached_enseigne: string | null;
cached_tranche_effectifs: TrancheEffectifs;
cached_tranche_effectifs_unite_legale: string | null;
cached_libelle_tranche_effectif: string | null;
cached_etat_administratif: string | null;
cached_est_active: string | null;
cached_statut_diffusion: string | null;
cached_est_diffusible: string | null;
cached_adresse: string | null;
cached_code_postal: string | null;
cached_code_officiel_geographique: string | null;
cached_activite_principale: string | null;
cached_libelle_activite_principale: string | null;
cached_categorie_juridique: string | null;
cached_libelle_categorie_juridique: string | null;
organization_info_fetched_at: Date | null;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// source : https://www.sirene.fr/sirene/public/variable/trancheEffectifsEtablissement
type TrancheEffectifs =
export type TrancheEffectifs =
// le champ peut être null bien que la documentation ne spécifie pas à quoi correspond ce cas
| null
// Etablissement non employeur (pas de salarié au cours de l'année de référence et pas d'effectif au 31/12)NN
Expand Down Expand Up @@ -34,24 +34,3 @@ type TrancheEffectifs =
| "52"
// 10 000 salariés et plus
| "53";

interface OrganizationInfo {
siret: string;
libelle: string;
nomComplet: string;
enseigne: string;
trancheEffectifs: TrancheEffectifs;
trancheEffectifsUniteLegale: TrancheEffectifs;
libelleTrancheEffectif: string;
etatAdministratif: string;
estActive: boolean;
statutDiffusion: string;
estDiffusible: boolean;
adresse: string;
codePostal: string;
codeOfficielGeographique: string;
activitePrincipale: string;
libelleActivitePrincipale: string;
categorieJuridique: string;
libelleCategorieJuridique: string;
}
Loading

0 comments on commit a809688

Please sign in to comment.