Skip to content

Commit

Permalink
[CT-808] Add pagination for pnl endpoint (#1529)
Browse files Browse the repository at this point in the history
* add pagination for pnl endpoint

* add unit tests
  • Loading branch information
dydxwill authored May 17, 2024
1 parent fe545e2 commit a20347d
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 24 deletions.
70 changes: 65 additions & 5 deletions indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import {
Ordering,
PnlTicksColumns,
PnlTicksCreateObject,
PnlTicksFromDatabase,
} from '../../src/types';
import * as PnlTicksTable from '../../src/stores/pnl-ticks-table';
import * as BlockTable from '../../src/stores/block-table';
import { clearData, migrate, teardown } from '../../src/helpers/db-helpers';
import { seedData } from '../helpers/mock-generators';
import {
defaultBlock, defaultBlock2,
defaultBlock,
defaultBlock2,
defaultPnlTick,
defaultSubaccountId,
defaultSubaccountId2,
Expand Down Expand Up @@ -58,7 +58,7 @@ describe('PnlTicks store', () => {
PnlTicksTable.create(pnlTick2),
]);

const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.findAll({}, [], {
const { results: pnlTicks } = await PnlTicksTable.findAll({}, [], {
orderBy: [[PnlTicksColumns.blockHeight, Ordering.ASC]],
});

Expand All @@ -78,7 +78,7 @@ describe('PnlTicks store', () => {
blockTime: defaultBlock.time,
};
await PnlTicksTable.createMany([defaultPnlTick, pnlTick2]);
const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.findAll({}, [], {
const { results: pnlTicks } = await PnlTicksTable.findAll({}, [], {
orderBy: [[PnlTicksColumns.blockHeight, Ordering.ASC]],
});

Expand All @@ -101,7 +101,7 @@ describe('PnlTicks store', () => {
}),
]);

const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.findAll(
const { results: pnlTicks } = await PnlTicksTable.findAll(
{
subaccountId: [defaultSubaccountId],
},
Expand All @@ -112,6 +112,66 @@ describe('PnlTicks store', () => {
expect(pnlTicks.length).toEqual(2);
});

it('Successfully finds PnlTicks using pagination', async () => {
const blockTime: IsoString = '2023-01-01T00:00:00.000Z';
await Promise.all([
PnlTicksTable.create(defaultPnlTick),
PnlTicksTable.create({
...defaultPnlTick,
createdAt: '2020-01-01T00:00:00.000Z',
blockHeight: '1000',
blockTime,
}),
]);

const responsePageOne = await PnlTicksTable.findAll({
page: 1,
limit: 1,
}, [], {
orderBy: [[PnlTicksColumns.blockHeight, Ordering.DESC]],
});

expect(responsePageOne.results.length).toEqual(1);
expect(responsePageOne.results[0]).toEqual(expect.objectContaining({
...defaultPnlTick,
createdAt: '2020-01-01T00:00:00.000Z',
blockHeight: '1000',
blockTime,
}));
expect(responsePageOne.offset).toEqual(0);
expect(responsePageOne.total).toEqual(2);

const responsePageTwo = await PnlTicksTable.findAll({
page: 2,
limit: 1,
}, [], {
orderBy: [[PnlTicksColumns.blockHeight, Ordering.DESC]],
});

expect(responsePageTwo.results.length).toEqual(1);
expect(responsePageTwo.results[0]).toEqual(expect.objectContaining(defaultPnlTick));
expect(responsePageTwo.offset).toEqual(1);
expect(responsePageTwo.total).toEqual(2);

const responsePageAllPages = await PnlTicksTable.findAll({
page: 1,
limit: 2,
}, [], {
orderBy: [[PnlTicksColumns.blockHeight, Ordering.DESC]],
});

expect(responsePageAllPages.results.length).toEqual(2);
expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining({
...defaultPnlTick,
createdAt: '2020-01-01T00:00:00.000Z',
blockHeight: '1000',
blockTime,
}));
expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining(defaultPnlTick));
expect(responsePageAllPages.offset).toEqual(0);
expect(responsePageAllPages.total).toEqual(2);
});

it('Successfully finds latest block time', async () => {
const blockTime: IsoString = '2023-01-01T00:00:00.000Z';
await Promise.all([
Expand Down
37 changes: 34 additions & 3 deletions indexer/packages/postgres/src/stores/pnl-ticks-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
PnlTicksQueryConfig,
QueryableField,
QueryConfig,
PaginationFromDatabase,
} from '../types';

export function uuid(
Expand All @@ -42,10 +43,11 @@ export async function findAll(
createdBeforeOrAtBlockHeight,
createdOnOrAfter,
createdOnOrAfterBlockHeight,
page,
}: PnlTicksQueryConfig,
requiredFields: QueryableField[],
options: Options = DEFAULT_POSTGRES_OPTIONS,
): Promise<PnlTicksFromDatabase[]> {
): Promise<PaginationFromDatabase<PnlTicksFromDatabase>> {
verifyAllRequiredFields(
{
limit,
Expand Down Expand Up @@ -128,11 +130,40 @@ export async function findAll(
);
}

if (limit !== undefined) {
if (limit !== undefined && page === undefined) {
baseQuery = baseQuery.limit(limit);
}

return baseQuery.returning('*');
/**
* If a query is made using a page number, then the limit property is used as 'page limit'
*/
if (page !== undefined && limit !== undefined) {
/**
* We make sure that the page number is always >= 1
*/
const currentPage: number = Math.max(1, page);
const offset: number = (currentPage - 1) * limit;

/**
* Ensure sorting is applied to maintain consistent pagination results.
* Also a casting of the ts type is required since the infer of the type
* obtained from the count is not performed.
*/
const count: { count?: string } = await baseQuery.clone().clearOrder().count({ count: '*' }).first() as unknown as { count?: string };

baseQuery = baseQuery.offset(offset).limit(limit);

return {
results: await baseQuery.returning('*'),
limit,
offset,
total: parseInt(count.count ?? '0', 10),
};
}

return {
results: await baseQuery.returning('*'),
};
}

export async function create(
Expand Down
2 changes: 1 addition & 1 deletion indexer/scripts/deploy-commit-to-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ case $env in
"dev4") account=525975847385;;
"dev5") account=917958511744;;
"staging") account=677285201534;;
"public-testnet") account=013339450148;; # public testnet
"testnet") account=013339450148;; # public testnet
"mainnet") account=332066407361;; # mainnet
*) account=329916310755;;
esac
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,75 @@ describe('pnlTicks-controller#V4', () => {
);
});

it('Get /historical-pnl respects pagination', async () => {
await testMocks.seedData();
const createdAt: string = '2000-05-25T00:00:00.000Z';
const blockHeight: string = '1';
const pnlTick2: PnlTicksCreateObject = {
...testConstants.defaultPnlTick,
createdAt,
blockHeight,
};
await Promise.all([
PnlTicksTable.create(testConstants.defaultPnlTick),
PnlTicksTable.create(pnlTick2),
]);

const responsePage1: request.Response = await sendRequest({
type: RequestMethod.GET,
path: `/v4/historical-pnl?address=${testConstants.defaultAddress}` +
`&subaccountNumber=${testConstants.defaultSubaccount.subaccountNumber}&page=1&limit=1`,
});

const responsePage2: request.Response = await sendRequest({
type: RequestMethod.GET,
path: `/v4/historical-pnl?address=${testConstants.defaultAddress}` +
`&subaccountNumber=${testConstants.defaultSubaccount.subaccountNumber}&page=2&limit=1`,
});

const expectedPnlTickResponse: PnlTicksResponseObject = {
...testConstants.defaultPnlTick,
id: PnlTicksTable.uuid(
testConstants.defaultPnlTick.subaccountId,
testConstants.defaultPnlTick.createdAt,
),
};

const expectedPnlTick2Response: PnlTicksResponseObject = {
...testConstants.defaultPnlTick,
createdAt,
blockHeight,
id: PnlTicksTable.uuid(
testConstants.defaultPnlTick.subaccountId,
createdAt,
),
};

expect(responsePage1.body.pageSize).toStrictEqual(1);
expect(responsePage1.body.offset).toStrictEqual(0);
expect(responsePage1.body.totalResults).toStrictEqual(2);
expect(responsePage1.body.historicalPnl).toHaveLength(1);
expect(responsePage1.body.historicalPnl).toEqual(
expect.arrayContaining([
expect.objectContaining({
...expectedPnlTickResponse,
}),
]),
);

expect(responsePage2.body.pageSize).toStrictEqual(1);
expect(responsePage2.body.offset).toStrictEqual(1);
expect(responsePage2.body.totalResults).toStrictEqual(2);
expect(responsePage2.body.historicalPnl).toHaveLength(1);
expect(responsePage2.body.historicalPnl).toEqual(
expect.arrayContaining([
expect.objectContaining({
...expectedPnlTick2Response,
}),
]),
);
});

it('Get /historical-pnl respects createdBeforeOrAt and createdBeforeOrAtHeight field', async () => {
await testMocks.seedData();
const createdAt: string = '2000-05-25T00:00:00.000Z';
Expand Down
14 changes: 14 additions & 0 deletions indexer/services/comlink/public/api-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1192,13 +1192,17 @@ fetch('https://dydx-testnet.imperator.co/v4/historical-pnl?address=string&subacc
|createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none|
|createdOnOrAfterHeight|query|number(double)|false|none|
|createdOnOrAfter|query|[IsoString](#schemaisostring)|false|none|
|page|query|number(double)|false|none|

> Example responses
> 200 Response
```json
{
"pageSize": 0,
"totalResults": 0,
"offset": 0,
"historicalPnl": [
{
"id": "string",
Expand Down Expand Up @@ -1277,13 +1281,17 @@ fetch('https://dydx-testnet.imperator.co/v4/historical-pnl/parentSubaccount?addr
|createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none|
|createdOnOrAfterHeight|query|number(double)|false|none|
|createdOnOrAfter|query|[IsoString](#schemaisostring)|false|none|
|page|query|number(double)|false|none|

> Example responses
> 200 Response
```json
{
"pageSize": 0,
"totalResults": 0,
"offset": 0,
"historicalPnl": [
{
"id": "string",
Expand Down Expand Up @@ -3772,6 +3780,9 @@ This operation does not require authentication

```json
{
"pageSize": 0,
"totalResults": 0,
"offset": 0,
"historicalPnl": [
{
"id": "string",
Expand All @@ -3792,6 +3803,9 @@ This operation does not require authentication

|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
|pageSize|number(double)|false|none|none|
|totalResults|number(double)|false|none|none|
|offset|number(double)|false|none|none|
|historicalPnl|[[PnlTicksResponseObject](#schemapnlticksresponseobject)]|true|none|none|

## TradingRewardAggregationPeriod
Expand Down
30 changes: 30 additions & 0 deletions indexer/services/comlink/public/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,18 @@
},
"HistoricalPnlResponse": {
"properties": {
"pageSize": {
"type": "number",
"format": "double"
},
"totalResults": {
"type": "number",
"format": "double"
},
"offset": {
"type": "number",
"format": "double"
},
"historicalPnl": {
"items": {
"$ref": "#/components/schemas/PnlTicksResponseObject"
Expand Down Expand Up @@ -1953,6 +1965,15 @@
"schema": {
"$ref": "#/components/schemas/IsoString"
}
},
{
"in": "query",
"name": "page",
"required": false,
"schema": {
"format": "double",
"type": "number"
}
}
]
}
Expand Down Expand Up @@ -2033,6 +2054,15 @@
"schema": {
"$ref": "#/components/schemas/IsoString"
}
},
{
"in": "query",
"name": "page",
"required": false,
"schema": {
"format": "double",
"type": "number"
}
}
]
}
Expand Down
Loading

0 comments on commit a20347d

Please sign in to comment.