Skip to content

Commit

Permalink
fix: cursor paging for multi param queries (#307)
Browse files Browse the repository at this point in the history
  • Loading branch information
rileydcampbell authored Aug 2, 2023
1 parent e02bc07 commit 04167d2
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 9 deletions.
9 changes: 9 additions & 0 deletions lib/config/dynamodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ export enum TABLE_KEY {
FILLER = 'filler',
TX_HASH = 'txHash',
CHAIN_ID = 'chainId',

// compound table keys
CHAIN_ID_FILLER = 'chainId_filler',
CHAIN_ID_ORDER_STATUS = 'chainId_orderStatus',
CHAIN_ID_ORDER_STATUS_FILLER = 'chainId_orderStatus_filler',
FILLER_OFFERER = 'filler_offerer',
FILLER_OFFERER_ORDER_STATUS = 'filler_offerer_orderStatus',
FILLER_ORDER_STATUS = 'filler_orderStatus',
OFFERER_ORDER_STATUS = 'offerer_orderStatus',
}
2 changes: 2 additions & 0 deletions lib/repositories/orders-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ export class DynamoOrdersRepository implements BaseOrdersRepository {
try {
lastEvaluatedKey = JSON.parse(decode(cursor))
} catch (e) {
DynamoOrdersRepository.log.error('Error parsing json cursor.', { cursor, error: e })
throw new Error('Invalid cursor.')
}
const keys = Object.keys(lastEvaluatedKey)
Expand All @@ -473,6 +474,7 @@ export class DynamoOrdersRepository implements BaseOrdersRepository {
})

if (keys.length != validKeys.length || !keysMatch) {
DynamoOrdersRepository.log.error('Error cursor key not in valid key list.', { cursor })
throw new Error('Invalid cursor.')
}

Expand Down
46 changes: 37 additions & 9 deletions test/repositories/dynamo-repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ const MOCK_ORDER_4 = {
orderStatus: ORDER_STATUS.OPEN,
}

const MOCK_ORDER_5 = {
orderHash: '0x5',
offerer: 'hayden.eth',
encodedOrder: 'order1',
signature: 'sig1',
nonce: '1',
chainId: 1,
orderStatus: ORDER_STATUS.OPEN,
}

const ADDITIONAL_FIELDS_ORDER_1 = {
...MOCK_ORDER_1,
filler: '0x1',
Expand All @@ -79,6 +89,11 @@ const ADDITIONAL_FIELDS_ORDER_4 = {
filler: '0x4',
}

const ADDITIONAL_FIELDS_ORDER_5 = {
...MOCK_ORDER_5,
filler: '0x1',
}

const mockedGetCurrentTime = jest.mocked(currentTimestampInSeconds)
const mockTime = (time: number) => {
mockedGetCurrentTime.mockImplementation(() => time.toString())
Expand Down Expand Up @@ -335,11 +350,22 @@ describe('OrdersRepository getOrders test with pagination', () => {
expect(orders.cursor).toEqual(undefined)
})

it('should successfully page through orders with chainId, orderStatus', async () => {
await ordersRepository.putOrderAndUpdateNonceTransaction(ADDITIONAL_FIELDS_ORDER_5)
let orders = await ordersRepository.getOrders(1, { orderStatus: ORDER_STATUS.OPEN, chainId: 1 })
expect(orders.orders.length).toEqual(1)
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_5))
orders = await ordersRepository.getOrders(2, { orderStatus: ORDER_STATUS.OPEN, chainId: 1 }, orders.cursor)
expect(orders.orders.length).toEqual(1)
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(orders.cursor).toEqual(undefined)
})

it('should throw an Error for cursor with the wrong index', async () => {
const orders = await ordersRepository.getOrders(2, { orderStatus: ORDER_STATUS.OPEN })
expect(orders.orders.length).toEqual(2)
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(orders.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_2))
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_5))
expect(orders.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(() => ordersRepository.getOrders(0, { offerer: 'riley.eth' }, orders.cursor)).rejects.toThrow(
Error('Invalid cursor.')
)
Expand All @@ -348,8 +374,8 @@ describe('OrdersRepository getOrders test with pagination', () => {
it('should throw an Error for cursor with the wrong cursor', async () => {
const orders = await ordersRepository.getOrders(2, { orderStatus: ORDER_STATUS.OPEN })
expect(orders.orders.length).toEqual(2)
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(orders.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_2))
expect(orders.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_5))
expect(orders.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(() => ordersRepository.getOrders(0, { offerer: 'riley.eth' }, 'wrong_cursor')).rejects.toThrow(
Error('Invalid cursor.')
)
Expand Down Expand Up @@ -402,9 +428,10 @@ describe('OrdersRepository getOrders test with sorting', () => {
sort: 'between(1,3)',
desc: true,
})
expect(queryResult.orders.length).toEqual(2)
expect(queryResult.orders.length).toEqual(3)
expect(queryResult.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_2))
expect(queryResult.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(queryResult.orders[2]).toEqual(expect.objectContaining(MOCK_ORDER_5))
})

it('should return all orders for OPEN status and between 1,3 time ascending order', async () => {
Expand All @@ -414,9 +441,10 @@ describe('OrdersRepository getOrders test with sorting', () => {
sort: 'between(1,3)',
desc: false,
})
expect(queryResult.orders.length).toEqual(2)
expect(queryResult.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(queryResult.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_2))
expect(queryResult.orders.length).toEqual(3)
expect(queryResult.orders[0]).toEqual(expect.objectContaining(MOCK_ORDER_5))
expect(queryResult.orders[1]).toEqual(expect.objectContaining(MOCK_ORDER_1))
expect(queryResult.orders[2]).toEqual(expect.objectContaining(MOCK_ORDER_2))
})
})

Expand Down Expand Up @@ -485,7 +513,7 @@ describe('OrdersRepository get order count by offerer test', () => {
it('should successfully return order count by existing offerer', async () => {
mockTime(4)
await ordersRepository.putOrderAndUpdateNonceTransaction(ADDITIONAL_FIELDS_ORDER_4)
expect(await ordersRepository.countOrdersByOffererAndStatus(MOCK_ORDER_4.offerer, ORDER_STATUS.OPEN)).toEqual(2)
expect(await ordersRepository.countOrdersByOffererAndStatus(MOCK_ORDER_4.offerer, ORDER_STATUS.OPEN)).toEqual(3)
})

it('should return 0 for nonexistent offerer', async () => {
Expand Down

0 comments on commit 04167d2

Please sign in to comment.