-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
231 additions
and
10 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { | ||
Column, | ||
Entity, | ||
JoinColumn, | ||
OneToOne, | ||
PrimaryGeneratedColumn, | ||
UpdateDateColumn, | ||
} from 'typeorm'; | ||
import { Stock } from './stock.entity'; | ||
|
||
@Entity('stock_detail') | ||
export class StockDetail { | ||
@PrimaryGeneratedColumn() | ||
id: number; | ||
|
||
@OneToOne(() => Stock) | ||
@JoinColumn({ name: 'stock_id' }) | ||
stock: Stock; | ||
|
||
@Column({ | ||
type: 'decimal', | ||
precision: 20, | ||
scale: 2, | ||
}) | ||
marketCap: number; | ||
|
||
@Column({ type: 'integer' }) | ||
eps: number; | ||
|
||
@Column({ type: 'decimal', precision: 6, scale: 3 }) | ||
per: number; | ||
|
||
@Column({ type: 'integer' }) | ||
high52w: number; | ||
|
||
@Column({ type: 'integer' }) | ||
low52w: number; | ||
|
||
@UpdateDateColumn({ type: 'timestamp', name: 'updated_at' }) | ||
updatedAt: Date; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
|
||
export class StockDetailResponse { | ||
@ApiProperty({ | ||
description: '주식의 시가 총액', | ||
example: 352510000000000, | ||
}) | ||
marketCap: number; | ||
|
||
@ApiProperty({ | ||
description: '주식의 EPS', | ||
example: 4091, | ||
}) | ||
eps: number; | ||
|
||
@ApiProperty({ | ||
description: '주식의 PER', | ||
example: 17.51, | ||
}) | ||
per: number; | ||
|
||
@ApiProperty({ | ||
description: '주식의 52주 최고가', | ||
example: 88000, | ||
}) | ||
high52w: number; | ||
|
||
@ApiProperty({ | ||
description: '주식의 52주 최저가', | ||
example: 53000, | ||
}) | ||
low52w: number; | ||
} |
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
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,75 @@ | ||
import { NotFoundException } from '@nestjs/common'; | ||
import { DataSource } from 'typeorm'; | ||
import { Logger } from 'winston'; | ||
import { StockDetail } from './domain/stockDetail.entity'; | ||
import { StockDetailService } from './stockDetail.service'; | ||
import { createDataSourceMock } from '@/user/user.service.spec'; | ||
|
||
const logger: Logger = { | ||
error: jest.fn(), | ||
warn: jest.fn(), | ||
info: jest.fn(), | ||
} as unknown as Logger; | ||
|
||
describe('StockDetailService 테스트', () => { | ||
const stockId = 'A005930'; | ||
|
||
test('stockId로 주식 상세 정보를 조회한다.', async () => { | ||
const mockStockDetail = { | ||
stock: { id: stockId }, | ||
marketCap: 352510000000000, | ||
eps: 4091, | ||
per: 17.51, | ||
high52w: 88000, | ||
low52w: 53000, | ||
}; | ||
const managerMock = { | ||
existsBy: jest.fn().mockResolvedValue(true), | ||
findBy: jest.fn().mockResolvedValue([mockStockDetail]), | ||
}; | ||
const dataSource = createDataSourceMock(managerMock); | ||
const stockDetailService = new StockDetailService( | ||
dataSource as DataSource, | ||
logger, | ||
); | ||
|
||
const result = await stockDetailService.getStockDetailByStockId(stockId); | ||
|
||
expect(managerMock.existsBy).toHaveBeenCalledWith(StockDetail, { | ||
stock: { id: stockId }, | ||
}); | ||
expect(managerMock.findBy).toHaveBeenCalledWith(StockDetail, { | ||
stock: { id: stockId }, | ||
}); | ||
expect(result).toMatchObject({ | ||
marketCap: expect.any(Number), | ||
eps: expect.any(Number), | ||
per: expect.any(Number), | ||
high52w: expect.any(Number), | ||
low52w: expect.any(Number), | ||
}); | ||
expect(result.marketCap).toEqual(mockStockDetail.marketCap); | ||
expect(result.eps).toEqual(mockStockDetail.eps); | ||
expect(result.per).toEqual(mockStockDetail.per); | ||
expect(result.high52w).toEqual(mockStockDetail.high52w); | ||
expect(result.low52w).toEqual(mockStockDetail.low52w); | ||
}); | ||
|
||
test('존재하지 않는 stockId로 조회 시 예외를 발생시킨다.', async () => { | ||
const managerMock = { | ||
existsBy: jest.fn().mockResolvedValue(false), | ||
}; | ||
const dataSource = createDataSourceMock(managerMock); | ||
const stockDetailService = new StockDetailService( | ||
dataSource as DataSource, | ||
logger, | ||
); | ||
|
||
await expect( | ||
stockDetailService.getStockDetailByStockId('nonexistentId'), | ||
).rejects.toThrow(NotFoundException); | ||
expect(logger.warn).toHaveBeenCalledWith( | ||
`stock detail not found (stockId: nonexistentId)`, | ||
); | ||
}); | ||
}); |
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,35 @@ | ||
import { Injectable, Inject, NotFoundException } from '@nestjs/common'; | ||
import { plainToInstance } from 'class-transformer'; | ||
import { DataSource } from 'typeorm'; | ||
import { Logger } from 'winston'; | ||
import { StockDetail } from './domain/stockDetail.entity'; | ||
import { StockDetailResponse } from './dto/stockDetail.response'; | ||
|
||
@Injectable() | ||
export class StockDetailService { | ||
constructor( | ||
private readonly datasource: DataSource, | ||
@Inject('winston') private readonly logger: Logger, | ||
) {} | ||
|
||
async getStockDetailByStockId(stockId: string): Promise<StockDetailResponse> { | ||
return await this.datasource.transaction(async (manager) => { | ||
const isExists = await manager.existsBy(StockDetail, { | ||
stock: { id: stockId }, | ||
}); | ||
|
||
if (!isExists) { | ||
this.logger.warn(`stock detail not found (stockId: ${stockId})`); | ||
throw new NotFoundException( | ||
`stock detail not found (stockId: ${stockId}`, | ||
); | ||
} | ||
|
||
const stockDetail = await manager.findBy(StockDetail, { | ||
stock: { id: stockId }, | ||
}); | ||
|
||
return plainToInstance(StockDetailResponse, stockDetail[0]); | ||
}); | ||
} | ||
} |
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