cursorPage method
Future<MssqlCursorPage<TRow> >
cursorPage({
- int size = 25,
- MssqlCursor? after,
- MssqlCursor? before,
- MssqlReadConsistency consistency = MssqlReadConsistency.committed,
A keyset page. after and before are mutually exclusive.
Composite ordering becomes nested AND/OR, not a tuple comparison.
Reverse (before) results are returned in the caller's order.
The cursor is an object; its keys are bound as parameters.
Implementation
Future<MssqlCursorPage<TRow>> cursorPage({
int size = 25,
MssqlCursor? after,
MssqlCursor? before,
MssqlReadConsistency consistency = MssqlReadConsistency.committed,
}) async {
if (after != null && before != null) {
throw ArgumentError(
'cursorPage cannot take after and before together. Ask for one '
'direction per call.',
);
}
if (size <= 0) {
throw ArgumentError.value(size, 'size', 'Must be positive.');
}
final ordered = ensureStableOrder();
final dialect = await _resolvedDialect();
final orders = ordered.state.orderBy;
MssqlKeyset.requireNamedColumns(orders, 'cursorPage()');
final orderSig = MssqlKeyset.orderSignature(orders, dialect);
final filterSig = MssqlKeyset.filterSignature(
binding: binding.erase(),
state: ordered.state,
dialect: dialect,
);
if (after != null) {
MssqlKeyset.check(
after,
orderSignature: orderSig,
filterSignature: filterSig,
keyCount: orders.length,
);
}
if (before != null) {
MssqlKeyset.check(
before,
orderSignature: orderSig,
filterSignature: filterSig,
keyCount: orders.length,
);
}
final walking = before != null ? MssqlKeyset.reverseOrders(orders) : orders;
final cursor = after ?? before;
final scopes = ordered.context.scopeCompiler(ordered.state.scope);
final loader = ordered._loaderFor(session, dialect);
return mssqlRunConsistent(
session: session,
consistency: consistency,
body: (s) async {
var query = ordered._select(orderBy: walking, scopes: scopes);
if (cursor != null) {
query = query.where(MssqlKeyset.after(walking, cursor.keys));
}
final fetched = await query
.top(size + 1)
.get(
s,
dialect: dialect,
timeout: state.options.timeout,
cancellationToken: state.options.cancellationToken,
options: state.options,
);
final hasExtra = fetched.length > size;
final kept = hasExtra ? fetched.sublist(0, size) : fetched;
var mapped = kept.map(binding.fromRow).toList();
if (before != null) {
mapped = mapped.reversed.toList();
}
final parents = await ordered._attachOn(
s,
mapped,
dialect: dialect,
loader: loader.withSession(s),
);
if (kept.isEmpty) {
return MssqlCursorPage<TRow>(rows: parents, hasMore: false);
}
final firstRaw = before != null ? kept.last : kept.first;
final lastRaw = before != null ? kept.first : kept.last;
MssqlCursor make(MssqlRow row) => MssqlKeyset.encode(
orderSignature: orderSig,
filterSignature: filterSig,
keys: MssqlKeyset.keysFromRow(row, orders),
);
return MssqlCursorPage<TRow>(
rows: parents,
hasMore: hasExtra,
next: before != null || hasExtra ? make(lastRaw) : null,
previous: after != null || (before != null && hasExtra)
? make(firstRaw)
: null,
);
},
);
}