8.6. Global Search & Token Paging¶
Global all-notes search is the scenario path that demonstrates
TokenPagedComposition beyond the simpler fixed-page notes list.
8.6.1. What It Proves¶
- forward-only token paging through repository-backed search
- search results that are independent of the currently focused notebook
- source-change refresh with an unchanged search term before token paging reads the new filtered projection
- a refresh whose first page is unchanged keeps every loaded result and its continuation, so Load More continues after the last visible result instead of fetching page two again (spec 21 §6.2, ADR-0136)
- explicit ownership of every lifecycle-bearing result VM created by a search, including results later replaced, equality-suppressed, or returned by stale asynchronous work
- the same conceptual flow across C#, Python, TypeScript, and Swift
8.6.2. Where It Lives¶
- C#:
ViewModels/GlobalSearchVM.csin the Avalonia flagship - Python:
viewmodels/global_search_vm.pyin the Textual flagship - TypeScript:
viewmodels/globalSearchVM.tsin the React flagship - Swift:
Sources/NotesShowcaseCore/ViewModels/in the Swift flagship core target
Use the per-flavor READMEs and source tree for the exact repository method names and host wiring: C#, Python, TypeScript, Swift.
8.6.3. Result Ownership¶
The four host examples construct NoteVM instances from repository values and
enable autoConstructOnAdd. TokenPagedComposition deliberately does not own
item lifetimes, so the enclosing GlobalSearchVM keeps an identity registry of
every result it creates—not only the currently visible page. Disposal marks that
registry terminal, disposes every retained result, and immediately disposes any
late result produced by already-running asynchronous work.
This local ownership boundary prevents refresh, same-page equality suppression,
or superseded fetches from making a constructed result unreachable before its
lifecycle closes. Rust's TUI search stores cloned NoteModel values rather than
lifecycle-bearing result VMs, so it does not need this registry.
8.6.4. Token Types¶
The token is opaque, and null / None / nil both requests the first page
and ends paging. The showcases use string tokens. For an integer offset or
page cursor, C# needs a token type that can hold null: use int?, where 0
is a valid cursor, rather than int, which cannot say "no next page" and is
rejected when the composition is constructed.
var paged = new TokenPagedComposition<NoteVM, int?>(async offset =>
{
var page = await repository.LoadPageAsync(offset ?? 0, pageSize);
int? next = page.HasMore ? (offset ?? 0) + pageSize : null;
return new TokenPage<NoteVM, int?>(page.Items, next);
});
Python, TypeScript, Swift, and Rust already express an absent token with
None, null, nil, and Option.