Skip to content

Commit

Permalink
feat: fetch fees endpoint (#3)
Browse files Browse the repository at this point in the history
* feat: add fees route and get total count by chain

* feat: add chains endpoint to get chain config data

* test: collect coverage from unit tests rather than e2e tests

* feat: add get fees route with pagination

* test: add e2e tests for querying collected fees
  • Loading branch information
kieranroneill authored Mar 16, 2024
1 parent 19b0345 commit b925e1f
Show file tree
Hide file tree
Showing 47 changed files with 17,559 additions and 60 deletions.
11 changes: 0 additions & 11 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@ services:
- plutus_network_test
ports:
- "${APP_PORT:-3000}:${APP_PORT:-3000}"
volumes:
- ./src:/usr/app/src:cached
- ./test:/usr/app/test:cached
- ./jest.config.ts:/usr/app/jest.config.ts:cached
- ./jest.config.e2e.ts:/usr/app/jest.config.e2e.ts:cached
- ./jest.config.unit.ts:/usr/app/jest.config.unit.ts:cached
- ./nest-cli.json:/usr/app/nest-cli.json:cached
- ./package.json:/usr/app/package.json:cached
- ./tsconfig.build.json:/usr/app/tsconfig.build.json:cached
- ./tsconfig.json:/usr/app/tsconfig.json:cached
- ./yarn.lock:/usr/app/yarn.lock:cached

###
# database
Expand Down
4 changes: 1 addition & 3 deletions jest.config.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import baseConfig from './jest.config';

const config: Config = {
...baseConfig,
collectCoverage: true,
collectCoverageFrom: ['<rootDir>/src/**/*.ts', '!<rootDir>/src/**/*.d.ts'],
coverageDirectory: 'coverage',
collectCoverage: false,
testMatch: ['<rootDir>/src/**/e2e.test.ts'],
};

Expand Down
4 changes: 3 additions & 1 deletion jest.config.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import baseConfig from './jest.config';

const config: Config = {
...baseConfig,
collectCoverage: false,
collectCoverage: true,
collectCoverageFrom: ['<rootDir>/src/**/*.ts', '!<rootDir>/src/**/*.d.ts'],
coverageDirectory: 'coverage',
testMatch: ['<rootDir>/src/**/{!(e2e),}.test.ts'],
};

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"husky": "^8.0.3",
"jest": "^29.7.0",
"lint-staged": "^15.2.2",
"mongo-seeding": "^4.0.0",
"prettier": "^3.2.5",
"semantic-release": "^23.0.2",
"source-map-support": "^0.5.21",
Expand All @@ -76,7 +78,10 @@
"@nestjs/event-emitter": "^2.0.4",
"@nestjs/platform-express": "^10.0.0",
"@typegoose/typegoose": "^12.2.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"ethers": "^6.11.1",
"express": "^4.18.3",
"joi": "^17.12.2",
"mongoose": "^8.2.1",
"morgan": "^1.10.0",
Expand Down
1 change: 1 addition & 0 deletions scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function main() {
printf "%b starting docker compose...\n" "${INFO_PREFIX}"
docker compose \
up \
api \
--build

exit 0
Expand Down
1 change: 1 addition & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function main {
-p plutus_test \
-f docker-compose.test.yml \
up \
--build \
-d

# poll the healthchecks
Expand Down
2 changes: 1 addition & 1 deletion src/constants/Durations.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const QUERY_EVENT_DELAY_IN_MILLISECONDS: number = 100; // 100 milliseconds
export const QUERY_EVENT_DELAY_IN_MILLISECONDS: number = 500; // 500 milliseconds
1 change: 1 addition & 0 deletions src/constants/Limiits.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const FEE_PAGINATION_MAX_LIMIT: number = 25;
export const QUERY_EVENT_MAX_LIMIT: number = 100;
2 changes: 2 additions & 0 deletions src/enums/APIPathEnum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
enum APIPathEnum {
Chains = 'chains',
Fees = 'fees',
Versions = 'versions',
}

Expand Down
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoggerService } from '@nestjs/common';
import { LoggerService, ValidationPipe } from '@nestjs/common';
import { NestApplication, NestFactory } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import morgan from 'morgan';
Expand Down Expand Up @@ -39,6 +39,7 @@ import createLoggerService from '@app/utils/createLoggerService';
},
})
);
app.useGlobalPipes(new ValidationPipe()); // for validating query params

