Skip to content

feat(core): B1.2 — sectioned-output hook (one file, many sections) - #66

Merged
thiagoluga merged 3 commits into
masterfrom
feat/b1-2a-sectioned-output-hook
Jul 1, 2026
Merged

feat(core): B1.2 — sectioned-output hook (one file, many sections)#66
thiagoluga merged 3 commits into
masterfrom
feat/b1-2a-sectioned-output-hook

Conversation

@thiagoluga

Copy link
Copy Markdown
Owner

The OSS/MIT enabling piece for the Pro workbook. A single output can now carry several sections — one file with many sections (e.g. an XLSX workbook with a worksheet per section) — each with its own filters/columns, all projected in one source pass. The commercial ClosedXML writer + XlsxWorkbook(...) API land in B1.3 on top of this.

This complements B1.1 (many outputs → many files) with the other axis (one output → many sections in one file).

API

new ReportBuilder<Sale>("workbook")
    .From(source)
    .Column(v => v.Id, "Id")
    .ToSections(new SectionedOutputSpec(xlsxWorkbookFactory), s => s
        .Section("Approved", v => v.Where(x => x.Amount > 0))
        .Section("Rejected", v => v
            .Where(x => x.Amount <= 0)
            .Column(x => x.Id, "Id").Column(x => x.Customer, "Customer")));

Changes (additive — default path byte-identical)

  • New Core contracts (in Core, not the frozen Abstractions, like the artifact store): IReportSectionedWriter, ISectionedWriterFactory, SectionedWriterContext, ReportSection.
  • Builder: ToSections(...) via a SectionBuilder<T> reusing B1.1's OutputView<T>. CompiledReport gains SectionedOutputs (spec + per-section name/schema).
  • Pipeline: TypedBatchReader also projects each section in the single pass; ProjectedBatch carries per-sectioned-output → per-section rows; WrittenCount counts a source row once across outputs and sections. The runner creates one IReportSectionedWriter per sectioned output, writes each section per batch, finalizes one file, and uploads/retains it (unified with regular outputs via a small IFinishedFile).

Tests

55 green Core (+1): a fake sectioned writer proves single read, per-section projection with different columns into one file, plus correct RecordsWritten. Jobs (16) and AspNetCore (10) unaffected — reports without sectioned outputs are byte-identical.

Next

B1.3 — NeoReports.Xlsx.Pro (commercial): a ClosedXML IReportSectionedWriter (one worksheet per section) + fluent XlsxWorkbook(...) + the PolyForm Small Business LICENSE (I'll fetch the canonical text) + metadata, excluded from the OSS NuGet release.

The OSS/MIT enabling piece for the Pro workbook. A single output can now carry several
sections (one file with many sections — e.g. an XLSX workbook with a worksheet per
section), each with its own filters/columns, all projected in one source pass. The Pro
ClosedXML writer + XlsxWorkbook(...) API (B1.3) implement the new Core contract.

- New Core contracts (in Core, not the frozen Abstractions, like the artifact store):
  IReportSectionedWriter, ISectionedWriterFactory, SectionedWriterContext, ReportSection.
- Builder: ToSections(SectionedOutputSpec, s => s.Section("name", v => v.Where(...).Column(...)))
  via a SectionBuilder<T> reusing the B1.1 OutputView<T>. CompiledReport gains
  SectionedOutputs (spec + per-section name/schema).
- Pipeline: TypedBatchReader also projects each section (single pass); ProjectedBatch
  carries per-sectioned-output, per-section rows; WrittenCount counts a source row once
  across outputs and sections. The runner creates one IReportSectionedWriter per sectioned
  output, writes each section per batch, finalizes one file, uploads/retains it (unified
  with regular outputs via an IFinishedFile interface).
- Additive: reports without sectioned outputs are byte-identical (all existing tests green).

Tests: 55 green Core (+1) — a fake sectioned writer proves single-read, per-section
projection with different columns into one file. Jobs (16) and AspNetCore (10) unaffected.
PLAN B1.2 done; B1.3 is the commercial NeoReports.Xlsx.Pro package.
Comment thread src/NeoReports.Core/Pipeline/ReportRunner.cs Fixed
Comment thread src/NeoReports.Core/Pipeline/ReportRunner.cs Fixed
- Refactor TypedBatchReader projection into small helpers (S3776 cognitive complexity).
- Explicit types where not apparent (IDE0008); Path.Join and a .Where filter in the runner
  (CodeQL cs/path-combine + missed-Where, both on the new sectioned code path).
- Hoist an expected array in the test (CA1861).

No behavior change; 55 green Core.
Comment thread src/NeoReports.Core/Pipeline/TypedBatchReader.cs Fixed
…urn types

Clears the re-scan findings on the B1.2 refactor: use raw.Count(Distribute) instead of a
foreach+if (S3267 / CodeQL use-Where), and return the concrete array types from the Freeze
helpers (CA1859). No behavior change; 55 green.
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@thiagoluga
thiagoluga merged commit 3a20b28 into master Jul 1, 2026
5 checks passed
@thiagoluga
thiagoluga deleted the feat/b1-2a-sectioned-output-hook branch July 1, 2026 11:55
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.

2 participants