Replace a function that rereads the whole table for every page number by an iterator that fetches a page only when its buffer runs out, remembers the last id seen, and can be walked any number of times.
An order history is scrolled on a phone, a few orders at a time. The code in the editor is one function, history_page(store, page, size): it asks the store for every order, then slices out page page. It works for the first screen, but it rereads the whole table for every page, and when a new order arrives between two pages, one order is shown twice. Refactor it into the Iterator pattern: an object the screen can loop over, that knows nothing about page numbers.
The rules (keep them exactly):
store.fetch(before, limit): up to limit orders with an id below before (or the newest ones when before is None), newest first. The store also counts its fetches and the rows_read it served.Build this API (Order and a fake Store are given):
OrderHistory(store, size), the aggregate: iterable. Each time it is iterated it hands out a fresh iterator. Iterating it must not call the store.PageIterator, the iterator: next gives the next order, and it is finished at the end. It keeps a buffer of the current page, a position in it, and the last id fetched as its cursor. It calls store.fetch(cursor, size) only when the buffer is used up and the caller asks for another order. A page shorter than size means the end, so no further fetch; a page of exactly size needs one more fetch to find out it was the last, and an empty page ends the walk.fetch: never call all_rows.In Python, PageIterator has __iter__ (returning itself) and __next__, and OrderHistory has __iter__. JavaScript and TypeScript use [Symbol.iterator](), and the iterator's next() returns { value, done }.
The tests check the whole sequence, the number of fetches and rows read, that nothing is fetched until the first order is asked for, that stopping early reads fewer pages, that a new order arriving mid-walk repeats nothing, that two walks are independent, that a used-up iterator stays used up, a different store written inside a test and plugged in, and that all_rows is gone.
Write your code, then run 10 example tests and 3 hidden tests. Each run is limited to 8 seconds: an infinite loop gets stopped and the runtime restarts, your code stays.