await app.listen(
configService.get<number>(EnvironmentVariableKeyEnum.AppPort)
Expand Down
4 changes: 4 additions & 0 deletions src/modules/app/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import * as Joi from 'joi';
import { EnvironmentVariableKeyEnum } from '@app/enums';

// modules
import ChainsModule from '@app/modules/chains/module';
import FeesCollectedEventListenerModule from '@app/modules/fees-collected-event-listener/module';
import FeesModule from '@app/modules/fees/module';
import VersionsModule from '@app/modules/versions/module';

// providers
Expand All @@ -21,6 +23,8 @@ import type { IEnvironmentVariables } from '@app/types';
/**
* api
*/
ChainsModule,
FeesModule,
VersionsModule,

/**
Expand Down
21 changes: 21 additions & 0 deletions src/modules/chains/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller, Get } from '@nestjs/common';

// configs
import { chains } from '@app/configs';

// enums
import { APIPathEnum } from '@app/enums';

// types
import type { IChainResponseBody } from '@app/types';

// utils
import mapChainConfigToChainResponseBody from '@app/utils/mapChainConfigToChainResponseBody';

@Controller(APIPathEnum.Chains)
export default class ChainsController {
@Get()
public async get(): Promise<IChainResponseBody[]> {
return chains.map(mapChainConfigToChainResponseBody);
}
}
31 changes: 31 additions & 0 deletions src/modules/chains/e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { HttpStatus } from '@nestjs/common';
import { agent as request, Response, Agent } from 'supertest';

// configs
import { chains } from '@app/configs';

// enums
import { APIPathEnum } from '@app/enums';

// utils
import mapChainConfigToChainResponseBody from '@app/utils/mapChainConfigToChainResponseBody';

describe(`/${APIPathEnum.Chains}`, () => {
let agent: Agent;

beforeAll(async () => {
agent = request(`http://127.0.0.1:3000`);
});

describe(`GET /${APIPathEnum.Chains}`, () => {
it('should return the chain configuration', async () => {
const response: Response = await agent
.get(`/${APIPathEnum.Chains}`)
.expect(HttpStatus.OK);

expect(response.body).toEqual(
chains.map(mapChainConfigToChainResponseBody)
);
});
});
});
9 changes: 9 additions & 0 deletions src/modules/chains/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';

// controllers
import ChainsController from './controller';

@Module({
controllers: [ChainsController],
})
export default class ChainsModule {}
17 changes: 17 additions & 0 deletions src/modules/fee-repository/dtos/FindByPageDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
interface IProps {
chainId: string;
limit?: number;
page?: number;
}

export default class FindByPageDTO {
public readonly chainId: string;
public readonly limit?: number;
public readonly page?: number;

constructor({ chainId, limit, page }: IProps) {
this.chainId = chainId;
this.limit = limit;
this.page = page;
}
}
1 change: 1 addition & 0 deletions src/modules/fee-repository/dtos/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as CreateDTO } from './CreateDTO';
export { default as FindByPageDTO } from './FindByPageDTO';
1 change: 1 addition & 0 deletions src/modules/fee-repository/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as FeeRepositoryService } from './service';
export * from './dtos';
export * from './types';
3 changes: 0 additions & 3 deletions src/modules/fee-repository/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ const FeeRepositoryProvider: FactoryProvider = {
useFactory: async (mongoose: Mongoose) =>
getModelForClass(FeeSchema, {
existingMongoose: mongoose,
options: {
customName: 'fee',
},
}),
};

Expand Down
49 changes: 48 additions & 1 deletion src/modules/fee-repository/service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Injectable, Inject } from '@nestjs/common';
import { Model } from 'mongoose';

// constants
import { FEE_PAGINATION_MAX_LIMIT } from '@app/constants';

// dtos
import { CreateDTO } from './dtos';
import { CreateDTO, FindByPageDTO } from './dtos';

// enums
import { ProviderNameEnum } from '@app/enums';

// types
import type { IFeeDocument } from '@app/types';
import type { IFindByPageAggregateResult, IFindByPageResult } from './types';

@Injectable()
export default class FeeRepositoryService {
Expand All @@ -21,10 +25,53 @@ export default class FeeRepositoryService {
return await this.model.create(dtos);
}

public async countByChainId(chainId: string): Promise<number> {
return await this.model.countDocuments({ chainId }).exec();
}

public async create(dto: CreateDTO): Promise<IFeeDocument> {
return await this.model.create(dto);
}

public async findByPage({
chainId,
limit = FEE_PAGINATION_MAX_LIMIT,
page = 1,
}: FindByPageDTO): Promise<IFindByPageResult> {
const result: IFindByPageAggregateResult[] =
await this.model.aggregate<IFindByPageAggregateResult>([
{
$match: {
chainId,
},
},
{
$facet: {
metadata: [
{
$count: 'total',
},
],
data: [
{
$skip: (page - 1) * limit,
},
{
$limit: limit,
},
],
},
},
]);

return {
data: result[0].data,
limit,
page,
total: result[0].metadata[0].total,
};
}

public async findLatestBlockNumberForChainId(
chainId: string
): Promise<bigint | null> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// types
import type { IFeeDocument } from '@app/types';

interface IFindByPageAggregateResult {
data: IFeeDocument[];
metadata: Record<'total', number>;
}

export default IFindByPageAggregateResult;
11 changes: 11 additions & 0 deletions src/modules/fee-repository/types/IFindByPageResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// types
import type { IFeeDocument } from '@app/types';

interface IFindByPageResult {
data: IFeeDocument[];
limit: number;
page: number;
total: number;
}

export default IFindByPageResult;
2 changes: 2 additions & 0 deletions src/modules/fee-repository/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as IFindByPageAggregateResult } from './IFindByPageAggregateResult';
export { default as IFindByPageResult } from './IFindByPageResult';
34 changes: 0 additions & 34 deletions src/modules/fees-collected-event-listener/service.test.ts

This file was deleted.

Loading

0 comments on commit b925e1f

Please sign in to comment.