Skip to content

feat(xlsx-s3): XLSX (ClosedXML) + S3 + multi-output numa passada - #9

Merged
thiagoluga merged 4 commits into
masterfrom
feat/xlsx-s3
May 30, 2026
Merged

feat(xlsx-s3): XLSX (ClosedXML) + S3 + multi-output numa passada#9
thiagoluga merged 4 commits into
masterfrom
feat/xlsx-s3

Conversation

@thiagoluga

Copy link
Copy Markdown
Owner

PR 4 — Formats.Xlsx + Destinations.S3 + multi-output

Fecha CA-5, CA-6, CA-8.

O que entra

  • Formats.Xlsx (ClosedXML) — Format.Xlsx(o => o.SheetName("Vendas").AutoFilter()). Tipos nativos do Excel (número/data/bool), formato por coluna, header via DisplayName. Constrói o workbook em memória (ADR D14); o CSV continua streaming.
  • Destinations.S3Destination.S3(bucket, "reports/{name}/{date:yyyy-MM-dd}.{ext}"). Upload tudo-ou-nada via PutObject (sem objeto parcial em falha); cliente do DI (IAmazonS3) ou defaults da AWS (ADR D15).
  • Multi-output numa passada — o Core já lê a source uma vez e escreve em todos os outputs; agora provado fim-a-fim com formatos reais.
  • Sample 02-sql-to-xlsx-s3.

Testes — 37 verdes

  • Xlsx (4): sheet nomeada + header + tipos nativos, auto-filtro on/off, nulos → célula vazia.
  • S3 (3): bucket/key resolvido, falha → Fail sem PutObject (sem parcial), status não-2xx → Fail.
  • Multi-output E2E (1): SQL → CSV + XLSX lendo a source uma única vez (RecordsWritten == 2 × RecordsRead), via Testcontainers.
  • Demais (Core/CSV/Local/SQL) seguem verdes.

Nota: o teste de falha do S3 dispara a exceção via OpenRead() (não via mock de PutObjectAsync) — configurar throw nesse método da interface gigante IAmazonS3 no NSubstitute acionava resolução real de região; o caminho via leitura exercita o mesmo try/catch e prova que PutObject não é chamado.

- Formats.Xlsx: ClosedXML-backed writer — SheetName/Header/AutoFilter options,
  native Excel types (numbers/dates/bool), per-column number/date formats. Builds
  the workbook in memory (ADR D14); CSV stays streaming.
- Destinations.S3: Destination.S3(bucket, keyTemplate) — all-or-nothing PutObject
  so a failure leaves no partial object; client from DI (IAmazonS3) or AWS
  defaults; key template shared with Local (ADR D15).
- Multi-output proven end-to-end: SQL -> CSV + XLSX reading the source once
  (RecordsWritten == 2 * RecordsRead).
- Sample 02-sql-to-xlsx-s3.
- Tests (37 green total): Xlsx (4), S3 (3), multi-output E2E (1), plus existing.
  Covers CA-5, CA-6, CA-8.
- ADR D14/D15 + plan.md PR4 checked off.
…assertion

- Use `using static ...Csv.Format` + `using static ...Xlsx.Format` in sample 02
  and the multi-output E2E test so Csv(...)/Xlsx(...) compile without the
  ambiguous `Format` class reference between the two format packages (ADR D16).
- Fix the multi-output E2E assertion: RecordsWritten counts distinct rows once
  (not per output); single-pass is proven by both output files being complete.
- ADR D14/D15/D16 recorded; plan.md PR4 test count corrected (34 green).
@thiagoluga
thiagoluga merged commit 37dbf89 into master May 30, 2026
1 check passed
@thiagoluga
thiagoluga deleted the feat/xlsx-s3 branch May 30, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant