Search Pagination Plan #44
Closed
SeanTAllen
started this conversation in
Research
Replies: 1 comment
-
|
Implemented in #50 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Context
GitHub search endpoints return paginated results via Link headers, just like list
endpoints. But the JSON shape differs:
[...]{"total_count": N, "incomplete_results": bool, "items": [...]}The library's current
PaginatedJsonRequester→PaginatedResultReceiver→PaginatedListJsonConverterchain handles the list shape.SearchIssuescurrentlyuses the non-paginated
JsonRequester→ResultReceiverchain, so search resultshave no
next_page()/prev_page().The existing TODO in
search.pony:9-21outlines the intent.Approach
Duplicate the paginated HTTP plumbing for search rather than trying to share it.
The
PaginatedJsonRequester/handler factory/handler chain is parameterized onAbecause it holds a concrete
PaginatedResultReceiver[A]. This type parametercarries real type information through the pipeline to
PaginatedList[A]— it'show Pony knows what the list contains. Erasing it via an unparameterized interface
would lose compile-time type safety. A parameterized interface doesn't help either
—
Awould be phantom sincesuccessandfailuresignatures don't mention it.Duplicating the ~100 lines of mechanical HTTP code (requester, handler factory,
handler) is the cleanest approach. This duplication can be consolidated later
if a good shared abstraction emerges.
Steps
Step 1: Add pagination to
SearchResults[A]insearch.ponyModify
SearchResults[A]to hold pagination state and expose navigation:_creds,_converter,_prev_link,_next_linkcreateto private_create(instances arealways built by the converter, never by end users — matches
PaginatedList's_from_arraypattern)prev_page()andnext_page()methods returning(Promise[(SearchResults[A] | RequestError)] | None)_retrieve_link()private helper (same pattern asPaginatedList._retrieve_link)itemsas a public field (consistent withPaginatedList.results— makingboth methods is a separate refactor)
Step 2: Add
PaginatedSearchJsonConverter[A]insearch.ponyA new converter class (analogous to
PaginatedListJsonConverter[A]) that:total_count,incomplete_results,items)JsonConverter[A]SearchResults[A]via_createThis replaces
IssueSearchResultsJsonConverter.Step 3: Add
SearchResultReceiver[A]actor insearch.ponyA new actor (analogous to
PaginatedResultReceiver[A]) that:Promise[(SearchResults[A] | RequestError)]PaginatedSearchJsonConverter[A]success(json, link_header): converts and fulfills the promisefailure(...): wraps inRequestErrorand fulfillsStep 4: Add search HTTP plumbing in
search.ponyDuplicate the paginated HTTP infrastructure for search use:
SearchJsonRequester: same asPaginatedJsonRequester, butapply[A]takesSearchResultReceiver[A]instead ofPaginatedResultReceiver[A]SearchJsonRequesterHandlerFactory[A]: same asPaginatedJsonRequesterHandlerFactory[A],stores
SearchResultReceiver[A]SearchJsonRequesterHandler[A]: same asPaginatedJsonRequesterHandler[A],stores
SearchResultReceiver[A]These are mechanical duplicates (~100 lines) of the corresponding paginated types.
The only difference is the receiver type. This duplication can be cleaned up later
if a good shared abstraction is found.
Step 5: Update
SearchIssuesprimitive insearch.ponyChange from non-paginated to paginated infrastructure:
PaginatedSearchJsonConverter[Issue]instead ofIssueSearchResultsJsonConverterSearchResultReceiver[Issue]instead ofResultReceiver[SearchResults[Issue]]SearchJsonRequesterinstead ofJsonRequesterStep 6: Clean up
search.ponyIssueSearchResultsJsonConverter(replaced by generic converter)use plp = "pagination_link_parser"importFiles changed
github_rest_api/search.ponySearchResults, new converter, new receiver, search HTTP plumbing, updatedSearchIssuesNo changes to
paginated_list.ponyorrepository.pony— the existing paginatedinfrastructure is left untouched.
Verification
The existing unit tests cover
SimpleURITemplateandPaginationLinkParserwhichare infrastructure this change depends on. There are no integration tests that hit
the live GitHub API, so verification that the search pagination actually works
end-to-end would require manual testing with a real token, or adding a test that
mocks the HTTP layer (which doesn't exist yet).
The key compile-time checks:
SearchResultReceiver[A]type-checks withSearchJsonRequester.apply[A]PaginatedResultReceiver[A]continues to type-check withPaginatedJsonRequester.apply[A](no changes to existing paginated infrastructure)
Manual testing
The
examples/search-issues/example is the natural test harness. After the change,update it to exercise pagination — following the same recursive-chaining pattern
used by
examples/get-repository-labels/main.pony:Requirements for manual testing:
--token). Public search workswithout a token but is rate-limited to 10 requests/minute.
per page by default. Example:
--query "repo:ponylang/ponyc is:issue"(ponychas thousands of issues, so this will produce many pages).
What to verify:
total_countnext_page()returnsNone)total_countandincomplete_resultsare consistent across pagesget-repository-labelsexample still works (regression check — nochanges to paginated infrastructure)
Beta Was this translation helpful? Give feedback.
All reactions