mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
94 lines
2.8 KiB
JavaScript
94 lines
2.8 KiB
JavaScript
/**
|
|
* IBGE baseline for the C186 dossiê (owner of the programmatic municipal
|
|
* context). Fetches the sourced population baseline used as the municipal
|
|
* denominator ("leitura relativa" — never an absolute state share). SIOPS/CNES
|
|
* health-execution series are not JSON APIs; they stay a per-era research task
|
|
* and degrade to an explicit gap when absent.
|
|
*
|
|
* `fetchImpl` is injectable so the unit tests never touch the network.
|
|
*/
|
|
|
|
import { formatInteger } from './cityReportFormat.mjs'
|
|
|
|
const SIDRA_BASE = 'https://apisidra.ibge.gov.br/values'
|
|
const CENSUS_YEAR = 2022
|
|
|
|
export const sidraPopulationUrl = (ibgeCode, year = CENSUS_YEAR) =>
|
|
`${SIDRA_BASE}/t/9514/n6/${ibgeCode}/v/93/p/${year}`
|
|
|
|
/** SIDRA `/values` returns a header row first; the datum is `payload[1].V`. */
|
|
export const parseSidraValue = (payload) => {
|
|
if (!Array.isArray(payload) || payload.length < 2) return null
|
|
const raw = String(payload[1]?.V ?? '').replace(/[^\d-]/g, '')
|
|
if (raw === '') return null
|
|
const value = Number(raw)
|
|
return Number.isFinite(value) ? value : null
|
|
}
|
|
|
|
const gap = ({ reason, sourceUrl, consultedAt }) => ({
|
|
status: 'gap',
|
|
reason,
|
|
items: [],
|
|
sourceUrl,
|
|
consultedAt,
|
|
})
|
|
|
|
/**
|
|
* @param {{
|
|
* ibgeCode?: string | null,
|
|
* fetchImpl?: typeof fetch,
|
|
* now?: Date,
|
|
* year?: number,
|
|
* }} [options]
|
|
* @returns {Promise<{ status: 'ok'|'gap', items: Array<{topic: string, detail: string, value: number, year: string, sourceUrl: string, sourceDate: string}>, reason: string|null, sourceUrl: string|null, consultedAt: string }>}
|
|
*/
|
|
export const fetchHealthData = async ({
|
|
ibgeCode = null,
|
|
fetchImpl = fetch,
|
|
now = new Date(),
|
|
year = CENSUS_YEAR,
|
|
} = {}) => {
|
|
const consultedAt = now.toISOString()
|
|
if (!ibgeCode) {
|
|
return gap({
|
|
reason: 'Município sem código IBGE no snapshot — contexto não consultado.',
|
|
sourceUrl: null,
|
|
consultedAt,
|
|
})
|
|
}
|
|
const sourceUrl = sidraPopulationUrl(ibgeCode, year)
|
|
try {
|
|
const response = await fetchImpl(sourceUrl)
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
const population = parseSidraValue(await response.json())
|
|
if (population === null) {
|
|
return gap({
|
|
reason: 'SIDRA não devolveu valor de população para o município.',
|
|
sourceUrl,
|
|
consultedAt,
|
|
})
|
|
}
|
|
return {
|
|
status: 'ok',
|
|
reason: null,
|
|
sourceUrl,
|
|
consultedAt,
|
|
items: [
|
|
{
|
|
topic: `População residente (Censo ${year})`,
|
|
detail: `${formatInteger(population)} habitantes`,
|
|
value: population,
|
|
year: String(year),
|
|
sourceUrl,
|
|
sourceDate: consultedAt.slice(0, 10),
|
|
},
|
|
],
|
|
}
|
|
} catch (error) {
|
|
return gap({
|
|
reason: `Falha ao consultar o IBGE/SIDRA: ${error instanceof Error ? error.message : error}`,
|
|
sourceUrl,
|
|
consultedAt,
|
|
})
|
|
}
|
|
}
|