feat(C155): fallback de listagem desce ao mês quando o ano inteiro falha

This commit is contained in:
Francisco Solla 2026-09-13 17:35:35 -03:00
parent 2040c98654
commit b86c108754
3 changed files with 49 additions and 19 deletions

View file

@ -245,9 +245,10 @@ async function fetchSpeechesRange(deputyId, from, to) {
/**
* Lista a faixa inteira; se a API recusar uma página funda (500/hang
* persistente, visto na 55ª em 2026-09-13), cai para a listagem por ano — cada
* chunk é raso e um ano quebrado não derruba os demais. Os chunks que falharem
* são reportados via `onWarning` (o run os registra como falha de `list`).
* persistente, visto na 55ª em 2026-09-13), cai para a listagem por ano e,
* se um ano inteiro falhar, desce ao mês — cada chunk é raso e um mês
* quebrado não derruba os demais. Os chunks que falharem são reportados via
* `onWarning` (o run os registra como falha de `list`).
*/
async function fetchSpeeches(deputyId, from, to, onWarning = () => {}) {
try {
@ -256,12 +257,21 @@ async function fetchSpeeches(deputyId, from, to, onWarning = () => {}) {
onWarning(`listagem ${from}..${to} falhou (${error?.message}); tentando por ano`)
const speeches = []
let listedChunks = 0
for (const [chunkFrom, chunkTo] of dateRangeChunks(from, to)) {
for (const [yearFrom, yearTo] of dateRangeChunks(from, to)) {
try {
speeches.push(...(await fetchSpeechesRange(deputyId, chunkFrom, chunkTo)))
speeches.push(...(await fetchSpeechesRange(deputyId, yearFrom, yearTo)))
listedChunks += 1
} catch (chunkError) {
onWarning(`listagem ${chunkFrom}..${chunkTo} falhou: ${chunkError?.message}`)
continue
} catch (yearError) {
onWarning(`listagem ${yearFrom}..${yearTo} falhou: ${yearError?.message}; tentando por mês`)
}
for (const [monthFrom, monthTo] of dateRangeChunks(yearFrom, yearTo, 'month')) {
try {
speeches.push(...(await fetchSpeechesRange(deputyId, monthFrom, monthTo)))
listedChunks += 1
} catch (monthError) {
onWarning(`listagem ${monthFrom}..${monthTo} falhou: ${monthError?.message}`)
}
}
}
if (listedChunks === 0) throw error

View file

@ -399,27 +399,36 @@ export const normalizeTranscription = (json) => {
}
}
const isIsoDate = (value) => /^\d{4}-\d{2}-\d{2}$/.test(String(value))
/**
* Splits an inclusive `YYYY-MM-DD` range into calendar-year chunks (no
* overlap; first/last partial). The backfill fallback uses it when the API
* refuses a deep page: a shallow per-year listing still recovers the years
* the broken offset does not cover.
* Splits an inclusive `YYYY-MM-DD` range into calendar chunks (no overlap;
* first/last partial) at `unit` granularity. The backfill fallback uses it
* when the API refuses a deep page: a shallow per-year listing still recovers
* the years the broken offset does not cover, and a broken year is isolated
* down to the month.
*
* @param {string} from
* @param {string} to
* @param {'year' | 'month'} unit
* @returns {Array<[string, string]>}
*/
export const dateRangeChunks = (from, to) => {
export const dateRangeChunks = (from, to, unit = 'year') => {
const chunks = []
if (!/^\d{4}-\d{2}-\d{2}$/.test(String(from)) || !/^\d{4}-\d{2}-\d{2}$/.test(String(to))) {
return chunks
}
if (!isIsoDate(from) || !isIsoDate(to)) return chunks
let start = String(from)
while (start <= String(to)) {
const yearEnd = `${start.slice(0, 4)}-12-31`
const end = yearEnd < String(to) ? yearEnd : String(to)
chunks.push([start, end])
const next = new Date(`${end}T00:00:00Z`)
const end =
unit === 'month'
? `${start.slice(0, 7)}-${String(
new Date(
Date.UTC(Number(start.slice(0, 4)), Number(start.slice(5, 7)), 0),
).getUTCDate(),
).padStart(2, '0')}`
: `${start.slice(0, 4)}-12-31`
const boundedEnd = end < String(to) ? end : String(to)
chunks.push([start, boundedEnd])
const next = new Date(`${boundedEnd}T00:00:00Z`)
next.setUTCDate(next.getUTCDate() + 1)
start = next.toISOString().slice(0, 10)
}

View file

@ -656,4 +656,15 @@ describe('dateRangeChunks', () => {
expect(dateRangeChunks('2023-1-1', '2023-12-31')).toEqual([])
expect(dateRangeChunks('', '2023-12-31')).toEqual([])
})
it('splits by month when asked, with the right month length', () => {
expect(dateRangeChunks('2018-01-01', '2018-03-15', 'month')).toEqual([
['2018-01-01', '2018-01-31'],
['2018-02-01', '2018-02-28'],
['2018-03-01', '2018-03-15'],
])
expect(dateRangeChunks('2024-02-01', '2024-02-29', 'month')).toEqual([
['2024-02-01', '2024-02-29'],
])
})
})