Transaction Query Pager
Problem
Design TransactionQueryPager to filter a fixed collection of transactions and return deterministic pages that a caller can continue with a cursor.
Requirements
- User filter. If
userIdis present, return only transactions whose case-sensitive user ID is equal to it. If it is absent, do not filter by user. - Currency filter. If
currencyis present, return only transactions whose case-sensitive currency is equal to it. If it is absent, do not filter by currency. - Time filter. If
startTimeandendTimeare present, include only timestamps in the inclusive rangestartTime <= timestamp <= endTime. If both are absent, do not filter by time. - Order. Sort matching transactions by
timestampascending, then by uniqueidascending when timestamps are equal. - Continuation. A null cursor starts before the first matching transaction. A non-null cursor starts strictly after the transaction key it represents, so that transaction and every earlier transaction are excluded.
- Page size. Return at most
pageSizeconsecutive matching transactions after the cursor boundary. - More pages. If matching transactions remain, return a non-null
nextCursorthat represents the timestamp and ID of the final returned transaction. - Last page. If no matching transaction remains after the page, return a null
nextCursor. An empty result is therefore terminal. - Filter composition. Return a transaction only when it satisfies every supplied user, currency, and time filter.
API
| Signature | Returns | Behavior |
|---|---|---|
TransactionQueryPager(transactions: Transaction[]) | Not applicable | Copies the fixed transaction collection. Transaction IDs are unique. |
query(filter: TransactionFilter, pageSize: integer, cursor: string?) | TransactionPage | Applies all supplied filters, order, cursor boundary, and page limit without changing the stored transactions. |
Transaction has id: string, timestamp: long, userId: string, currency: string, and amount: long.
TransactionFilter has optional userId: string?, currency: string?, startTime: long?, and endTime: long?. The two time fields are both present or both absent.
TransactionPage has transactions: Transaction[] and nextCursor: string?. A cursor is an opaque token returned by this pager for the same filter. It represents the final transaction's (timestamp, id) order key.
Examples
Construct the pager with transactions t2=(20,u1,USD,7), t1=(10,u1,USD,5), and t3=(20,u1,EUR,9), where each tuple lists (timestamp,userId,currency,amount).
| Step | Operation | Result |
|---|---|---|
| 1 | query({userId: "u1", currency: "USD", startTime: 10, endTime: 20}, 1, null) | transactions=[t1]; nextCursor is non-null. |
| 2 | query(the same filter, 1, step1.nextCursor) | transactions=[t2]; nextCursor=null. |
For equal timestamps, IDs break the tie. If transactions b and a both have timestamp 5, query({}, 10, null) returns [a,b] with a null cursor.
Constraints
- The constructor receives from 0 to 100,000 transactions.
- Each
id,userId, andcurrencycontains 1 to 64 case-sensitive ASCII letters, digits, dots, colons, underscores, or hyphens. - Each
timestampandamountfits in a signed 64-bit integer. - A supplied time range has
startTime <= endTime. pageSizeis from 1 to 1,000.- A non-null cursor came from an earlier call on this pager with the same filter.
Notes
Calls are sequential. The constructor collection does not change after the pager is created.