From 99551fc0e23c25fb51307aa1cb29a6b32ca00fb5 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:13:09 +0100 Subject: [PATCH 01/17] =?UTF-8?q?feat(postgres):=20=E2=9C=A8=20add=20trans?= =?UTF-8?q?fer=20pagination=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../postgres/src/stores/transfer-table.ts | 37 +++++++++++++++++-- indexer/packages/postgres/src/types/index.ts | 1 + .../postgres/src/types/pagination-types.ts | 6 +++ .../postgres/src/types/query-types.ts | 2 + 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 indexer/packages/postgres/src/types/pagination-types.ts diff --git a/indexer/packages/postgres/src/stores/transfer-table.ts b/indexer/packages/postgres/src/stores/transfer-table.ts index 1a14bb174b..10ae5514db 100644 --- a/indexer/packages/postgres/src/stores/transfer-table.ts +++ b/indexer/packages/postgres/src/stores/transfer-table.ts @@ -21,6 +21,7 @@ import { QueryableField, ToAndFromSubaccountTransferQueryConfig, SubaccountAssetNetTransferMap, + PaginationFromDatabase, } from '../types'; export function uuid( @@ -194,10 +195,11 @@ export async function findAllToOrFromSubaccountId( createdBeforeOrAt, createdAfterHeight, createdAfter, + page, }: ToAndFromSubaccountTransferQueryConfig, requiredFields: QueryableField[], options: Options = DEFAULT_POSTGRES_OPTIONS, -): Promise { +): Promise> { verifyAllRequiredFields( { limit, @@ -291,11 +293,40 @@ export async function findAllToOrFromSubaccountId( } } - 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 = Math.max(1, page); + const offset = (currentPage - 1) * limit; + + /** + * We need to remove the sorting as it is not necessary in this case. + * Also a casting of the ts type is required since the infer of the type + * obtained from the count is not performed. + */ + const count = 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('*'), + }; } function convertToSubaccountAssetMap( diff --git a/indexer/packages/postgres/src/types/index.ts b/indexer/packages/postgres/src/types/index.ts index 455c67d7ff..ca52d40443 100644 --- a/indexer/packages/postgres/src/types/index.ts +++ b/indexer/packages/postgres/src/types/index.ts @@ -25,4 +25,5 @@ export * from './compliance-data-types'; export * from './compliance-status-types'; export * from './trading-reward-types'; export * from './trading-reward-aggregation-types'; +export * from './pagination-types'; export { PositionSide } from './position-types'; diff --git a/indexer/packages/postgres/src/types/pagination-types.ts b/indexer/packages/postgres/src/types/pagination-types.ts new file mode 100644 index 0000000000..1566e2eef3 --- /dev/null +++ b/indexer/packages/postgres/src/types/pagination-types.ts @@ -0,0 +1,6 @@ +export interface PaginationFromDatabase { + results: T[]; + total?: number, + offset?: number, + limit?: number +} diff --git a/indexer/packages/postgres/src/types/query-types.ts b/indexer/packages/postgres/src/types/query-types.ts index b4e2541059..34cfc3b7dc 100644 --- a/indexer/packages/postgres/src/types/query-types.ts +++ b/indexer/packages/postgres/src/types/query-types.ts @@ -10,6 +10,7 @@ import { IsoString } from './utility-types'; export enum QueryableField { LIMIT = 'limit', + PAGE = 'page', ID = 'id', ADDRESS = 'address', SUBACCOUNT_NUMBER = 'subaccountNumber', @@ -88,6 +89,7 @@ export enum QueryableField { export interface QueryConfig { [QueryableField.LIMIT]?: number; + [QueryableField.PAGE]?: number; } export interface SubaccountQueryConfig extends QueryConfig { From 56719553e4d60bcc769b1ade7aa26c16caa06ce4 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:13:53 +0100 Subject: [PATCH 02/17] =?UTF-8?q?test(postgres):=20=E2=9C=85=20add=20trans?= =?UTF-8?q?fer=20pagination=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/stores/transfer-table.test.ts | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts b/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts index a2c52739ce..5e88aff408 100644 --- a/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts @@ -115,7 +115,7 @@ describe('Transfer store', () => { TransferTable.create(transfer2), ]); - const transfers: TransferFromDatabase[] = await TransferTable.findAllToOrFromSubaccountId( + const { results: transfers } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [defaultSubaccountId] }, [], { orderBy: [[TransferColumns.id, Ordering.ASC]], @@ -142,7 +142,7 @@ describe('Transfer store', () => { TransferTable.create(transfer2), ]); - const transfers: TransferFromDatabase[] = await TransferTable.findAllToOrFromSubaccountId( + const { results: transfers } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [defaultSubaccountId], eventId: [defaultTendermintEventId], @@ -155,6 +155,54 @@ describe('Transfer store', () => { expect(transfers[0]).toEqual(expect.objectContaining(defaultTransfer)); }); + it('Successfully finds all transfers to and from subaccount using pagination', async () => { + const transfer2: TransferCreateObject = { + senderSubaccountId: defaultSubaccountId2, + recipientSubaccountId: defaultSubaccountId, + assetId: defaultAsset2.id, + size: '5', + eventId: defaultTendermintEventId2, + transactionHash: '', // TODO: Add a real transaction Hash + createdAt: createdDateTime.toISO(), + createdAtHeight: createdHeight, + }; + await Promise.all([ + TransferTable.create(defaultTransfer), + TransferTable.create(transfer2), + ]); + + const responsePageOne = await TransferTable.findAllToOrFromSubaccountId( + { subaccountId: [defaultSubaccountId], page: 1, limit: 1 }, + [], { + orderBy: [[TransferColumns.id, Ordering.ASC]], + }); + + expect(responsePageOne.results.length).toEqual(1); + expect(responsePageOne.results[0]).toEqual(expect.objectContaining(defaultTransfer)); + expect(responsePageOne.offset).toEqual(0); + + const responsePageTwo = await TransferTable.findAllToOrFromSubaccountId( + { subaccountId: [defaultSubaccountId], page: 2, limit: 1 }, + [], { + orderBy: [[TransferColumns.id, Ordering.ASC]], + }); + + expect(responsePageTwo.results.length).toEqual(1); + expect(responsePageTwo.results[0]).toEqual(expect.objectContaining(transfer2)); + expect(responsePageTwo.offset).toEqual(1); + + const responsePageAllPages = await TransferTable.findAllToOrFromSubaccountId( + { subaccountId: [defaultSubaccountId], page: 1, limit: 2 }, + [], { + orderBy: [[TransferColumns.id, Ordering.ASC]], + }); + + expect(responsePageAllPages.results.length).toEqual(2); + expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining(defaultTransfer)); + expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining(transfer2)); + expect(responsePageAllPages.offset).toEqual(0); + }); + it('Successfully finds Transfer with eventId', async () => { await Promise.all([ TransferTable.create(defaultTransfer), @@ -234,7 +282,7 @@ describe('Transfer store', () => { TransferTable.create(transfer2), ]); - const transfers: TransferFromDatabase[] = await TransferTable.findAllToOrFromSubaccountId( + const { results: transfers } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [defaultSubaccountId], createdBeforeOrAt: '2000-05-25T00:00:00.000Z', From 9794af74f27d316ab760b67f98b22b7f02bcce8e Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:14:29 +0100 Subject: [PATCH 03/17] =?UTF-8?q?feat(comlink):=20=E2=9C=A8=20add=20pagina?= =?UTF-8?q?tion=20for=20getTransfers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comlink/public/api-documentation.md | 10 +++++++++ indexer/services/comlink/public/swagger.json | 21 +++++++++++++++++++ .../api/v4/transfers-controller.ts | 14 +++++++------ indexer/services/comlink/src/types.ts | 9 +++++++- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index d1af0c5567..f1398a1f47 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -2048,6 +2048,7 @@ fetch('https://dydx-testnet.imperator.co/v4/transfers?address=string&subaccountN |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| +|page|query|number(double)|false|none| > Example responses @@ -2055,6 +2056,9 @@ fetch('https://dydx-testnet.imperator.co/v4/transfers?address=string&subaccountN ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "transfers": [ { "id": "string", @@ -3944,6 +3948,9 @@ or ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "transfers": [ { "id": "string", @@ -3971,5 +3978,8 @@ or |Name|Type|Required|Restrictions|Description| |---|---|---|---|---| +|pageSize|number(double)|false|none|none| +|totalResults|number(double)|false|none|none| +|offset|number(double)|false|none|none| |transfers|[[TransferResponseObject](#schematransferresponseobject)]|true|none|none| diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 9efb4d4804..45755ec07b 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -1158,6 +1158,18 @@ }, "TransferResponse": { "properties": { + "pageSize": { + "type": "number", + "format": "double" + }, + "totalResults": { + "type": "number", + "format": "double" + }, + "offset": { + "type": "number", + "format": "double" + }, "transfers": { "items": { "$ref": "#/components/schemas/TransferResponseObject" @@ -2297,6 +2309,15 @@ "schema": { "$ref": "#/components/schemas/IsoString" } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "double", + "type": "number" + } } ] } diff --git a/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts b/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts index ecb412b16c..9be1b9c060 100644 --- a/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts @@ -1,7 +1,6 @@ import { stats } from '@dydxprotocol-indexer/base'; import { AssetColumns, - AssetFromDatabase, AssetTable, DEFAULT_POSTGRES_OPTIONS, IsoString, @@ -50,15 +49,14 @@ class TransfersController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, + @Query() page?: number, ): Promise { const subaccountId: string = SubaccountTable.uuid(address, subaccountNumber); // TODO(DEC-656): Change to a cache in Redis similar to Librarian instead of querying DB. - const [subaccount, transfers, assets] : [ - SubaccountFromDatabase | undefined, - TransferFromDatabase[], - AssetFromDatabase[] - ] = await + const [subaccount, { + results: transfers, limit: pageSize, offset, total, + }, assets] = await Promise.all([ SubaccountTable.findById( subaccountId, @@ -71,6 +69,7 @@ class TransfersController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, + page, }, [QueryableField.LIMIT], { @@ -123,6 +122,9 @@ class TransfersController extends Controller { transfers: transfers.map((transfer: TransferFromDatabase) => { return transferToResponseObject(transfer, idToAsset, idToSubaccount, subaccountId); }), + pageSize, + totalResults: total, + offset, }; } } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 256f9179ea..89e0a981ce 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -40,6 +40,13 @@ export enum RequestMethod { PUT = 'PUT', } +/* ------- Pagination ------- */ +export interface PaginationResponse { + pageSize?: number, + totalResults?: number, + offset?: number, +} + /* ------- SUBACCOUNT TYPES ------- */ export interface AddressResponse { @@ -143,7 +150,7 @@ export interface FillResponseObject { /* ------- TRANSFER TYPES ------- */ -export interface TransferResponse { +export interface TransferResponse extends PaginationResponse { transfers: TransferResponseObject[], } From d95839665ef6f5e409a0fd62128db6bd15ca5bfa Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:14:38 +0100 Subject: [PATCH 04/17] =?UTF-8?q?test(ender):=20=E2=9C=85=20update=20trans?= =?UTF-8?q?fer=20handler=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ender/__tests__/handlers/transfer-handler.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts b/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts index 040a261d8f..1b6370dd65 100644 --- a/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts +++ b/indexer/services/ender/__tests__/handlers/transfer-handler.test.ts @@ -545,7 +545,7 @@ async function expectNoExistingTransfers( subaccountIds: string[], ) { // Confirm there is no existing transfer to or from the subaccounts - const transfers: TransferFromDatabase[] = await TransferTable.findAllToOrFromSubaccountId( + const { results: transfers } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: subaccountIds, }, @@ -572,7 +572,7 @@ async function expectAndReturnNewTransfer( ): Promise { // Confirm there is now a transfer to or from the recipient subaccount if (recipientSubaccountId) { - const newTransfersRelatedToRecipient: TransferFromDatabase[] = await + const { results: newTransfersRelatedToRecipient } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [ @@ -588,7 +588,7 @@ async function expectAndReturnNewTransfer( if (senderSubaccountId) { // Confirm there is now a transfer to or from the sender subaccount - const newTransfersRelatedToSender: TransferFromDatabase[] = await + const { results: newTransfersRelatedToSender } = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [ From bcc708517eda7b28f4d3208001c85f80c8efe254 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:22:07 +0100 Subject: [PATCH 05/17] =?UTF-8?q?feat(postgres):=20=E2=9C=A8=20add=20fill?= =?UTF-8?q?=20pagination=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../postgres/src/stores/fill-table.ts | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/indexer/packages/postgres/src/stores/fill-table.ts b/indexer/packages/postgres/src/stores/fill-table.ts index 186f645b6a..8411da9751 100644 --- a/indexer/packages/postgres/src/stores/fill-table.ts +++ b/indexer/packages/postgres/src/stores/fill-table.ts @@ -25,6 +25,7 @@ import { CostOfFills, QueryableField, QueryConfig, + PaginationFromDatabase, } from '../types'; export function uuid(eventId: Buffer, liquidity: Liquidity): string { @@ -49,10 +50,11 @@ export async function findAll( createdOnOrAfter, clientMetadata, fee, + page, }: FillQueryConfig, requiredFields: QueryableField[], options: Options = DEFAULT_POSTGRES_OPTIONS, -): Promise { +): Promise> { verifyAllRequiredFields( { limit, @@ -156,11 +158,40 @@ export async function findAll( Ordering.DESC, ); - 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 = Math.max(1, page); + const offset = (currentPage - 1) * limit; + + /** + * We need to remove the sorting as it is not necessary in this case. + * Also a casting of the ts type is required since the infer of the type + * obtained from the count is not performed. + */ + const count = 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( From 4dac677c5d0f6219a6da06623ed34d0fd6e2a95a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:22:46 +0100 Subject: [PATCH 06/17] =?UTF-8?q?test(postgres):=20=E2=9C=85=20add=20fill?= =?UTF-8?q?=20pagination=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/stores/fill-table.test.ts | 64 +++++++++++++++++-- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/fill-table.test.ts b/indexer/packages/postgres/__tests__/stores/fill-table.test.ts index d31ed9e177..6d740576b8 100644 --- a/indexer/packages/postgres/__tests__/stores/fill-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/fill-table.test.ts @@ -71,7 +71,7 @@ describe('Fill store', () => { FillTable.create(defaultFill), ]); - const fills: FillFromDatabase[] = await FillTable.findAll({}, [], {}); + const { results: fills } = await FillTable.findAll({}, [], {}); expect(fills.length).toEqual(2); expect(fills[0]).toEqual(expect.objectContaining(defaultFill)); @@ -91,7 +91,7 @@ describe('Fill store', () => { }), ]); - const fills: FillFromDatabase[] = await FillTable.findAll({}, [], { + const { results: fills } = await FillTable.findAll({}, [], { orderBy: [[FillColumns.eventId, Ordering.DESC]], }); @@ -103,6 +103,56 @@ describe('Fill store', () => { expect(fills[1]).toEqual(expect.objectContaining(defaultFill)); }); + it('Successfully finds fills using pagination', async () => { + await Promise.all([ + FillTable.create(defaultFill), + FillTable.create({ + ...defaultFill, + eventId: defaultTendermintEventId2, + }), + ]); + + const responsePageOne = await FillTable.findAll({ + page: 1, + limit: 1, + }, [], { + orderBy: [[FillColumns.eventId, Ordering.DESC]], + }); + + expect(responsePageOne.results.length).toEqual(1); + expect(responsePageOne.results[0]).toEqual(expect.objectContaining({ + ...defaultFill, + eventId: defaultTendermintEventId2, + })); + expect(responsePageOne.offset).toEqual(0); + + const responsePageTwo = await FillTable.findAll({ + page: 2, + limit: 1, + }, [], { + orderBy: [[FillColumns.eventId, Ordering.DESC]], + }); + + expect(responsePageTwo.results.length).toEqual(1); + expect(responsePageTwo.results[0]).toEqual(expect.objectContaining(defaultFill)); + expect(responsePageTwo.offset).toEqual(1); + + const responsePageAllPages = await FillTable.findAll({ + page: 1, + limit: 2, + }, [], { + orderBy: [[FillColumns.eventId, Ordering.DESC]], + }); + + expect(responsePageAllPages.results.length).toEqual(2); + expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining({ + ...defaultFill, + eventId: defaultTendermintEventId2, + })); + expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining(defaultFill)); + expect(responsePageAllPages.offset).toEqual(0); + }); + it('Successfully finds Fill with eventId', async () => { await Promise.all([ FillTable.create(defaultFill), @@ -112,7 +162,7 @@ describe('Fill store', () => { }), ]); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { eventId: defaultFill.eventId, }, @@ -134,7 +184,7 @@ describe('Fill store', () => { ) => { await FillTable.create(defaultFill); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { createdBeforeOrAt: createdDateTime.plus({ seconds: deltaSeconds }).toISO(), }, @@ -155,7 +205,7 @@ describe('Fill store', () => { ) => { await FillTable.create(defaultFill); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { createdBeforeOrAtHeight: Big(createdHeight).plus(deltaBlocks).toFixed(), }, @@ -177,7 +227,7 @@ describe('Fill store', () => { ) => { await FillTable.create(defaultFill); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { createdOnOrAfter: createdDateTime.minus({ seconds: deltaSeconds }).toISO(), }, @@ -199,7 +249,7 @@ describe('Fill store', () => { ) => { await FillTable.create(defaultFill); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { createdOnOrAfterHeight: Big(createdHeight).minus(deltaBlocks).toFixed(), }, From 635dcd681b7d21205ed0ea395367077700b9c17a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 18:23:21 +0100 Subject: [PATCH 07/17] =?UTF-8?q?feat(comlink):=20=E2=9C=A8=20add=20pagina?= =?UTF-8?q?tion=20for=20getTrades=20and=20getFills?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comlink/public/api-documentation.md | 23 ++++++++++ indexer/services/comlink/public/swagger.json | 42 +++++++++++++++++++ .../controllers/api/v4/fills-controller.ts | 14 ++++++- .../controllers/api/v4/trades-controller.ts | 12 +++++- indexer/services/comlink/src/types.ts | 4 +- 5 files changed, 90 insertions(+), 5 deletions(-) diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index f1398a1f47..6f825f72d4 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -688,6 +688,7 @@ fetch('https://dydx-testnet.imperator.co/v4/fills?address=string&subaccountNumbe |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| +|page|query|number(double)|false|none| #### Enumerated Values @@ -702,6 +703,9 @@ fetch('https://dydx-testnet.imperator.co/v4/fills?address=string&subaccountNumbe ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "fills": [ { "id": "string", @@ -800,6 +804,9 @@ fetch('https://dydx-testnet.imperator.co/v4/fills/parentSubaccount?address=strin ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "fills": [ { "id": "string", @@ -1966,6 +1973,7 @@ fetch('https://dydx-testnet.imperator.co/v4/trades/perpetualMarket/{ticker}', |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| +|page|query|number(double)|false|none| > Example responses @@ -1973,6 +1981,9 @@ fetch('https://dydx-testnet.imperator.co/v4/trades/perpetualMarket/{ticker}', ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "trades": [ { "id": "string", @@ -2968,6 +2979,9 @@ This operation does not require authentication ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "fills": [ { "id": "string", @@ -2994,6 +3008,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| |fills|[[FillResponseObject](#schemafillresponseobject)]|true|none|none| ## HeightResponse @@ -3845,6 +3862,9 @@ or ```json { + "pageSize": 0, + "totalResults": 0, + "offset": 0, "trades": [ { "id": "string", @@ -3864,6 +3884,9 @@ or |Name|Type|Required|Restrictions|Description| |---|---|---|---|---| +|pageSize|number(double)|false|none|none| +|totalResults|number(double)|false|none|none| +|offset|number(double)|false|none|none| |trades|[[TradeResponseObject](#schematraderesponseobject)]|true|none|none| ## TransferType diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 45755ec07b..9ebfd6614f 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -471,6 +471,18 @@ }, "FillResponse": { "properties": { + "pageSize": { + "type": "number", + "format": "double" + }, + "totalResults": { + "type": "number", + "format": "double" + }, + "offset": { + "type": "number", + "format": "double" + }, "fills": { "items": { "$ref": "#/components/schemas/FillResponseObject" @@ -1066,6 +1078,18 @@ }, "TradeResponse": { "properties": { + "pageSize": { + "type": "number", + "format": "double" + }, + "totalResults": { + "type": "number", + "format": "double" + }, + "offset": { + "type": "number", + "format": "double" + }, "trades": { "items": { "$ref": "#/components/schemas/TradeResponseObject" @@ -1523,6 +1547,15 @@ "schema": { "$ref": "#/components/schemas/IsoString" } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "double", + "type": "number" + } } ] } @@ -2246,6 +2279,15 @@ "schema": { "$ref": "#/components/schemas/IsoString" } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "double", + "type": "number" + } } ] } diff --git a/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts b/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts index f9ae639b92..e4e74bc3b6 100644 --- a/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts @@ -55,6 +55,7 @@ class FillsController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, + @Query() page?: number, ): Promise { // TODO(DEC-656): Change to using a cache of markets in Redis similar to Librarian instead of // querying the DB. @@ -68,7 +69,12 @@ class FillsController extends Controller { } const subaccountId: string = SubaccountTable.uuid(address, subaccountNumber); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { + results: fills, + limit: pageSize, + offset, + total, + } = await FillTable.findAll( { subaccountId: [subaccountId], clobPairId, @@ -77,6 +83,7 @@ class FillsController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, + page, }, [QueryableField.LIMIT], ); @@ -98,6 +105,9 @@ class FillsController extends Controller { fills: fills.map((fill: FillFromDatabase): FillResponseObject => { return fillToResponseObject(fill, clobPairIdToMarket, subaccountNumber); }), + pageSize, + totalResults: total, + offset, }; } @@ -132,7 +142,7 @@ class FillsController extends Controller { ); const subaccountIds: string[] = Object.keys(childIdtoSubaccountNumber); - const fills: FillFromDatabase[] = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { subaccountId: subaccountIds, clobPairId, diff --git a/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts b/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts index e94e514c56..a9725ac823 100644 --- a/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts @@ -45,6 +45,7 @@ class TradesController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, + @Query() page?: number, ): Promise { const clobPairId: string | undefined = perpetualMarketRefresher .getClobPairIdFromTicker(ticker); @@ -53,7 +54,12 @@ class TradesController extends Controller { throw new NotFoundError(`${ticker} not found in tickers of type ${MarketType.PERPETUAL}`); } - const fills: FillFromDatabase[] = await FillTable.findAll( + const { + results: fills, + limit: pageSize, + offset, + total, + } = await FillTable.findAll( { clobPairId, liquidity: Liquidity.TAKER, @@ -62,6 +68,7 @@ class TradesController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, + page, }, [QueryableField.LIQUIDITY, QueryableField.CLOB_PAIR_ID, QueryableField.LIMIT], ); @@ -70,6 +77,9 @@ class TradesController extends Controller { trades: fills.map((fill: FillFromDatabase): TradeResponseObject => { return fillToTradeResponseObject(fill); }), + pageSize, + totalResults: total, + offset, }; } } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 89e0a981ce..50a37df0f9 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -127,7 +127,7 @@ export type AssetPositionsMap = { [symbol: string]: AssetPositionResponseObject /* ------- FILL TYPES ------- */ -export interface FillResponse { +export interface FillResponse extends PaginationResponse { fills: FillResponseObject[], } @@ -191,7 +191,7 @@ export interface PnlTicksResponseObject { /* ------- TRADE TYPES ------- */ -export interface TradeResponse { +export interface TradeResponse extends PaginationResponse { trades: TradeResponseObject[], } From f4ca7ec287a94fdc4f3d3f74e31ae76dac9cda70 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Tue, 26 Mar 2024 19:26:48 +0100 Subject: [PATCH 08/17] test: :white_check_mark: update pagination tests updated pagination tests to also evaluate total pages. --- indexer/packages/postgres/__tests__/stores/fill-table.test.ts | 3 +++ .../packages/postgres/__tests__/stores/transfer-table.test.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/indexer/packages/postgres/__tests__/stores/fill-table.test.ts b/indexer/packages/postgres/__tests__/stores/fill-table.test.ts index 6d740576b8..e641c0da36 100644 --- a/indexer/packages/postgres/__tests__/stores/fill-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/fill-table.test.ts @@ -125,6 +125,7 @@ describe('Fill store', () => { eventId: defaultTendermintEventId2, })); expect(responsePageOne.offset).toEqual(0); + expect(responsePageOne.total).toEqual(2); const responsePageTwo = await FillTable.findAll({ page: 2, @@ -136,6 +137,7 @@ describe('Fill store', () => { expect(responsePageTwo.results.length).toEqual(1); expect(responsePageTwo.results[0]).toEqual(expect.objectContaining(defaultFill)); expect(responsePageTwo.offset).toEqual(1); + expect(responsePageTwo.total).toEqual(2); const responsePageAllPages = await FillTable.findAll({ page: 1, @@ -151,6 +153,7 @@ describe('Fill store', () => { })); expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining(defaultFill)); expect(responsePageAllPages.offset).toEqual(0); + expect(responsePageAllPages.total).toEqual(2); }); it('Successfully finds Fill with eventId', async () => { diff --git a/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts b/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts index 5e88aff408..c3293b12d6 100644 --- a/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/transfer-table.test.ts @@ -180,6 +180,7 @@ describe('Transfer store', () => { expect(responsePageOne.results.length).toEqual(1); expect(responsePageOne.results[0]).toEqual(expect.objectContaining(defaultTransfer)); expect(responsePageOne.offset).toEqual(0); + expect(responsePageOne.total).toEqual(2); const responsePageTwo = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [defaultSubaccountId], page: 2, limit: 1 }, @@ -190,6 +191,7 @@ describe('Transfer store', () => { expect(responsePageTwo.results.length).toEqual(1); expect(responsePageTwo.results[0]).toEqual(expect.objectContaining(transfer2)); expect(responsePageTwo.offset).toEqual(1); + expect(responsePageTwo.total).toEqual(2); const responsePageAllPages = await TransferTable.findAllToOrFromSubaccountId( { subaccountId: [defaultSubaccountId], page: 1, limit: 2 }, @@ -201,6 +203,7 @@ describe('Transfer store', () => { expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining(defaultTransfer)); expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining(transfer2)); expect(responsePageAllPages.offset).toEqual(0); + expect(responsePageAllPages.total).toEqual(2); }); it('Successfully finds Transfer with eventId', async () => { From 0d14f11d9d8046396db741056ad725881fca9699 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Wed, 27 Mar 2024 19:42:50 +0100 Subject: [PATCH 09/17] feat(postgres): :label: add explicit types added explicit types for fill and transfer tables. --- indexer/packages/postgres/src/stores/fill-table.ts | 6 +++--- indexer/packages/postgres/src/stores/transfer-table.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/indexer/packages/postgres/src/stores/fill-table.ts b/indexer/packages/postgres/src/stores/fill-table.ts index 8411da9751..07c2369d2d 100644 --- a/indexer/packages/postgres/src/stores/fill-table.ts +++ b/indexer/packages/postgres/src/stores/fill-table.ts @@ -169,15 +169,15 @@ export async function findAll( /** * We make sure that the page number is always >= 1 */ - const currentPage = Math.max(1, page); - const offset = (currentPage - 1) * limit; + const currentPage: number = Math.max(1, page); + const offset: number = (currentPage - 1) * limit; /** * We need to remove the sorting as it is not necessary in this case. * Also a casting of the ts type is required since the infer of the type * obtained from the count is not performed. */ - const count = await baseQuery.clone().clearOrder().count({ count: '*' }).first() as unknown as { count?: string }; + const count: { count?: string } = await baseQuery.clone().clearOrder().count({ count: '*' }).first() as unknown as { count?: string }; baseQuery = baseQuery.offset(offset).limit(limit); diff --git a/indexer/packages/postgres/src/stores/transfer-table.ts b/indexer/packages/postgres/src/stores/transfer-table.ts index 10ae5514db..296258d474 100644 --- a/indexer/packages/postgres/src/stores/transfer-table.ts +++ b/indexer/packages/postgres/src/stores/transfer-table.ts @@ -304,15 +304,15 @@ export async function findAllToOrFromSubaccountId( /** * We make sure that the page number is always >= 1 */ - const currentPage = Math.max(1, page); - const offset = (currentPage - 1) * limit; + const currentPage: number = Math.max(1, page); + const offset: number = (currentPage - 1) * limit; /** * We need to remove the sorting as it is not necessary in this case. * Also a casting of the ts type is required since the infer of the type * obtained from the count is not performed. */ - const count = await baseQuery.clone().clearOrder().count({ count: '*' }).first() as unknown as { count?: string }; + const count: { count?: string } = await baseQuery.clone().clearOrder().count({ count: '*' }).first() as unknown as { count?: string }; baseQuery = baseQuery.offset(offset).limit(limit); From 15bcf494a8586e950e599ba15938fd20615695c9 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 5 Apr 2024 23:25:16 +0200 Subject: [PATCH 10/17] feat(postgres): :sparkles: add order pagination support --- .../postgres/src/stores/order-table.ts | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/indexer/packages/postgres/src/stores/order-table.ts b/indexer/packages/postgres/src/stores/order-table.ts index df59c4e27c..f16a75ea58 100644 --- a/indexer/packages/postgres/src/stores/order-table.ts +++ b/indexer/packages/postgres/src/stores/order-table.ts @@ -15,6 +15,7 @@ import { OrderQueryConfig, OrderStatus, OrderUpdateObject, + PaginationFromDatabase, QueryableField, QueryConfig, } from '../types'; @@ -67,10 +68,11 @@ export async function findAll( goodTilBlockTimeBeforeOrAt, clientMetadata, triggerPrice, + page, }: OrderQueryConfig, requiredFields: QueryableField[], options: Options = DEFAULT_POSTGRES_OPTIONS, -): Promise { +): Promise> { verifyAllRequiredFields( { limit, @@ -185,11 +187,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; + + /** + * We need to remove the sorting as it is not necessary in this case. + * 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( From 34c42926968854256d009667c2101c11129a2a56 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 5 Apr 2024 23:25:50 +0200 Subject: [PATCH 11/17] test(postgres): :white_check_mark: add order pagination test --- .../__tests__/stores/order-table.test.ts | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/order-table.test.ts b/indexer/packages/postgres/__tests__/stores/order-table.test.ts index 1cd9e26a60..7a3b92a13b 100644 --- a/indexer/packages/postgres/__tests__/stores/order-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/order-table.test.ts @@ -49,7 +49,7 @@ describe('Order store', () => { it('Successfully creates an Order with goodTilBlockTime', async () => { await OrderTable.create(defaultOrderGoodTilBlockTime); - const orders: OrderFromDatabase[] = await OrderTable.findAll({}, [], {}); + const { results: orders } = await OrderTable.findAll({}, [], {}); expect(orders).toHaveLength(1); expect(orders[0]).toEqual(expect.objectContaining({ @@ -67,7 +67,7 @@ describe('Order store', () => { }), ]); - const orders: OrderFromDatabase[] = await OrderTable.findAll({}, [], { + const { results: orders } = await OrderTable.findAll({}, [], { orderBy: [[OrderColumns.clientId, Ordering.ASC]], }); @@ -79,6 +79,50 @@ describe('Order store', () => { })); }); + it('Successfully finds all Orders using pagination', async () => { + await Promise.all([ + OrderTable.create(defaultOrder), + OrderTable.create({ + ...defaultOrder, + clientId: '2', + }), + ]); + + const responsePageOne = await OrderTable.findAll({ page: 1, limit: 1 }, [], { + orderBy: [[OrderColumns.clientId, Ordering.ASC]], + }); + + expect(responsePageOne.results.length).toEqual(1); + expect(responsePageOne.results[0]).toEqual(expect.objectContaining(defaultOrder)); + expect(responsePageOne.offset).toEqual(0); + expect(responsePageOne.total).toEqual(2); + + const responsePageTwo = await OrderTable.findAll({ page: 2, limit: 1 }, [], { + orderBy: [[OrderColumns.clientId, Ordering.ASC]], + }); + + expect(responsePageTwo.results.length).toEqual(1); + expect(responsePageTwo.results[0]).toEqual(expect.objectContaining({ + ...defaultOrder, + clientId: '2', + })); + expect(responsePageTwo.offset).toEqual(1); + expect(responsePageTwo.total).toEqual(2); + + const responsePageAllPages = await OrderTable.findAll({ page: 1, limit: 2 }, [], { + orderBy: [[OrderColumns.clientId, Ordering.ASC]], + }); + + expect(responsePageAllPages.results.length).toEqual(2); + expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining(defaultOrder)); + expect(responsePageAllPages.results[1]).toEqual(expect.objectContaining({ + ...defaultOrder, + clientId: '2', + })); + expect(responsePageAllPages.offset).toEqual(0); + expect(responsePageAllPages.total).toEqual(2); + }); + it('findOpenLongTermOrConditionalOrders', async () => { await Promise.all([ OrderTable.create(defaultOrder), @@ -106,7 +150,7 @@ describe('Order store', () => { }), ]); - const orders: OrderFromDatabase[] = await OrderTable.findAll( + const { results: orders } = await OrderTable.findAll( { clientId: '1', }, @@ -202,7 +246,7 @@ describe('Order store', () => { OrderTable.create(defaultOrderGoodTilBlockTime), ]); - const orders: OrderFromDatabase[] = await OrderTable.findAll( + const { results: orders } = await OrderTable.findAll( filter, [], { readReplica: true }, From 9b37c5ac05e4f2788877b60b1fe8f3a661b585df Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 5 Apr 2024 23:27:39 +0200 Subject: [PATCH 12/17] feat: :recycle: update order findAll usage --- .../comlink/src/controllers/api/v4/orders-controller.ts | 9 ++++++--- .../__tests__/tasks/cancel-stale-orders.test.ts | 4 ++-- .../services/roundtable/src/tasks/cancel-stale-orders.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts b/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts index 25a5623481..63a24d3b33 100644 --- a/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts @@ -12,6 +12,7 @@ import { OrderStatus, OrderTable, OrderType, + PaginationFromDatabase, perpetualMarketRefresher, protocolTranslations, SubaccountTable, @@ -95,10 +96,10 @@ class OrdersController extends Controller { : Ordering.DESC; const [ redisOrderMap, - postgresOrders, + { results: postgresOrders }, ]: [ RedisOrderMap, - OrderFromDatabase[], + PaginationFromDatabase, ] = await Promise.all([ getRedisOrderMapForSubaccountId( SubaccountTable.uuid(address, subaccountNumber), @@ -140,11 +141,13 @@ class OrdersController extends Controller { // then we do not want to return this order to the user as 'BEST_EFFORT_OPENED'. let additionalPostgresOrders: OrderFromDatabase[] = []; if (!_.isEmpty(postgresOrderIdsToFetch)) { - additionalPostgresOrders = await OrderTable.findAll({ + const { results } = await OrderTable.findAll({ id: redisOrderIds, }, [], { ...DEFAULT_POSTGRES_OPTIONS, }); + + additionalPostgresOrders = results; } const postgresOrderMap: PostgresOrderMap = _.keyBy( diff --git a/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts b/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts index 2628ab4150..243b23432b 100644 --- a/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts @@ -83,7 +83,7 @@ describe('cancel-stale-orders', () => { await cancelStaleOrdersTask(); - const ordersAfterTask: OrderFromDatabase[] = await OrderTable.findAll( + const { results: ordersAfterTask } = await OrderTable.findAll( { id: createdOrderIds, }, @@ -145,7 +145,7 @@ describe('cancel-stale-orders', () => { expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders.count', 1); expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders_canceled.count', 1); - const ordersAfterTask: OrderFromDatabase[] = await OrderTable.findAll( + const { results: ordersAfterTask } = await OrderTable.findAll( { id: createdOrderIds, }, diff --git a/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts b/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts index 43f315c21a..2c9e457ae8 100644 --- a/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts +++ b/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts @@ -22,7 +22,7 @@ export default async function runTask(): Promise { const latestBlockHeight: number = parseInt(latestBlock.blockHeight, 10); - const staleOpenOrders: OrderFromDatabase[] = await OrderTable.findAll( + const { results: staleOpenOrders } = await OrderTable.findAll( { statuses: [OrderStatus.OPEN], orderFlags: ORDER_FLAG_SHORT_TERM.toString(), From 6bea2ce60e4fa210242b24c17e928e8c8908e59f Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 5 Apr 2024 23:33:28 +0200 Subject: [PATCH 13/17] revert: :rewind: revert add pagination for getTransfers --- .../comlink/public/api-documentation.md | 10 --------- indexer/services/comlink/public/swagger.json | 21 ------------------- .../api/v4/transfers-controller.ts | 10 +-------- indexer/services/comlink/src/types.ts | 2 +- 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index 6f825f72d4..6fc03e3ecc 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -2059,7 +2059,6 @@ fetch('https://dydx-testnet.imperator.co/v4/transfers?address=string&subaccountN |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| -|page|query|number(double)|false|none| > Example responses @@ -2067,9 +2066,6 @@ fetch('https://dydx-testnet.imperator.co/v4/transfers?address=string&subaccountN ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "transfers": [ { "id": "string", @@ -3971,9 +3967,6 @@ or ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "transfers": [ { "id": "string", @@ -4001,8 +3994,5 @@ or |Name|Type|Required|Restrictions|Description| |---|---|---|---|---| -|pageSize|number(double)|false|none|none| -|totalResults|number(double)|false|none|none| -|offset|number(double)|false|none|none| |transfers|[[TransferResponseObject](#schematransferresponseobject)]|true|none|none| diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 9ebfd6614f..4cf3365cf3 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -1182,18 +1182,6 @@ }, "TransferResponse": { "properties": { - "pageSize": { - "type": "number", - "format": "double" - }, - "totalResults": { - "type": "number", - "format": "double" - }, - "offset": { - "type": "number", - "format": "double" - }, "transfers": { "items": { "$ref": "#/components/schemas/TransferResponseObject" @@ -2351,15 +2339,6 @@ "schema": { "$ref": "#/components/schemas/IsoString" } - }, - { - "in": "query", - "name": "page", - "required": false, - "schema": { - "format": "double", - "type": "number" - } } ] } diff --git a/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts b/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts index 9be1b9c060..e491830e20 100644 --- a/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/transfers-controller.ts @@ -49,15 +49,11 @@ class TransfersController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, - @Query() page?: number, ): Promise { const subaccountId: string = SubaccountTable.uuid(address, subaccountNumber); // TODO(DEC-656): Change to a cache in Redis similar to Librarian instead of querying DB. - const [subaccount, { - results: transfers, limit: pageSize, offset, total, - }, assets] = await - Promise.all([ + const [subaccount, { results: transfers }, assets] = await Promise.all([ SubaccountTable.findById( subaccountId, ), @@ -69,7 +65,6 @@ class TransfersController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, - page, }, [QueryableField.LIMIT], { @@ -122,9 +117,6 @@ class TransfersController extends Controller { transfers: transfers.map((transfer: TransferFromDatabase) => { return transferToResponseObject(transfer, idToAsset, idToSubaccount, subaccountId); }), - pageSize, - totalResults: total, - offset, }; } } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 50a37df0f9..769bae17fb 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -150,7 +150,7 @@ export interface FillResponseObject { /* ------- TRANSFER TYPES ------- */ -export interface TransferResponse extends PaginationResponse { +export interface TransferResponse { transfers: TransferResponseObject[], } From 5e210366f2b71df5f540d922e9260997e167798a Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Fri, 5 Apr 2024 23:37:17 +0200 Subject: [PATCH 14/17] revert: :rewind: revert add pagination for getTrades and getFills --- .../comlink/public/api-documentation.md | 23 ---------- indexer/services/comlink/public/swagger.json | 42 ------------------- .../controllers/api/v4/fills-controller.ts | 12 +----- .../controllers/api/v4/trades-controller.ts | 12 +----- indexer/services/comlink/src/types.ts | 11 +---- 5 files changed, 4 insertions(+), 96 deletions(-) diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index 6fc03e3ecc..d1af0c5567 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -688,7 +688,6 @@ fetch('https://dydx-testnet.imperator.co/v4/fills?address=string&subaccountNumbe |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| -|page|query|number(double)|false|none| #### Enumerated Values @@ -703,9 +702,6 @@ fetch('https://dydx-testnet.imperator.co/v4/fills?address=string&subaccountNumbe ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "fills": [ { "id": "string", @@ -804,9 +800,6 @@ fetch('https://dydx-testnet.imperator.co/v4/fills/parentSubaccount?address=strin ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "fills": [ { "id": "string", @@ -1973,7 +1966,6 @@ fetch('https://dydx-testnet.imperator.co/v4/trades/perpetualMarket/{ticker}', |limit|query|number(double)|false|none| |createdBeforeOrAtHeight|query|number(double)|false|none| |createdBeforeOrAt|query|[IsoString](#schemaisostring)|false|none| -|page|query|number(double)|false|none| > Example responses @@ -1981,9 +1973,6 @@ fetch('https://dydx-testnet.imperator.co/v4/trades/perpetualMarket/{ticker}', ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "trades": [ { "id": "string", @@ -2975,9 +2964,6 @@ This operation does not require authentication ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "fills": [ { "id": "string", @@ -3004,9 +2990,6 @@ 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| |fills|[[FillResponseObject](#schemafillresponseobject)]|true|none|none| ## HeightResponse @@ -3858,9 +3841,6 @@ or ```json { - "pageSize": 0, - "totalResults": 0, - "offset": 0, "trades": [ { "id": "string", @@ -3880,9 +3860,6 @@ or |Name|Type|Required|Restrictions|Description| |---|---|---|---|---| -|pageSize|number(double)|false|none|none| -|totalResults|number(double)|false|none|none| -|offset|number(double)|false|none|none| |trades|[[TradeResponseObject](#schematraderesponseobject)]|true|none|none| ## TransferType diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 4cf3365cf3..9efb4d4804 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -471,18 +471,6 @@ }, "FillResponse": { "properties": { - "pageSize": { - "type": "number", - "format": "double" - }, - "totalResults": { - "type": "number", - "format": "double" - }, - "offset": { - "type": "number", - "format": "double" - }, "fills": { "items": { "$ref": "#/components/schemas/FillResponseObject" @@ -1078,18 +1066,6 @@ }, "TradeResponse": { "properties": { - "pageSize": { - "type": "number", - "format": "double" - }, - "totalResults": { - "type": "number", - "format": "double" - }, - "offset": { - "type": "number", - "format": "double" - }, "trades": { "items": { "$ref": "#/components/schemas/TradeResponseObject" @@ -1535,15 +1511,6 @@ "schema": { "$ref": "#/components/schemas/IsoString" } - }, - { - "in": "query", - "name": "page", - "required": false, - "schema": { - "format": "double", - "type": "number" - } } ] } @@ -2267,15 +2234,6 @@ "schema": { "$ref": "#/components/schemas/IsoString" } - }, - { - "in": "query", - "name": "page", - "required": false, - "schema": { - "format": "double", - "type": "number" - } } ] } diff --git a/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts b/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts index e4e74bc3b6..0df1441c11 100644 --- a/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/fills-controller.ts @@ -55,7 +55,6 @@ class FillsController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, - @Query() page?: number, ): Promise { // TODO(DEC-656): Change to using a cache of markets in Redis similar to Librarian instead of // querying the DB. @@ -69,12 +68,7 @@ class FillsController extends Controller { } const subaccountId: string = SubaccountTable.uuid(address, subaccountNumber); - const { - results: fills, - limit: pageSize, - offset, - total, - } = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { subaccountId: [subaccountId], clobPairId, @@ -83,7 +77,6 @@ class FillsController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, - page, }, [QueryableField.LIMIT], ); @@ -105,9 +98,6 @@ class FillsController extends Controller { fills: fills.map((fill: FillFromDatabase): FillResponseObject => { return fillToResponseObject(fill, clobPairIdToMarket, subaccountNumber); }), - pageSize, - totalResults: total, - offset, }; } diff --git a/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts b/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts index a9725ac823..f9059b69f4 100644 --- a/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/trades-controller.ts @@ -45,7 +45,6 @@ class TradesController extends Controller { @Query() limit?: number, @Query() createdBeforeOrAtHeight?: number, @Query() createdBeforeOrAt?: IsoString, - @Query() page?: number, ): Promise { const clobPairId: string | undefined = perpetualMarketRefresher .getClobPairIdFromTicker(ticker); @@ -54,12 +53,7 @@ class TradesController extends Controller { throw new NotFoundError(`${ticker} not found in tickers of type ${MarketType.PERPETUAL}`); } - const { - results: fills, - limit: pageSize, - offset, - total, - } = await FillTable.findAll( + const { results: fills } = await FillTable.findAll( { clobPairId, liquidity: Liquidity.TAKER, @@ -68,7 +62,6 @@ class TradesController extends Controller { ? createdBeforeOrAtHeight.toString() : undefined, createdBeforeOrAt, - page, }, [QueryableField.LIQUIDITY, QueryableField.CLOB_PAIR_ID, QueryableField.LIMIT], ); @@ -77,9 +70,6 @@ class TradesController extends Controller { trades: fills.map((fill: FillFromDatabase): TradeResponseObject => { return fillToTradeResponseObject(fill); }), - pageSize, - totalResults: total, - offset, }; } } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index 769bae17fb..256f9179ea 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -40,13 +40,6 @@ export enum RequestMethod { PUT = 'PUT', } -/* ------- Pagination ------- */ -export interface PaginationResponse { - pageSize?: number, - totalResults?: number, - offset?: number, -} - /* ------- SUBACCOUNT TYPES ------- */ export interface AddressResponse { @@ -127,7 +120,7 @@ export type AssetPositionsMap = { [symbol: string]: AssetPositionResponseObject /* ------- FILL TYPES ------- */ -export interface FillResponse extends PaginationResponse { +export interface FillResponse { fills: FillResponseObject[], } @@ -191,7 +184,7 @@ export interface PnlTicksResponseObject { /* ------- TRADE TYPES ------- */ -export interface TradeResponse extends PaginationResponse { +export interface TradeResponse { trades: TradeResponseObject[], } From d1ee4e063152288c66ce704a866ffe3bf03bf12d Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Sat, 6 Apr 2024 17:16:14 +0200 Subject: [PATCH 15/17] feat: :label: add explicit ts types --- .../__tests__/stores/order-table.test.ts | 48 ++++++++++++++----- .../controllers/api/v4/orders-controller.ts | 2 +- .../tasks/cancel-stale-orders.test.ts | 39 +++++++++------ .../src/tasks/cancel-stale-orders.ts | 28 ++++++----- 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/indexer/packages/postgres/__tests__/stores/order-table.test.ts b/indexer/packages/postgres/__tests__/stores/order-table.test.ts index 7a3b92a13b..a5449405df 100644 --- a/indexer/packages/postgres/__tests__/stores/order-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/order-table.test.ts @@ -4,6 +4,7 @@ import { OrderFromDatabase, Ordering, OrderStatus, + PaginationFromDatabase, TimeInForce, } from '../../src/types'; import * as OrderTable from '../../src/stores/order-table'; @@ -49,7 +50,9 @@ describe('Order store', () => { it('Successfully creates an Order with goodTilBlockTime', async () => { await OrderTable.create(defaultOrderGoodTilBlockTime); - const { results: orders } = await OrderTable.findAll({}, [], {}); + const { + results: orders, + }: PaginationFromDatabase = await OrderTable.findAll({}, [], {}); expect(orders).toHaveLength(1); expect(orders[0]).toEqual(expect.objectContaining({ @@ -67,7 +70,9 @@ describe('Order store', () => { }), ]); - const { results: orders } = await OrderTable.findAll({}, [], { + const { + results: orders, + }: PaginationFromDatabase = await OrderTable.findAll({}, [], { orderBy: [[OrderColumns.clientId, Ordering.ASC]], }); @@ -88,7 +93,12 @@ describe('Order store', () => { }), ]); - const responsePageOne = await OrderTable.findAll({ page: 1, limit: 1 }, [], { + const responsePageOne: PaginationFromDatabase = await OrderTable.findAll({ + page: 1, + limit: 1, + }, + [], + { orderBy: [[OrderColumns.clientId, Ordering.ASC]], }); @@ -97,7 +107,12 @@ describe('Order store', () => { expect(responsePageOne.offset).toEqual(0); expect(responsePageOne.total).toEqual(2); - const responsePageTwo = await OrderTable.findAll({ page: 2, limit: 1 }, [], { + const responsePageTwo: PaginationFromDatabase = await OrderTable.findAll({ + page: 2, + limit: 1, + }, + [], + { orderBy: [[OrderColumns.clientId, Ordering.ASC]], }); @@ -109,9 +124,15 @@ describe('Order store', () => { expect(responsePageTwo.offset).toEqual(1); expect(responsePageTwo.total).toEqual(2); - const responsePageAllPages = await OrderTable.findAll({ page: 1, limit: 2 }, [], { - orderBy: [[OrderColumns.clientId, Ordering.ASC]], - }); + const responsePageAllPages: PaginationFromDatabase = await OrderTable + .findAll({ + page: 1, + limit: 2, + }, + [], + { + orderBy: [[OrderColumns.clientId, Ordering.ASC]], + }); expect(responsePageAllPages.results.length).toEqual(2); expect(responsePageAllPages.results[0]).toEqual(expect.objectContaining(defaultOrder)); @@ -150,7 +171,7 @@ describe('Order store', () => { }), ]); - const { results: orders } = await OrderTable.findAll( + const { results: orders }: PaginationFromDatabase = await OrderTable.findAll( { clientId: '1', }, @@ -246,11 +267,12 @@ describe('Order store', () => { OrderTable.create(defaultOrderGoodTilBlockTime), ]); - const { results: orders } = await OrderTable.findAll( - filter, - [], - { readReplica: true }, - ); + const { results: orders }: PaginationFromDatabase = await OrderTable + .findAll( + filter, + [], + { readReplica: true }, + ); expect(orders).toHaveLength(1); expect(orders[0]).toEqual(expect.objectContaining(expectedOrder)); diff --git a/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts b/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts index 63a24d3b33..a44777b283 100644 --- a/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/orders-controller.ts @@ -141,7 +141,7 @@ class OrdersController extends Controller { // then we do not want to return this order to the user as 'BEST_EFFORT_OPENED'. let additionalPostgresOrders: OrderFromDatabase[] = []; if (!_.isEmpty(postgresOrderIdsToFetch)) { - const { results } = await OrderTable.findAll({ + const { results }: PaginationFromDatabase = await OrderTable.findAll({ id: redisOrderIds, }, [], { ...DEFAULT_POSTGRES_OPTIONS, diff --git a/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts b/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts index 243b23432b..77b1ff96b0 100644 --- a/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/cancel-stale-orders.test.ts @@ -1,5 +1,12 @@ import { - BlockTable, OrderFromDatabase, OrderTable, OrderStatus, dbHelpers, testConstants, testMocks, + BlockTable, + OrderFromDatabase, + OrderTable, + OrderStatus, + dbHelpers, + testConstants, + testMocks, + PaginationFromDatabase, } from '@dydxprotocol-indexer/postgres'; import cancelStaleOrdersTask from '../../src/tasks/cancel-stale-orders'; import { defaultOrderGoodTilBlockTime } from '@dydxprotocol-indexer/postgres/build/__tests__/helpers/constants'; @@ -83,13 +90,14 @@ describe('cancel-stale-orders', () => { await cancelStaleOrdersTask(); - const { results: ordersAfterTask } = await OrderTable.findAll( - { - id: createdOrderIds, - }, - [], - {}, - ); + const { results: ordersAfterTask }: PaginationFromDatabase = await OrderTable + .findAll( + { + id: createdOrderIds, + }, + [], + {}, + ); expect(_.sortBy(ordersAfterTask, ['id'])).toEqual(_.sortBy(expectedOrders, ['id'])); expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders.count', 2); expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders_canceled.count', 2); @@ -145,13 +153,14 @@ describe('cancel-stale-orders', () => { expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders.count', 1); expect(stats.gauge).toHaveBeenCalledWith('roundtable.num_stale_orders_canceled.count', 1); - const { results: ordersAfterTask } = await OrderTable.findAll( - { - id: createdOrderIds, - }, - [], - {}, - ); + const { results: ordersAfterTask }: PaginationFromDatabase = await OrderTable + .findAll( + { + id: createdOrderIds, + }, + [], + {}, + ); expect(_.sortBy(ordersAfterTask, ['id'])).toEqual(_.sortBy(expectedOrders, ['id'])); config.CANCEL_STALE_ORDERS_QUERY_BATCH_SIZE = oldLimit; diff --git a/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts b/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts index 2c9e457ae8..505202a6ee 100644 --- a/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts +++ b/indexer/services/roundtable/src/tasks/cancel-stale-orders.ts @@ -7,6 +7,7 @@ import { OrderFromDatabase, OrderStatus, OrderTable, + PaginationFromDatabase, } from '@dydxprotocol-indexer/postgres'; import { ORDER_FLAG_SHORT_TERM } from '@dydxprotocol-indexer/v4-proto-parser'; @@ -22,19 +23,20 @@ export default async function runTask(): Promise { const latestBlockHeight: number = parseInt(latestBlock.blockHeight, 10); - const { results: staleOpenOrders } = await OrderTable.findAll( - { - statuses: [OrderStatus.OPEN], - orderFlags: ORDER_FLAG_SHORT_TERM.toString(), - // goodTilBlock needs to be < latest block height to be guaranteed to be CANCELED - goodTilBlockBeforeOrAt: (latestBlockHeight - 1).toString(), - limit: config.CANCEL_STALE_ORDERS_QUERY_BATCH_SIZE, - }, - [], - { - readReplica: true, - }, - ); + const { results: staleOpenOrders }: PaginationFromDatabase = await OrderTable + .findAll( + { + statuses: [OrderStatus.OPEN], + orderFlags: ORDER_FLAG_SHORT_TERM.toString(), + // goodTilBlock needs to be < latest block height to be guaranteed to be CANCELED + goodTilBlockBeforeOrAt: (latestBlockHeight - 1).toString(), + limit: config.CANCEL_STALE_ORDERS_QUERY_BATCH_SIZE, + }, + [], + { + readReplica: true, + }, + ); stats.timing(`${config.SERVICE_NAME}.cancel_stale_orders.query.timing`, Date.now() - queryStart); const updateStart: number = Date.now(); From f197ad1a56517bafbc329b4a4dfb6cdbba0876e2 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Wed, 10 Apr 2024 19:31:34 +0200 Subject: [PATCH 16/17] docs: :bulb: add pagination todo comment --- indexer/packages/postgres/src/stores/fill-table.ts | 1 + indexer/packages/postgres/src/stores/order-table.ts | 1 + indexer/packages/postgres/src/stores/transfer-table.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/indexer/packages/postgres/src/stores/fill-table.ts b/indexer/packages/postgres/src/stores/fill-table.ts index 07c2369d2d..8e5adaa162 100644 --- a/indexer/packages/postgres/src/stores/fill-table.ts +++ b/indexer/packages/postgres/src/stores/fill-table.ts @@ -164,6 +164,7 @@ export async function findAll( /** * If a query is made using a page number, then the limit property is used as 'page limit' + * TODO: Improve pagination by adding a required eventId for orderBy clause */ if (page !== undefined && limit !== undefined) { /** diff --git a/indexer/packages/postgres/src/stores/order-table.ts b/indexer/packages/postgres/src/stores/order-table.ts index f16a75ea58..d7c3944111 100644 --- a/indexer/packages/postgres/src/stores/order-table.ts +++ b/indexer/packages/postgres/src/stores/order-table.ts @@ -193,6 +193,7 @@ export async function findAll( /** * If a query is made using a page number, then the limit property is used as 'page limit' + * TODO: Improve pagination by adding a required eventId for orderBy clause */ if (page !== undefined && limit !== undefined) { /** diff --git a/indexer/packages/postgres/src/stores/transfer-table.ts b/indexer/packages/postgres/src/stores/transfer-table.ts index 296258d474..dd1afc8bb4 100644 --- a/indexer/packages/postgres/src/stores/transfer-table.ts +++ b/indexer/packages/postgres/src/stores/transfer-table.ts @@ -299,6 +299,7 @@ export async function findAllToOrFromSubaccountId( /** * If a query is made using a page number, then the limit property is used as 'page limit' + * TODO: Improve pagination by adding a required eventId for orderBy clause */ if (page !== undefined && limit !== undefined) { /** From e8bbacef45dfcbd260cd8adff43b1d83767ed187 Mon Sep 17 00:00:00 2001 From: Davide Segullo Date: Thu, 11 Apr 2024 13:40:44 +0200 Subject: [PATCH 17/17] docs(postgres): :bulb: improve pagination comment improve pagination comment thanks to coderabbitai. --- indexer/packages/postgres/src/stores/fill-table.ts | 2 +- indexer/packages/postgres/src/stores/order-table.ts | 2 +- indexer/packages/postgres/src/stores/transfer-table.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/indexer/packages/postgres/src/stores/fill-table.ts b/indexer/packages/postgres/src/stores/fill-table.ts index 8e5adaa162..0ece392045 100644 --- a/indexer/packages/postgres/src/stores/fill-table.ts +++ b/indexer/packages/postgres/src/stores/fill-table.ts @@ -174,7 +174,7 @@ export async function findAll( const offset: number = (currentPage - 1) * limit; /** - * We need to remove the sorting as it is not necessary in this case. + * 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. */ diff --git a/indexer/packages/postgres/src/stores/order-table.ts b/indexer/packages/postgres/src/stores/order-table.ts index d7c3944111..a197dee1a9 100644 --- a/indexer/packages/postgres/src/stores/order-table.ts +++ b/indexer/packages/postgres/src/stores/order-table.ts @@ -203,7 +203,7 @@ export async function findAll( const offset: number = (currentPage - 1) * limit; /** - * We need to remove the sorting as it is not necessary in this case. + * 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. */ diff --git a/indexer/packages/postgres/src/stores/transfer-table.ts b/indexer/packages/postgres/src/stores/transfer-table.ts index dd1afc8bb4..01611b9183 100644 --- a/indexer/packages/postgres/src/stores/transfer-table.ts +++ b/indexer/packages/postgres/src/stores/transfer-table.ts @@ -309,7 +309,7 @@ export async function findAllToOrFromSubaccountId( const offset: number = (currentPage - 1) * limit; /** - * We need to remove the sorting as it is not necessary in this case. + * 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. */