Skip to content

feat(write): TabularExport<T> — an export declared once with typed columns - #84

Merged
vaceslav merged 10 commits into
mainfrom
feat/write-export
Oct 4, 2026
Merged

vaceslav merged 10 commits into
mainfrom
feat/write-export

Conversation

@vaceslav

@vaceslav vaceslav commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Part 4 of #67. Closes #73.

  • TabularExport.For<T>().Column(...).Build(): typed columns (text, integers, decimal, double, bool, DateTime, DateOnly, nullable), headers from typed import fields so an export maps back by header.
  • Writes a sheet from IEnumerable<T>, IAsyncEnumerable<T>, chunks, or messages with a chunk selector (itemsOf) — e.g. a server stream of batches — flushing per chunk and when the buffer recommends it.
  • Immutable and thread-safe; nothing allocated per row (measured); per-cell cost 1–6% over a hand-written loop.
  • A failed sheet faults the caller's writer, so a truncated file can never be completed; a completed writer stays complete.
  • Text check uses SearchValues (the generic range search boxed 96 B per text cell at tier 0).
  • Round trip proven per format: export → TabularFile.Open → import by header gives the same values.

…or a plain sequence — flushed as it goes

Also: Columns returns a read-only wrapper, so a caller cannot cast it back to an array and change the export.
… sheet faults the caller's writer; remove a stray backup file
…AnyInRange<char> boxed 96 bytes on every text cell

TextRules.Check ran on every text cell and called the generic
IndexOfAnyInRange('\uD800', '\uDFFF'), which allocates boxed chars on each
call: up to ~81 MB per million rows in the export test, in every format;
how much showed depended on tiered compilation, hence the varying failures.
A SearchValues over U+D800..U+DFFF finds the same surrogates with no
allocation. A million rows now allocate ~22 KB more than ten thousand
(per-chunk async state), in csv, xlsx and ods on net8.0 and net10.0.
…ns; rename the selector to itemsOf; name the real parameter for a null chunk; cover selector and cancellation failures
… document ArgumentException for a null chunk; spec states the measured per-cell cost
… one-off tiering allocation on Linux net10 failed the exact zero
@vaceslav
vaceslav merged commit 78f2379 into main Oct 4, 2026
9 checks passed
@vaceslav
vaceslav deleted the feat/write-export branch October 4, 2026 12:45
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.

Writing part 4: TabularExport<T> and the import-field bridge

1 participant