seekToken method
Restores a cursorToken using the expected table and complete sort order.
Rejects malformed tokens or mismatched columns, codecs, directions, and
nullability with QUERY.CURSOR. Existing filters still apply; the token
is neither signed authorization nor a database snapshot.
Implementation
Query<R, F> seekToken(
String token, {
required List<OrderTerm> Function(F) orderBy,
}) {
final order = orderBy(queryFields);
_validateCursor(order);
try {
final payload = jsonDecode(
utf8.decode(base64Url.decode(token)),
) as Map<String, Object?>;
if (payload['version'] != 1 ||
payload['table'] != queryState.source.schema.name ||
jsonEncode(payload['order']) != jsonEncode(_cursorShape(order))) {
throw const FormatException(
'Cursor belongs to another schema or sort order.',
);
}
final values = payload['values'] as List<Object?>;
if (values.length != order.length) {
throw const FormatException('Cursor arity differs.');
}
final terms = <CursorTerm>[];
for (var i = 0; i < order.length; i++) {
final codec = order[i].expression.codec;
final decoded = codec.decode(_decodeCursorValue(values[i]));
terms.add(CursorTerm.internal(order[i], codec.encode(decoded)));
}
return seekAfter((_) => terms);
} catch (e) {
throw OrmException(
'QUERY.CURSOR',
'Invalid cursor for this query.',
cause: e,
);
}
}