scanKeys method
Future<Stream<String> >
scanKeys(
- KeyPattern pattern, {
- bool includeExpired = false,
- OrderByKey? orderBy,
- int? limit,
- int? skip,
override
Stream the keystore keys that match pattern. Backend-
portable successor to KeyValueStore.getKeys for callers
that want structured filtering rather than building regular
expressions.
The return type is Stream<String> (rather than Stream<K>):
KeyPattern's fields — sharedBy, sharedWith, namespace,
idPrefix — are atKey-shaped, so the result is inherently a
stream of atKey strings.
By default, expired or not-yet-born keys are excluded; pass
includeExpired: true to surface them.
orderBy controls the result order. null (default) means
"the backend's natural order". limit caps the number of
keys yielded; skip discards the first N.
The returned Future completes once the backend has accepted
the request; the Stream then yields the matching keys.
Implementation
@override
Future<Stream<String>> scanKeys(
KeyPattern pattern, {
bool includeExpired = false,
OrderByKey? orderBy,
int? limit,
int? skip,
}) async {
var where = '1=1';
final params = <Object?>[];
if (!includeExpired) {
final now = _nowMillis();
where +=
' AND (available_at IS NULL OR available_at <= ?) AND (expires_at IS NULL OR expires_at > ?)';
params
..add(now)
..add(now);
}
final order = switch (orderBy) {
OrderByKey.byKey => ' ORDER BY atkey',
OrderByKey.byExpiresAt =>
' ORDER BY (expires_at IS NULL), expires_at', // nulls last
OrderByKey.byCreatedAt =>
" ORDER BY json_extract(metadata, '\$.createdAt')",
null => '',
};
final rows =
_db.raw.select('SELECT atkey FROM at_data WHERE $where$order;', params);
// KeyPattern filter, then skip/limit (limit is post-filter, matching
// the Hive semantics).
var matched = rows
.map((r) => r['atkey'] as String)
.where((k) => SqliteQueryTranslator.matchesKeyPattern(k, pattern));
if (skip != null) matched = matched.skip(skip);
if (limit != null) matched = matched.take(limit);
return Stream.fromIterable(matched.toList());
}