Adjust locality DwC export fields

This commit is contained in:
karilint
2026-04-28 13:42:35 +03:00
parent 30040eaeeb
commit ec4edd4699
3 changed files with 61 additions and 122 deletions
@@ -233,19 +233,6 @@ type LocalityForExport = Pick<
country: string | null country: string | null
} }
}> }>
now_plr: ReadonlyArray<{
now_proj: {
proj_code: string | null
proj_name: string | null
proj_status: string | null
}
}>
now_lau: ReadonlyArray<{
lau_date: Date | null
lau_comment: string | null
com_people_now_lau_lau_coordinatorTocom_people: { full_name: string }
com_people_now_lau_lau_authorizerTocom_people: { full_name: string }
}>
now_ls: ReadonlyArray<{ now_ls: ReadonlyArray<{
com_species: { com_species: {
order_name: string order_name: string
@@ -550,6 +537,20 @@ const LOCALITY_MEASUREMENT_MAPPINGS: Array<{
// TODO(#1150): Add controlled vocabulary / description. // TODO(#1150): Add controlled vocabulary / description.
measurementMethod: '', measurementMethod: '',
}, },
{
field: 'basin',
measurementType: 'basin',
measurementUnit: '',
// TODO(#1150): Add field description / controlled vocabulary.
measurementMethod: '',
},
{
field: 'subbasin',
measurementType: 'subbasin',
measurementUnit: '',
// TODO(#1150): Add field description / controlled vocabulary.
measurementMethod: '',
},
{ {
field: 'rock_type', field: 'rock_type',
measurementType: 'rock type', measurementType: 'rock type',
@@ -711,6 +712,20 @@ const LOCALITY_MEASUREMENT_MAPPINGS: Array<{
// TODO(#1150): Add controlled vocabulary. // TODO(#1150): Add controlled vocabulary.
measurementMethod: '', measurementMethod: '',
}, },
{
field: 'plant_pres',
measurementType: 'Plant Preservation',
measurementUnit: '',
// TODO(#1150): Add controlled vocabulary.
measurementMethod: '',
},
{
field: 'invert_pres',
measurementType: 'Invertebrate Preservation',
measurementUnit: '',
// TODO(#1150): Add controlled vocabulary.
measurementMethod: '',
},
{ {
field: 'taph_comm', field: 'taph_comm',
measurementType: 'Taphonomy comment', measurementType: 'Taphonomy comment',
@@ -951,8 +966,6 @@ export const mapLocalityToMeasurementRows = (locality: LocalityForExport): Local
const bosId = buildLocalityMeasurementId(lid, 'bos') const bosId = buildLocalityMeasurementId(lid, 'bos')
const datumPlaneId = buildLocalityMeasurementId(lid, 'datum_plane') const datumPlaneId = buildLocalityMeasurementId(lid, 'datum_plane')
const lastUpdateParentId = buildLocalityMeasurementId(lid, 'last_update')
const hasMaxAgeGroup = const hasMaxAgeGroup =
isMeaningfulMeasurementValue(locality.max_age) || isMeaningfulMeasurementValue(locality.max_age) ||
isMeaningfulMeasurementValue(locality.bfa_max) || isMeaningfulMeasurementValue(locality.bfa_max) ||
@@ -1036,68 +1049,6 @@ export const mapLocalityToMeasurementRows = (locality: LocalityForExport): Local
} }
} }
const lastUpdate = locality.now_lau[0]
if (lastUpdate) {
rows.push({
taxonID,
measurementID: lastUpdateParentId,
parentMeasurementID: '',
measurementType: 'last update',
verbatimMeasurementType: 'now_lau',
measurementValue: '',
measurementUnit: '',
measurementMethod: '',
})
if (lastUpdate.lau_date) {
rows.push({
taxonID,
measurementID: buildLocalityMeasurementId(lid, 'last_update_date'),
parentMeasurementID: lastUpdateParentId,
measurementType: 'last update date',
verbatimMeasurementType: 'now_lau.lau_date',
measurementValue: lastUpdate.lau_date.toISOString().slice(0, 10),
measurementUnit: '',
measurementMethod: '',
})
}
rows.push({
taxonID,
measurementID: buildLocalityMeasurementId(lid, 'last_update_coordinator'),
parentMeasurementID: lastUpdateParentId,
measurementType: 'last update coordinator',
verbatimMeasurementType: 'now_lau.lau_coordinator',
measurementValue: toMaybeMeaningful(lastUpdate.com_people_now_lau_lau_coordinatorTocom_people.full_name),
measurementUnit: '',
measurementMethod: '',
})
rows.push({
taxonID,
measurementID: buildLocalityMeasurementId(lid, 'last_update_authorizer'),
parentMeasurementID: lastUpdateParentId,
measurementType: 'last update authorizer',
verbatimMeasurementType: 'now_lau.lau_authorizer',
measurementValue: toMaybeMeaningful(lastUpdate.com_people_now_lau_lau_authorizerTocom_people.full_name),
measurementUnit: '',
measurementMethod: '',
})
if (isMeaningfulString(lastUpdate.lau_comment)) {
rows.push({
taxonID,
measurementID: buildLocalityMeasurementId(lid, 'last_update_comment'),
parentMeasurementID: lastUpdateParentId,
measurementType: 'last update comment',
verbatimMeasurementType: 'now_lau.lau_comment',
measurementValue: lastUpdate.lau_comment.trim(),
measurementUnit: '',
measurementMethod: '',
})
}
}
if (hasAnyAgeBasis) { if (hasAnyAgeBasis) {
rows.push({ rows.push({
taxonID, taxonID,
@@ -1214,34 +1165,6 @@ export const mapLocalityToMeasurementRows = (locality: LocalityForExport): Local
}) })
} }
const projects = locality.now_plr
.map(row => row.now_proj)
.map(project =>
[
toMaybeMeaningful(project.proj_code),
toMaybeMeaningful(project.proj_name),
toMaybeMeaningful(project.proj_status),
]
.filter(Boolean)
.join(' - ')
)
.filter(isMeaningfulString)
.map(value => value.trim())
if (projects.length) {
rows.push({
taxonID,
measurementID: buildLocalityMeasurementId(lid, 'projects'),
parentMeasurementID: '',
measurementType: 'Projects',
verbatimMeasurementType: 'now_plr.pid',
measurementValue: projects.join('|'),
measurementUnit: '',
// TODO(#1150): Add field description.
measurementMethod: '',
})
}
const collectingMethods = locality.now_coll_meth const collectingMethods = locality.now_coll_meth
.map(method => method.coll_meth) .map(method => method.coll_meth)
.filter(value => isMeaningfulString(value)) .filter(value => isMeaningfulString(value))
@@ -1599,21 +1522,6 @@ export const buildDwcLocalityArchiveZipBuffer = async (): Promise<Buffer> => {
com_mlist: { select: { institution: true, alt_int_name: true, city: true, state: true, country: true } }, com_mlist: { select: { institution: true, alt_int_name: true, city: true, state: true, country: true } },
}, },
}, },
now_plr: {
select: {
now_proj: { select: { proj_code: true, proj_name: true, proj_status: true } },
},
},
now_lau: {
take: 1,
orderBy: { lau_date: 'desc' },
select: {
lau_date: true,
lau_comment: true,
com_people_now_lau_lau_coordinatorTocom_people: { select: { full_name: true } },
com_people_now_lau_lau_authorizerTocom_people: { select: { full_name: true } },
},
},
now_ls: { now_ls: {
select: { select: {
com_species: { com_species: {
@@ -112,8 +112,6 @@ describe('DwC-A locality export mapping', () => {
now_ss: [], now_ss: [],
now_coll_meth: [], now_coll_meth: [],
now_mus: [], now_mus: [],
now_plr: [],
now_lau: [],
now_ls: [], now_ls: [],
now_time_unit_now_loc_bfa_maxTonow_time_unit: null, now_time_unit_now_loc_bfa_maxTonow_time_unit: null,
now_time_unit_now_loc_bfa_minTonow_time_unit: null, now_time_unit_now_loc_bfa_minTonow_time_unit: null,
@@ -158,6 +156,37 @@ describe('DwC-A locality export mapping', () => {
expect(rows.some(r => r.verbatimMeasurementType === 'bfa_min')).toEqual(false) expect(rows.some(r => r.verbatimMeasurementType === 'bfa_min')).toEqual(false)
}) })
it('exports requested locality fields and omits project and last-update rows', () => {
const rows = mapLocalityToMeasurementRows({
...baseLocality,
basin: 'Basin value',
subbasin: 'Subbasin value',
bipedal_footprints: true,
invert_pres: 'Invert preservation',
nutrients: 'High',
pers_pollen_ap: 10,
pers_pollen_nap: 20,
pers_pollen_other: 0,
plant_pres: 'Plant preservation',
})
expect(rows).toEqual(
expect.arrayContaining([
expect.objectContaining({ verbatimMeasurementType: 'basin', measurementValue: 'Basin value' }),
expect.objectContaining({ verbatimMeasurementType: 'subbasin', measurementValue: 'Subbasin value' }),
expect.objectContaining({ verbatimMeasurementType: 'bipedal_footprints', measurementValue: 'true' }),
expect.objectContaining({ verbatimMeasurementType: 'invert_pres', measurementValue: 'Invert preservation' }),
expect.objectContaining({ verbatimMeasurementType: 'nutrients', measurementValue: 'High' }),
expect.objectContaining({ verbatimMeasurementType: 'pers_pollen_ap', measurementValue: '10' }),
expect.objectContaining({ verbatimMeasurementType: 'pers_pollen_nap', measurementValue: '20' }),
expect.objectContaining({ verbatimMeasurementType: 'pers_pollen_other', measurementValue: '0' }),
expect.objectContaining({ verbatimMeasurementType: 'plant_pres', measurementValue: 'Plant preservation' }),
])
)
expect(rows.some(r => r.verbatimMeasurementType.startsWith('now_plr'))).toEqual(false)
expect(rows.some(r => r.verbatimMeasurementType.startsWith('now_lau'))).toEqual(false)
})
it('concatenates collecting methods with |', () => { it('concatenates collecting methods with |', () => {
const rows = mapLocalityToMeasurementRows({ const rows = mapLocalityToMeasurementRows({
...baseLocality, ...baseLocality,
@@ -67,6 +67,8 @@ Concatenation rules (v1):
Field coverage (v1): Field coverage (v1):
- Fossil Assemblage, Taphonomy, Climate, Ecometrics, and Archaeology tab fields are exported as `MeasurementOrFact` rows when populated (plus selected calculated values such as mean hypsodonty). - Fossil Assemblage, Taphonomy, Climate, Ecometrics, and Archaeology tab fields are exported as `MeasurementOrFact` rows when populated (plus selected calculated values such as mean hypsodonty).
- `basin` and `subbasin` are exported both as part of `higherGeography` and as explicit `MeasurementOrFact` rows.
- `now_plr` project links and `now_lau` last-update rows are intentionally excluded.
## Admin-only ## Admin-only