Coding Software Engineer High Frequency
Create a transaction-query interface that can filter records and return them through cursor-driven pages. Given a collection of financial transactions, build an API that can apply several filters and efficiently page through the matching entries.
An important part of the exercise is that no API methods or method signatures are specified for you. You are expected to choose and design a clear interface.
Use an in-memory collection for this exercise, while keeping in mind how the same approach could be implemented against a database.
transactions = [
{"time": 2, "id": 31, "user_id": 4, "currency": 1, "amount": 8},
{"time": 3, "id": 32, "user_id": 4, "currency": 3, "amount": 9},
{"time": 4, "id": 33, "user_id": 5, "currency": 2, "amount": -7},
{"time": 5, "id": 34, "user_id": 5, "currency": 2, "amount": 14},
{"time": 6, "id": 35, "user_id": 4, "currency": 1, "amount": 8},
{"time": 7, "id": 36, "user_id": 4, "currency": 2, "amount": 17},
{"time": 8, "id": 37, "user_id": 4, "currency": 2, "amount": 17},
{"time": 9, "id": 38, "user_id": 4, "currency": 2, "amount": 8},
{"time": 10, "id": 39, "user_id": 4, "currency": 1, "amount": 19},
{"time": 11, "id": 40, "user_id": 4, "currency": 1, "amount": 19},
{"time": 11, "id": 41, "user_id": 4, "currency": 1, "amount": 20},
{"time": 12, "id": 42, "user_id": 4, "currency": 1, "amount": 6},
{"time": 12, "id": 43, "user_id": 4, "currency": 2, "amount": 6},
{"time": 13, "id": 44, "user_id": 4, "currency": 2, "amount": 7},
{"time": 14, "id": 45, "user_id": 4, "currency": 1, "amount": 8},
]
Implement a transaction-query system that accepts any combination of these filters:
[start_time, end_time], including both endpoints.[min_amount, max_amount], with both limits included.Your API should let callers configure filters separately and combine them. A caller must be able to choose one or several filters, then run the query to retrieve the transactions that satisfy all selected conditions.
Consider the following questions:
execute() call, or by returning results as soon as filters are assigned?query = TransactionQuery(transactions)
# Restrict results to one user.
query.set_user_id(4)
results = query.execute()
# Produces every transaction whose user_id equals 4.
# Apply both a time interval and a currency restriction.
query = TransactionQuery(transactions)
query.set_time_range(6, 11)
query.set_currency(1)
results = query.execute()
# Produces transactions satisfying 6 <= time <= 11 AND currency == 1.
# -> [{"time": 6, "id": 35,...}, {"time": 10, "id": 39,...},
# {"time": 11, "id": 40,...}, {"time": 11, "id": 41,...}]
Interviewer: "Extend this with pagination. After choosing a page size, callers should be able to traverse filtered results one page at a time with cursor-based pagination."
Add paging support to the query system. Once filters and a page size are configured, a caller must be able to:
The cursor must be opaque from the caller's perspective: the caller simply returns the received cursor value to request the following page.
query = TransactionQuery(transactions)
query.set_user_id(4)
query.set_page_size(3)
# Initial page.
page1 = query.fetch_page()
# page1.data -> the first 3 matching transactions.
# page1.next_cursor -> the token used to request the following page.
# Following page.
page2 = query.fetch_page(cursor=page1.next_cursor)
# page2.data -> the next 3 matching transactions.
# page2.next_cursor -> the cursor for page 3, or None when nothing remains.
# Visit every page.
cursor = 0
while cursor is not None:
page = query.fetch_page(cursor=cursor)
print(page.data)
cursor = page.next_cursor