Skip to content

Commit

Permalink
feat: update data to new isin based on stock splits (#42)
Browse files Browse the repository at this point in the history
* fix: update migration path in typeorm

* feat: add findOne to base db class

* feat: update data to new isin for stock splits
  • Loading branch information
danishjoseph authored Jul 28, 2024
1 parent 144ed49 commit b979e32
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,22 @@ export interface DatabaseRepository<T extends ObjectLiteral> {
options: UpsertOptions<T>,
): Promise<InsertResult>;
createQueryBuilder(alias: string): SelectQueryBuilder<T>;
findOne(options: FindOneOptions<T>): Promise<T | null>;
}

export abstract class BaseRepository<T extends ObjectLiteral>
implements DatabaseRepository<T>
{
constructor(protected readonly repository: Repository<T>) {}

findOne(options: FindOneOptions<T>): Promise<T | null> {
return this.repository.findOne(options);
}

async findAll(): Promise<T[]> {
return this.repository.find();
}

// Todo: Remove this method
async findById(id: any): Promise<T | null> {
return this.repository.findOne(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('AssetExchangeService', () => {
{
provide: AssetExchangeRepository,
useValue: {
findOneBy: jest.fn(),
findOne: jest.fn(),
},
},
],
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('AssetExchangeService', () => {
deliveryData: jest.fn(),
};

assetExchangeRepository.findOneBy.mockResolvedValue(
assetExchangeRepository.findOne.mockResolvedValue(
expectedData as unknown as AssetExchange,
);

Expand All @@ -55,12 +55,13 @@ describe('AssetExchangeService', () => {
);

expect(result).toEqual(expectedData);
expect(assetExchangeRepository.findOneBy).toHaveBeenCalledWith(
{
expect(assetExchangeRepository.findOne).toHaveBeenCalledWith({
where: {
asset: { symbol },
exchange,
},
relations,
);
order: { id: 'DESC' },
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ export class AssetExchangeService {
const identifier =
exchange.abbreviation === Ex.NSE ? 'symbol' : 'assetExchangeCode';

return this.assetExchangeRepository.findOneBy(
{
return this.assetExchangeRepository.findOne({
where: {
asset: { [identifier]: symbol },
exchange,
},
relations,
);
relations: relations,
order: { id: 'DESC' },
});
}
}
73 changes: 46 additions & 27 deletions libs/asset-management/src/lib/services/asset.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ describe('AssetService', () => {
let assetService: AssetService;
let assetRepository: AssetRepository;
let assetExchangeRepository: AssetExchangeRepository;
const assetData: AssetDto = {
isin: 'test-isin',
name: 'Test Asset',
symbol: 'TST',
assetExchangeCode: 'TST123',
faceValue: 0,
industry: '',
sector: '',
assetExchanges: [],
};
const exchange = {
id: 1,
name: 'Test Exchange',
abbreviation: 'TST',
} as Exchange;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -16,14 +31,14 @@ describe('AssetService', () => {
{
provide: AssetRepository,
useValue: {
findOneBy: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
},
},
{
provide: AssetExchangeRepository,
useValue: {
findOneBy: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
},
},
Expand All @@ -40,22 +55,10 @@ describe('AssetService', () => {
});

it('should create asset and asset exchange', async () => {
const assetData: AssetDto = {
isin: 'test-isin',
name: 'Test Asset',
symbol: 'TST',
assetExchangeCode: 'TST123',
faceValue: 0,
industry: '',
sector: '',
assetExchanges: [],
};
const exchange = {
const asset: Asset = {
id: 1,
name: 'Test Exchange',
abbreviation: 'TST',
} as Exchange;
const asset: Asset = { id: 1, ...assetData };
...assetData,
};
const assetExchange: AssetExchange = {
id: 1,
asset,
Expand All @@ -64,28 +67,44 @@ describe('AssetService', () => {
deliveryData: [],
};

assetRepository.findOneBy = jest.fn().mockResolvedValueOnce(null);
assetExchangeRepository.findOneBy = jest.fn().mockResolvedValueOnce(null);
assetRepository.create = jest
.fn()
.mockResolvedValueOnce({ id: 1, ...assetData });
assetRepository.findOne = jest.fn().mockResolvedValueOnce(null);
assetExchangeRepository.findOne = jest.fn().mockResolvedValueOnce(null);
assetRepository.create = jest.fn().mockResolvedValueOnce(asset);
assetExchangeRepository.create = jest
.fn()
.mockResolvedValueOnce(assetExchange);

await assetService.createAsset(assetData, exchange);

expect(assetRepository.findOneBy).toHaveBeenCalledWith({
isin: assetData.isin,
expect(assetRepository.findOne).toHaveBeenCalledWith({
where: { isin: assetData.isin },
});
expect(assetExchangeRepository.findOneBy).toHaveBeenCalledWith({
asset: { isin: assetData.isin },
exchange,
expect(assetExchangeRepository.findOne).toHaveBeenCalledWith({
where: { asset: { isin: assetData.isin }, exchange },
});
expect(assetRepository.create).toHaveBeenCalledWith(assetData);
expect(assetExchangeRepository.create).toHaveBeenCalledWith({
asset,
exchange,
});
});

it('should not create asset if it already exists', async () => {
const asset: Asset = {
id: 1,
...assetData,
};

assetRepository.findOne = jest.fn().mockResolvedValueOnce(asset);
assetExchangeRepository.findOne = jest.fn().mockResolvedValueOnce(asset);

await assetService.createAsset(assetData, exchange);

expect(assetRepository.findOne).toHaveBeenCalledWith({
where: { isin: assetData.isin },
});
expect(assetExchangeRepository.findOne).toHaveBeenCalled();
expect(assetRepository.create).not.toHaveBeenCalled();
expect(assetExchangeRepository.create).not.toHaveBeenCalled();
});
});
7 changes: 3 additions & 4 deletions libs/asset-management/src/lib/services/asset.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ export class AssetService {
await validateAndThrowError(assetData, 'AssetDto');

const [existingStock, existingAssetExchange] = await Promise.all([
this.assetRepository.findOneBy({ isin: assetData.isin }),
this.assetExchangeRepository.findOneBy({
asset: { isin: assetData.isin },
exchange,
this.assetRepository.findOne({ where: { isin: assetData.isin } }),
this.assetExchangeRepository.findOne({
where: { asset: { isin: assetData.isin }, exchange },
}),
]);
let savedStock;
Expand Down
4 changes: 2 additions & 2 deletions libs/typeorm/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const dataSourceOptions: DataSourceOptions = {
database: process.env.DB_NAME,
synchronize: false,
logging: true,
entities: ['./src/lib/entities/*.entity{.ts,.js}'],
migrations: ['./src/lib/migrations/*{.ts,.js}'],
entities: ['./libs/typeorm/src/lib/entities/*.entity{.ts,.js}'],
migrations: ['./libs/typeorm/src/lib/migrations/*{.ts,.js}'],
migrationsRun: true,
};

Expand Down

0 comments on commit b979e32

Please sign in to comment.