chunk method

Future<void> chunk(
  1. MssqlSession session,
  2. int size,
  3. Future<bool> handle(
    1. List<MssqlRow> rows
    ), {
  4. MssqlDialect dialect = MssqlDialect.sql2012,
})

Walks the whole result in keyset pages of size, without holding it all in memory.

OFFSET is not used: deleting a processed row would otherwise skip the next one. Requires orderBy on named columns so each page can bind the last row's keys. A mutable order column is still not a snapshot.

The callback returning false stops the walk, so a search can give up early without reading the rest.

Implementation

Future<void> chunk(
  MssqlSession session,
  int size,
  Future<bool> Function(List<MssqlRow> rows) handle, {
  MssqlDialect dialect = MssqlDialect.sql2012,
}) async {
  if (size <= 0) {
    throw ArgumentError.value(size, 'size', 'Must be positive.');
  }
  if (ordering.isEmpty) {
    throw StateError(
      'chunk() needs orderBy(): without one, two pages can return the same '
      'row and never return another. Source: ${source.quoted}.',
    );
  }
  MssqlKeyset.requireNamedColumns(ordering, 'chunk()');
  List<Object?>? after;
  while (true) {
    var query = this;
    if (after != null) {
      query = query.where(MssqlKeyset.after(ordering, after));
    }
    final page = await query.top(size).get(session, dialect: dialect);
    if (page.isEmpty) return;
    if (!await handle(page)) return;
    if (page.length < size) return;
    after = MssqlKeyset.keysFromRow(page.last, ordering);
  }
}