Skip to content

Commit

Permalink
Merge pull request #198 from AgenceBio/maud/schema_validation_from_ty…
Browse files Browse the repository at this point in the history
…pescript

Refactoring et utilisation des types
  • Loading branch information
jillro committed Jun 13, 2024
2 parents ea345a5 + b0a945f commit c003482
Show file tree
Hide file tree
Showing 9 changed files with 1,089 additions and 518 deletions.
2 changes: 1 addition & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agencebio/cartobio-types",
"version": "1.6.1",
"version": "1.7.1",
"main": "types.d.ts",
"files": [
"**/*.d.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"numeroBio": "99999",
"data": {
"ocId": 1,
"ocLabel": "Ecocert France",
"auditDate": "2023-04-27T00:00:00.000Z",
"geojson": {
"record": {
"numerobio": "99999",
"oc_id": 1,
"oc_label": "Ecocert France",
"audit_date": "2023-04-27T00:00:00.000Z",
"parcelles": {
"type": "FeatureCollection",
"features": [
{
Expand Down
107 changes: 37 additions & 70 deletions lib/providers/cartobio.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,42 +77,25 @@ const evvClient = extend({
const recordFields = /* sqlFragment */`cartobio_operators.record_id, numerobio, version_name, certification_date_debut, certification_date_fin, certification_state, created_at, updated_at, oc_id, metadata, audit_date, audit_history, audit_notes, audit_demandes`

/**
* Create a new record unless we find a dangling one with the same numeroBio, in which case we update it
* Create a new record unless we find a dangling one with the same numeroBio and audit date, in which case we update it
* with the merge algorithm described in ../../docs/rfc/001-api-parcellaire.md
*
* @param {Object} data
* @param {String} data.numeroBio
* @param {Number} data.ocId
* @param {String} data.ocLabel
* @param {Object} [data.metadata]
* @param {import('geojson').FeatureCollection<Polygon|null, CartoBioFeatureProperties>} data.geojson
* @param {String} [data.certificationState]
* @param {String} [data.dateCertificationDebut]
* @param {String} [data.dateCertificationFin]
* @param {String} [data.notesAudit]
* @param {String} [data.versionName]
* @param {Partial<NormalizedRecord>} record
* @param {Object} [context]
* @param {CartoBioUser} [context.user]
* @param {NormalizedRecord} [context.oldRecord]
* @param {Date} [context.date]
* @param {Boolean} [context.copyParcellesData]
* @param {import('pg').PoolClient} [customClient]
* @returns {Promise<DBOperatorRecord>}
*/
async function createOrUpdateOperatorRecord (data, context, customClient) {
const { user, oldRecord } = context || {}
const { numeroBio, ocId, ocLabel, metadata, geojson, notesAudit, versionName, dateCertificationDebut, dateCertificationFin } = data

const certificationState = data.certificationState || CertificationState.OPERATOR_DRAFT
async function createOrUpdateOperatorRecord (record, context = {}, customClient) {
const certificationState = record.certification_state || CertificationState.OPERATOR_DRAFT

/** @type {HistoryEntry} */
const historyEntry = createNewEvent(
EventType.FEATURE_COLLECTION_CREATE,
{ features: geojson.features, state: certificationState, metadata, date: context.date },
{ user, record: oldRecord }
{ features: record.parcelles.features, state: certificationState, metadata: record.metadata, date: new Date() },
{ user: context?.user, record: null }
)
// context.date is audit date if the source is API Parcellaire
const auditDate = metadata.source === 'API Parcellaire' ? context.date : null

let result = null
const client = customClient || await pool.connect()
Expand All @@ -137,23 +120,23 @@ async function createOrUpdateOperatorRecord (data, context, customClient) {
coalesce($11, cartobio_operators.audit_notes), coalesce($12, cartobio_operators.version_name))
RETURNING ${recordFields}`,
[
/* $1 */ numeroBio,
/* $2 */ ocId,
/* $3 */ ocLabel,
/* $1 */ record.numerobio,
/* $2 */ record.oc_id,
/* $3 */ record.oc_label,
/* $4 */ 'now',
/* $5 */ metadata,
/* $5 */ record.metadata,
/* $6 */ certificationState,
/* $7 */ dateCertificationDebut,
/* $8 */ dateCertificationFin,
/* $7 */ record.certification_date_debut,
/* $8 */ record.certification_date_fin,
/* $9 */ historyEntry,
/* $10 */ auditDate,
/* $11 */ notesAudit,
/* $12 */ versionName
/* $10 */ record.audit_date,
/* $11 */ record.audit_notes,
/* $12 */ record.version_name
]
)

const parcelles = []
for (let feature of geojson.features) {
for (let feature of record.parcelles.features) {
feature = populateWithMultipleCultures(feature)
if (!feature.geometry) {
const { rows: partialUpdateRows } = await client.query(
Expand Down Expand Up @@ -222,7 +205,7 @@ async function createOrUpdateOperatorRecord (data, context, customClient) {
reference_cadastre)
VALUES ($1, $2, $3, $4, coalesce((SELECT cultures FROM merged_cultures), $5, '[]'::jsonb),
coalesce(NULLIF($6, 'AB?'), (SELECT conversion_niveau FROM previous_version), $6),
nullif(coalesce($7::date, (SELECT engagement_date FROM previous_version))::text, '')::date, $8,
nullif(coalesce($7::text, (SELECT engagement_date FROM previous_version)::text), '')::date, $8,
coalesce($9,(SELECT auditeur_notes FROM previous_version)),
coalesce($10, '[]'::jsonb),
now(), now(), coalesce(NULLIF($11, ''), (SELECT name FROM previous_version)), $12, $13, $14, $15)
Expand All @@ -233,7 +216,7 @@ async function createOrUpdateOperatorRecord (data, context, customClient) {
reference_cadastre) =
(coalesce($3, cartobio_parcelles.geometry), coalesce($4, cartobio_parcelles.commune),
coalesce($5, cartobio_parcelles.cultures), coalesce($6, cartobio_parcelles.conversion_niveau),
nullif(coalesce($7, cartobio_parcelles.engagement_date)::text, '')::date,
nullif(coalesce($7::text, cartobio_parcelles.engagement_date::text), '')::date,
coalesce($8, cartobio_parcelles.commentaire),
coalesce($9, cartobio_parcelles.auditeur_notes), coalesce($10, cartobio_parcelles.annotations),
now(), coalesce($11, cartobio_parcelles.name), coalesce($12, cartobio_parcelles.numero_pacage),
Expand All @@ -257,7 +240,7 @@ async function createOrUpdateOperatorRecord (data, context, customClient) {
/* $14 */ feature.properties.NUMERO_P,
/* $15 */ feature.properties.cadastre,
/* $16 */ result.rows.at(0).numerobio,
/* $17 */ Boolean(context.copyParcellesData)
/* $17 */ Boolean(context?.copyParcellesData)
]
)
parcelles.push(rows.at(0))
Expand All @@ -270,7 +253,7 @@ async function createOrUpdateOperatorRecord (data, context, customClient) {
[result.rows.at(0).record_id, parcelles.map(({ id }) => id)]
)

if (context.copyParcellesData) {
if (context?.copyParcellesData) {
const addedParcelles = await client.query(
/* sql */`
INSERT INTO cartobio_parcelles
Expand Down Expand Up @@ -1107,12 +1090,7 @@ async function getDataGouvStats () {
* @generator
* @param {NodeJS.ReadableStream} stream - a Json Stream
* @param {{ organismeCertificateur: OrganismeCertificateur }} options
* @yields {{numeroBio: String, data: {
* ocId: Number,
* ocLabel: String,
* auditDate: Date,
* geojson: CartoBioFeatureCollection
* }, error: Error?}}
* @yields {{ record: Partial<NormalizedRecord>, error: Error?}}
*/
async function * parseAPIParcellaireStream (stream, { organismeCertificateur }) {
/**
Expand Down Expand Up @@ -1211,17 +1189,21 @@ async function * parseAPIParcellaireStream (stream, { organismeCertificateur })
continue
}

// emit a data structure similar to what `/v2/operator/:numeroBio/parcelles` consumes
yield {
numeroBio: String(record.numeroBio),
data: {
ocId: organismeCertificateur.id,
ocLabel: organismeCertificateur.nom,
notesAudit: record.commentaire,
dateCertificationDebut: record.dateCertificationDebut,
dateCertificationFin: record.dateCertificationFin,
auditDate: new Date(record.dateAudit),
geojson: featureCollection(features)
record: {
numerobio: String(record.numeroBio),
certification_state: CertificationState.CERTIFIED,
oc_id: organismeCertificateur.id,
oc_label: organismeCertificateur.nom,
parcelles: featureCollection(features),
audit_notes: record.commentaire,
certification_date_debut: record.dateCertificationDebut,
certification_date_fin: record.dateCertificationFin,
audit_date: (new Date(record.dateAudit)).toISOString(),
metadata: {
source: 'API Parcellaire',
sourceLastUpdate: new Date().toISOString()
}
}
}
}
Expand All @@ -1242,30 +1224,15 @@ async function parcellaireStreamToDb (stream, organismeCertificateur) {
await client.query('BEGIN;')

try {
for await (const { numeroBio, data, error } of generator) {
for await (const { record, error } of generator) {
count++
if (error) {
errors.push([count, error.message])
continue
}

try {
await createOrUpdateOperatorRecord({
numeroBio,
ocId: data.ocId,
ocLabel: data.ocLabel,
geojson: data.geojson,
certificationState: CertificationState.CERTIFIED,
dateCertificationDebut: data.dateCertificationDebut,
dateCertificationFin: data.dateCertificationFin,
notesAudit: data.notesAudit,
metadata: {
source: 'API Parcellaire',
sourceLastUpdate: new Date().toISOString()
}
}, {
date: data.auditDate || new Date()
}, client)
await createOrUpdateOperatorRecord(record, null, client)
} catch (e) {
if (e.code === 'INVALID_API_REQUEST') {
errors.push([count, e.message])
Expand Down
1 change: 1 addition & 0 deletions lib/providers/types/cartobio.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type DBOperatorRecord = {
created_at: string;
updated_at: string;
oc_id: number;
oc_label: string;
parcelles?: DBParcelle[];
metadata: any;
audit_history: HistoryEntry[];
Expand Down
Loading

0 comments on commit c003482

Please sign in to comment.