scanRange method

Future<List<({Bytes? document, Uint8List key})>> scanRange({
  1. Uint8List? start,
  2. Uint8List? end,
  3. bool includeStart = true,
  4. bool includeEnd = false,
  5. int? limit,
})

Returns entries in ascending key order inside the requested range.

Newer sources win: the memtable, then segments newest to oldest. Tombstones are skipped. This is the async counterpart of the local engine's range scan, used by the Web query layer.

Implementation

Future<List<({Uint8List key, Bytes? document})>> scanRange({
  Uint8List? start,
  Uint8List? end,
  bool includeStart = true,
  bool includeEnd = false,
  int? limit,
}) async {
  final memKeys = <Uint8List>[];
  final memDocs = <Bytes?>[];
  _memtable.forEachRange(
    start,
    end,
    (key, chunk, offset, length) {
      memKeys.add(Uint8List.fromList(key));
      memDocs.add(length < 0 ? null : _arena.view(chunk, offset, length));
    },
    includeLower: includeStart,
    includeUpper: includeEnd,
  );

  final cursors = <SegmentEntryCursor>[];
  final cursorKeys = <Uint8List?>[];
  for (var i = _segmentInfos.length - 1; i >= 0; i--) {
    final cursor = (await _readerAt(i)).entryCursor(
      lower: start,
      includeLower: includeStart,
      upper: end,
      includeUpper: includeEnd,
    );
    cursors.add(cursor);
    cursorKeys.add(cursor.moveNext() ? cursor.key : null);
  }

  final out = <({Uint8List key, Bytes? document})>[];
  var memIndex = 0;
  while (true) {
    Uint8List? winner;
    if (memIndex < memKeys.length) winner = memKeys[memIndex];
    for (final key in cursorKeys) {
      if (key == null) continue;
      if (winner == null ||
          StringView.compareRanges(
                key,
                0,
                key.length,
                winner,
                0,
                winner.length,
              ) <
              0) {
        winner = key;
      }
    }
    if (winner == null) break;

    Bytes? document;
    var matched = false;
    if (memIndex < memKeys.length && _sameKey(memKeys[memIndex], winner)) {
      document = memDocs[memIndex];
      memIndex++;
      matched = true;
    }
    for (var i = 0; i < cursors.length; i++) {
      final key = cursorKeys[i];
      if (key == null || !_sameKey(key, winner)) continue;
      if (!matched) {
        document = cursors[i].document?.toBytes();
        matched = true;
      }
      cursorKeys[i] = cursors[i].moveNext() ? cursors[i].key : null;
    }
    if (document == null) continue;
    out.add((key: Uint8List.fromList(winner), document: document));
    if (limit != null && out.length >= limit) break;
  }
  return out;
}