-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[OTE-750] Affiliates new affiliate info table (#2179)
- Loading branch information
1 parent
ffde811
commit f4bb592
Showing
14 changed files
with
331 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
indexer/packages/postgres/__tests__/stores/affiliate-info-table.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { AffiliateInfoFromDatabase } from '../../src/types'; | ||
import { clearData, migrate, teardown } from '../../src/helpers/db-helpers'; | ||
import { defaultAffiliateInfo, defaultAffiliateInfo1 } from '../helpers/constants'; | ||
import * as AffiliateInfoTable from '../../src/stores/affiliate-info-table'; | ||
|
||
describe('Affiliate info store', () => { | ||
beforeAll(async () => { | ||
await migrate(); | ||
}); | ||
|
||
afterEach(async () => { | ||
await clearData(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await teardown(); | ||
}); | ||
|
||
it('Successfully creates affiliate info', async () => { | ||
await AffiliateInfoTable.create(defaultAffiliateInfo); | ||
}); | ||
|
||
it('Cannot create duplicate info for duplicate address', async () => { | ||
await AffiliateInfoTable.create(defaultAffiliateInfo); | ||
await expect(AffiliateInfoTable.create(defaultAffiliateInfo)).rejects.toThrowError(); | ||
}); | ||
|
||
it('Can upsert affiliate info multiple times', async () => { | ||
await AffiliateInfoTable.upsert(defaultAffiliateInfo); | ||
let info: AffiliateInfoFromDatabase | undefined = await AffiliateInfoTable.findById( | ||
defaultAffiliateInfo.address, | ||
); | ||
expect(info).toEqual(expect.objectContaining(defaultAffiliateInfo)); | ||
|
||
await AffiliateInfoTable.upsert(defaultAffiliateInfo1); | ||
info = await AffiliateInfoTable.findById(defaultAffiliateInfo1.address); | ||
expect(info).toEqual(expect.objectContaining(defaultAffiliateInfo1)); | ||
}); | ||
|
||
it('Successfully finds all affiliate infos', async () => { | ||
await Promise.all([ | ||
AffiliateInfoTable.create(defaultAffiliateInfo), | ||
AffiliateInfoTable.create(defaultAffiliateInfo1), | ||
]); | ||
|
||
const infos: AffiliateInfoFromDatabase[] = await AffiliateInfoTable.findAll( | ||
{}, | ||
[], | ||
{ readReplica: true }, | ||
); | ||
|
||
expect(infos.length).toEqual(2); | ||
expect(infos).toEqual(expect.arrayContaining([ | ||
expect.objectContaining(defaultAffiliateInfo), | ||
expect.objectContaining(defaultAffiliateInfo1), | ||
])); | ||
}); | ||
|
||
it('Successfully finds an affiliate info', async () => { | ||
await AffiliateInfoTable.create(defaultAffiliateInfo); | ||
|
||
const info: AffiliateInfoFromDatabase | undefined = await AffiliateInfoTable.findById( | ||
defaultAffiliateInfo.address, | ||
); | ||
|
||
expect(info).toEqual(expect.objectContaining(defaultAffiliateInfo)); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
.../postgres/src/db/migrations/migration_files/20240830165511_create_affiliate_info_table.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import * as Knex from 'knex'; | ||
|
||
export async function up(knex: Knex): Promise<void> { | ||
return knex.schema.createTable('affiliate_info', (table) => { | ||
table.string('address').primary().notNullable(); | ||
table.decimal('affiliateEarnings').notNullable(); | ||
table.integer('referredMakerTrades').notNullable(); | ||
table.integer('referredTakerTrades').notNullable(); | ||
table.decimal('totalReferredFees').notNullable(); | ||
table.integer('totalReferredUsers').notNullable(); | ||
table.decimal('referredNetProtocolEarnings').notNullable(); | ||
table.bigInteger('firstReferralBlockHeight').notNullable(); | ||
}); | ||
} | ||
|
||
export async function down(knex: Knex): Promise<void> { | ||
return knex.schema.dropTable('affiliate_info'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
indexer/packages/postgres/src/models/affiliate-info-model.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { NonNegativeNumericPattern } from '../lib/validators'; | ||
import UpsertQueryBuilder from '../query-builders/upsert'; | ||
import BaseModel from './base-model'; | ||
|
||
export default class AffiliateInfoModel extends BaseModel { | ||
static get tableName() { | ||
return 'affiliate_info'; | ||
} | ||
|
||
static get idColumn() { | ||
return 'address'; | ||
} | ||
|
||
static get jsonSchema() { | ||
return { | ||
type: 'object', | ||
required: [ | ||
'address', | ||
'affiliateEarnings', | ||
'referredMakerTrades', | ||
'referredTakerTrades', | ||
'totalReferredFees', | ||
'totalReferredUsers', | ||
'referredNetProtocolEarnings', | ||
'firstReferralBlockHeight', | ||
], | ||
properties: { | ||
address: { type: 'string' }, | ||
affiliateEarnings: { type: 'string', pattern: NonNegativeNumericPattern }, | ||
referredMakerTrades: { type: 'int' }, | ||
referredTakerTrades: { type: 'int' }, | ||
totalReferredFees: { type: 'string', pattern: NonNegativeNumericPattern }, | ||
totalReferredUsers: { type: 'int' }, | ||
referredNetProtocolEarnings: { type: 'string', pattern: NonNegativeNumericPattern }, | ||
firstReferralBlockHeight: { type: 'string', pattern: NonNegativeNumericPattern }, | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* A mapping from column name to JSON conversion expected. | ||
* See getSqlConversionForDydxModelTypes for valid conversions. | ||
* | ||
* TODO(IND-239): Ensure that jsonSchema() / sqlToJsonConversions() / model fields match. | ||
*/ | ||
static get sqlToJsonConversions() { | ||
return { | ||
address: 'string', | ||
affiliateEarnings: 'string', | ||
referredMakerTrades: 'int', | ||
referredTakerTrades: 'int', | ||
totalReferredFees: 'string', | ||
totalReferredUsers: 'int', | ||
referredNetProtocolEarnings: 'string', | ||
firstReferralBlockHeight: 'string', | ||
}; | ||
} | ||
|
||
QueryBuilderType!: UpsertQueryBuilder<this>; | ||
|
||
address!: string; | ||
|
||
affiliateEarnings!: string; | ||
|
||
referredMakerTrades!: number; | ||
|
||
referredTakerTrades!: number; | ||
|
||
totalReferredFees!: string; | ||
|
||
totalReferredUsers!: number; | ||
|
||
referredNetProtocolEarnings!: string; | ||
|
||
firstReferralBlockHeight!: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
indexer/packages/postgres/src/stores/affiliate-info-table.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { QueryBuilder } from 'objection'; | ||
|
||
import { DEFAULT_POSTGRES_OPTIONS } from '../constants'; | ||
import { setupBaseQuery, verifyAllRequiredFields } from '../helpers/stores-helpers'; | ||
import Transaction from '../helpers/transaction'; | ||
import AffiliateInfoModel from '../models/affiliate-info-model'; | ||
import { | ||
Options, | ||
Ordering, | ||
QueryableField, | ||
QueryConfig, | ||
AffiliateInfoColumns, | ||
AffiliateInfoCreateObject, | ||
AffiliateInfoFromDatabase, | ||
AffiliateInfoQueryConfig, | ||
} from '../types'; | ||
|
||
export async function findAll( | ||
{ | ||
address, | ||
limit, | ||
}: AffiliateInfoQueryConfig, | ||
requiredFields: QueryableField[], | ||
options: Options = DEFAULT_POSTGRES_OPTIONS, | ||
): Promise<AffiliateInfoFromDatabase[]> { | ||
verifyAllRequiredFields( | ||
{ | ||
address, | ||
limit, | ||
} as QueryConfig, | ||
requiredFields, | ||
); | ||
|
||
let baseQuery: QueryBuilder<AffiliateInfoModel> = setupBaseQuery<AffiliateInfoModel>( | ||
AffiliateInfoModel, | ||
options, | ||
); | ||
|
||
if (address) { | ||
baseQuery = baseQuery.where(AffiliateInfoColumns.address, address); | ||
} | ||
|
||
if (options.orderBy !== undefined) { | ||
for (const [column, order] of options.orderBy) { | ||
baseQuery = baseQuery.orderBy( | ||
column, | ||
order, | ||
); | ||
} | ||
} else { | ||
baseQuery = baseQuery.orderBy( | ||
AffiliateInfoColumns.address, | ||
Ordering.ASC, | ||
); | ||
} | ||
|
||
if (limit) { | ||
baseQuery = baseQuery.limit(limit); | ||
} | ||
|
||
return baseQuery.returning('*'); | ||
} | ||
|
||
export async function create( | ||
AffiliateInfoToCreate: AffiliateInfoCreateObject, | ||
options: Options = { txId: undefined }, | ||
): Promise<AffiliateInfoFromDatabase> { | ||
return AffiliateInfoModel.query( | ||
Transaction.get(options.txId), | ||
).insert(AffiliateInfoToCreate).returning('*'); | ||
} | ||
|
||
export async function upsert( | ||
AffiliateInfoToUpsert: AffiliateInfoCreateObject, | ||
options: Options = { txId: undefined }, | ||
): Promise<AffiliateInfoFromDatabase> { | ||
const AffiliateInfos: AffiliateInfoModel[] = await AffiliateInfoModel.query( | ||
Transaction.get(options.txId), | ||
).upsert(AffiliateInfoToUpsert).returning('*'); | ||
// should only ever be one AffiliateInfo | ||
return AffiliateInfos[0]; | ||
} | ||
export async function findById( | ||
address: string, | ||
options: Options = DEFAULT_POSTGRES_OPTIONS, | ||
): Promise<AffiliateInfoFromDatabase | undefined> { | ||
const baseQuery: QueryBuilder<AffiliateInfoModel> = setupBaseQuery<AffiliateInfoModel>( | ||
AffiliateInfoModel, | ||
options, | ||
); | ||
return baseQuery | ||
.findById(address) | ||
.returning('*'); | ||
} |
Oops, something went wrong.