diff --git a/libs/asset-management/src/lib/repositories/base.repository.ts b/libs/asset-management/src/lib/repositories/base.repository.ts index fdfc61c..a616fcd 100644 --- a/libs/asset-management/src/lib/repositories/base.repository.ts +++ b/libs/asset-management/src/lib/repositories/base.repository.ts @@ -20,6 +20,7 @@ export interface DatabaseRepository { options: UpsertOptions, ): Promise; createQueryBuilder(alias: string): SelectQueryBuilder; + findOne(options: FindOneOptions): Promise; } export abstract class BaseRepository @@ -27,10 +28,14 @@ export abstract class BaseRepository { constructor(protected readonly repository: Repository) {} + findOne(options: FindOneOptions): Promise { + return this.repository.findOne(options); + } + async findAll(): Promise { return this.repository.find(); } - + // Todo: Remove this method async findById(id: any): Promise { return this.repository.findOne(id); } diff --git a/libs/asset-management/src/lib/services/asset-exchange.service.test.ts b/libs/asset-management/src/lib/services/asset-exchange.service.test.ts index eb0e29a..f961755 100644 --- a/libs/asset-management/src/lib/services/asset-exchange.service.test.ts +++ b/libs/asset-management/src/lib/services/asset-exchange.service.test.ts @@ -15,7 +15,7 @@ describe('AssetExchangeService', () => { { provide: AssetExchangeRepository, useValue: { - findOneBy: jest.fn(), + findOne: jest.fn(), }, }, ], @@ -44,7 +44,7 @@ describe('AssetExchangeService', () => { deliveryData: jest.fn(), }; - assetExchangeRepository.findOneBy.mockResolvedValue( + assetExchangeRepository.findOne.mockResolvedValue( expectedData as unknown as AssetExchange, ); @@ -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' }, + }); }); }); diff --git a/libs/asset-management/src/lib/services/asset-exchange.service.ts b/libs/asset-management/src/lib/services/asset-exchange.service.ts index d76197e..9cad149 100644 --- a/libs/asset-management/src/lib/services/asset-exchange.service.ts +++ b/libs/asset-management/src/lib/services/asset-exchange.service.ts @@ -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' }, + }); } } diff --git a/libs/asset-management/src/lib/services/asset.service.test.ts b/libs/asset-management/src/lib/services/asset.service.test.ts index 793f6bb..ad93e9f 100644 --- a/libs/asset-management/src/lib/services/asset.service.test.ts +++ b/libs/asset-management/src/lib/services/asset.service.test.ts @@ -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({ @@ -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(), }, }, @@ -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, @@ -64,23 +67,20 @@ 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({ @@ -88,4 +88,23 @@ describe('AssetService', () => { 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(); + }); }); diff --git a/libs/asset-management/src/lib/services/asset.service.ts b/libs/asset-management/src/lib/services/asset.service.ts index c1c9941..858d454 100644 --- a/libs/asset-management/src/lib/services/asset.service.ts +++ b/libs/asset-management/src/lib/services/asset.service.ts @@ -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; diff --git a/libs/typeorm/data-source.ts b/libs/typeorm/data-source.ts index c552325..b1723f8 100644 --- a/libs/typeorm/data-source.ts +++ b/libs/typeorm/data-source.ts @@ -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, };