Skip to content

Complete the async surface: async open, async memo reads, IAsyncEnumerable record streaming #297

Description

@chrisrichards

Context

#284 added true async record reading but deliberately deferred three pieces (listed in that PR):

  1. Async table open — DbfTable's constructors read the header and column descriptors synchronously, so ExecuteReaderAsync still does a small synchronous read at open. Requires a static factory (DbfTable.OpenAsync(...)) since constructors cannot await; DbfDbCommand could then offer a genuinely async ExecuteDbDataReaderAsync.
  2. Async memo resolution — memo values are resolved during span parsing via a synchronous BinaryReader (DbfMemo), so a table with memo columns performs sync I/O inside ReadAsync. Needs the memo subsystem moved off BinaryReader onto buffered reads with async variants, and a way for value parsing to defer memo fetches (e.g. parse block pointers, resolve lazily/asynchronously on access).
  3. IAsyncEnumerable<DbfRecord> on DbfTable — parked on a real design question: yielding the mutated reused record is a footgun (ToListAsync would produce N references to one object), yielding fresh records allocates the full value-object set per row. The typed builder (Add typed queries: DbfQuery<T> builder and Dapper-style Query<T> (SQL support phase 5) #290) sidesteps this with materialised Ts; a raw-record async stream should probably yield fresh records and document the cost, or take the reused record as a parameter like Read(DbfRecord) does.

These fit naturally as one PR or three small ones.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions