Skip to content

Commit

Permalink
[OTE-543] Add leaderboard pnl table (#1938)
Browse files Browse the repository at this point in the history
Co-authored-by: Christopher-Li <Christopher-Li@users.noreply.github.com>
  • Loading branch information
affanv14 and Christopher-Li authored Jul 18, 2024
1 parent 6da7590 commit cdb8a78
Show file tree
Hide file tree
Showing 12 changed files with 415 additions and 0 deletions.
35 changes: 35 additions & 0 deletions indexer/packages/postgres/__tests__/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
FillCreateObject,
FillType,
FundingIndexUpdatesCreateObject,
LeaderboardPnlCreateObject,
Liquidity,
LiquidityTiersCreateObject,
MarketCreateObject,
Expand Down Expand Up @@ -855,3 +856,37 @@ export const duplicatedSubaccountUsername: SubaccountUsernamesCreateObject = {
username: 'LyingRaisin32',
subaccountId: defaultSubaccountId3,
};

// ============== Leaderboard pnl Data ==============

export const defaultLeaderboardPnlOneDay: LeaderboardPnlCreateObject = {
subaccountId: defaultSubaccountId,
timeSpan: 'ONE_DAY',
pnl: '10000',
currentEquity: '1000',
rank: 1,
};

export const defaultLeaderboardPnl2OneDay: LeaderboardPnlCreateObject = {
subaccountId: defaultSubaccountId2,
timeSpan: 'ONE_DAY',
pnl: '100',
currentEquity: '10000',
rank: 2,
};

export const defaultLeaderboardPnl1AllTime: LeaderboardPnlCreateObject = {
subaccountId: defaultSubaccountId,
timeSpan: 'ALL_TIME',
pnl: '10000',
currentEquity: '1000',
rank: 1,
};

export const defaultLeaderboardPnlOneDayToUpsert: LeaderboardPnlCreateObject = {
subaccountId: defaultSubaccountId,
timeSpan: 'ONE_DAY',
pnl: '100000',
currentEquity: '1000',
rank: 1,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { LeaderboardPnlFromDatabase } from '../../src/types';
import * as LeaderboardPnlTable from '../../src/stores/leaderboard-pnl-table';
import { clearData, migrate, teardown } from '../../src/helpers/db-helpers';
import {
defaultLeaderboardPnl2OneDay,
defaultLeaderboardPnlOneDay,
defaultLeaderboardPnl1AllTime,
defaultLeaderboardPnlOneDayToUpsert,
} from '../helpers/constants';
import { seedData } from '../helpers/mock-generators';

describe('LeaderboardPnl store', () => {
beforeEach(async () => {
await seedData();
});

beforeAll(async () => {
await migrate();
});

afterEach(async () => {
await clearData();
});

afterAll(async () => {
await teardown();
});

it('Successfully creates a LeaderboardPnl', async () => {
await LeaderboardPnlTable.create(defaultLeaderboardPnlOneDay);
});

it('Successfully creates multiple LeaderboardPnls', async () => {
await Promise.all([
LeaderboardPnlTable.create(defaultLeaderboardPnlOneDay),
LeaderboardPnlTable.create(defaultLeaderboardPnl2OneDay),
LeaderboardPnlTable.create(defaultLeaderboardPnl1AllTime),
]);

const leaderboardPnls: LeaderboardPnlFromDatabase[] = await LeaderboardPnlTable.findAll(
{},
[],
);

expect(leaderboardPnls.length).toEqual(3);
});

it('Successfully finds LeaderboardPnl with subaccountId and timespan', async () => {
await Promise.all([
LeaderboardPnlTable.create(defaultLeaderboardPnlOneDay),
LeaderboardPnlTable.create(defaultLeaderboardPnl2OneDay),
LeaderboardPnlTable.create(defaultLeaderboardPnl1AllTime),
]);

const leaderboardPnl: LeaderboardPnlFromDatabase[] = await LeaderboardPnlTable.findAll(
{
subaccountId: [defaultLeaderboardPnlOneDay.subaccountId],
timeSpan: [defaultLeaderboardPnlOneDay.timeSpan],
},
[],
);

expect(leaderboardPnl.length).toEqual(1);
expect(leaderboardPnl[0]).toEqual(expect.objectContaining(defaultLeaderboardPnlOneDay));
});

it('Successfully upserts a LeaderboardPnl', async () => {
await LeaderboardPnlTable.upsert(defaultLeaderboardPnlOneDay);

await LeaderboardPnlTable.upsert(defaultLeaderboardPnlOneDayToUpsert);

const leaderboardPnls: LeaderboardPnlFromDatabase[] = await LeaderboardPnlTable.findAll(
{},
[],
);

expect(leaderboardPnls.length).toEqual(1);
expect(leaderboardPnls[0]).toEqual(
expect.objectContaining(defaultLeaderboardPnlOneDayToUpsert));
});

it('Successfully bulk upserts LeaderboardPnls', async () => {
await LeaderboardPnlTable.bulkUpsert(
[defaultLeaderboardPnlOneDay, defaultLeaderboardPnl2OneDay]);

const leaderboardPnls: LeaderboardPnlFromDatabase[] = await LeaderboardPnlTable.findAll(
{},
[],
);

expect(leaderboardPnls.length).toEqual(2);
expect(leaderboardPnls[0]).toEqual(expect.objectContaining(defaultLeaderboardPnlOneDay));
expect(leaderboardPnls[1]).toEqual(expect.objectContaining(defaultLeaderboardPnl2OneDay));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as Knex from 'knex';

export async function up(knex: Knex): Promise<void> {
return knex.schema.createTable('leaderboard_pnl', (table) => {
table.uuid('subaccountId').notNullable().references('id').inTable('subaccounts');
table.enum(
'timeSpan',
[
'ONE_DAY',
'SEVEN_DAYS',
'THIRTY_DAYS',
'ONE_YEAR',
'ALL_TIME',
],
);
table.string('pnl').notNullable();
table.string('currentEquity').notNullable();
table.integer('rank').notNullable();
table.primary(['subaccountId', 'timeSpan']);
});
}

export async function down(knex: Knex): Promise<void> {
return knex.schema.dropTable('leaderboard_pnl');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as Knex from 'knex';

export async function up(knex: Knex): Promise<void> {
await knex.raw(`
CREATE INDEX CONCURRENTLY IF NOT EXISTS "leaderboard_pnl_rank_timespan_index" ON leaderboard_pnl("rank", "timeSpan");
`);
}

export async function down(knex: Knex): Promise<void> {
await knex.raw(`
DROP INDEX CONCURRENTLY IF EXISTS "leaderboard_pnl_rank_timespan_index";
`);
}

export const config = {
transaction: false,
};
1 change: 1 addition & 0 deletions indexer/packages/postgres/src/helpers/db-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const layer2Tables = [
'perpetual_positions',
'fills',
'subaccount_usernames',
'leaderboard_pnl',
];

const layer1Tables = [
Expand Down
2 changes: 2 additions & 0 deletions indexer/packages/postgres/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export { default as TransferModel } from './models/transfer-model';
export { default as TradingRewardModel } from './models/trading-reward-model';
export { default as TradingRewardAggregationModel } from './models/trading-reward-aggregation-model';
export { default as SubaccountUsernamesModel } from './models/subaccount-usernames-model';
export { default as LeaderboardPnlModel } from './models/leaderboard-pnl-model';

export * as AssetTable from './stores/asset-table';
export * as AssetPositionTable from './stores/asset-position-table';
Expand All @@ -40,6 +41,7 @@ export * as ComplianceTable from './stores/compliance-table';
export * as ComplianceStatusTable from './stores/compliance-status-table';
export * as TradingRewardTable from './stores/trading-reward-table';
export * as TradingRewardAggregationTable from './stores/trading-reward-aggregation-table';
export * as LeaderboardPnlTable from './stores/leaderboard-pnl-table';
export * as SubaccountUsernamesTable from './stores/subaccount-usernames-table';

export * as perpetualMarketRefresher from './loops/perpetual-market-refresher';
Expand Down
61 changes: 61 additions & 0 deletions indexer/packages/postgres/src/models/leaderboard-pnl-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import path from 'path';

import { Model } from 'objection';

import { NumericPattern } from '../lib/validators';
import UpsertQueryBuilder from '../query-builders/upsert';
import BaseModel from './base-model';

export default class LeaderboardPnlModel extends BaseModel {

static get tableName() {
return 'leaderboard_pnl';
}

static get idColumn() {
return ['subaccountId', 'timeSpan'];
}

static relationMappings = {
subaccount: {
relation: Model.BelongsToOneRelation,
modelClass: path.join(__dirname, 'subaccount-model'),
join: {
from: 'leaderboard_pnl.subaccountId',
to: 'subaccounts.id',
},
},
};

static get jsonSchema() {
return {
type: 'object',
required: [
'subaccountId',
'timeSpan',
'pnl',
'currentEquity',
'rank',
],
properties: {
subaccountId: { type: 'string' },
timeSpan: { type: 'string' },
pnl: { type: 'string', pattern: NumericPattern },
currentEquity: { type: 'string', pattern: NumericPattern },
rank: { type: 'integer' },
},
};
}

subaccountId!: string;

timeSpan!: string;

QueryBuilderType!: UpsertQueryBuilder<this>;

pnl!: string;

currentEquity!: string;

rank!: number;
}
Loading

0 comments on commit cdb8a78

Please sign in to comment.