Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions src/__mocks__/api/v3/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { default as company } from '~/__mocks__/fixtures/v3/company.js'
import { default as daily } from '~/__mocks__/fixtures/v3/daily.js'
import { default as quarter } from '~/__mocks__/fixtures/v3/quarter.js'

export class BuffettCodeApiClientV2 {
export class BuffettCodeApiClientV3 {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここはtypoです…

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これは今までの class 名がよろしくないのね

public mockCompany = jest.fn()
public mockDaily = jest.fn()
public mockQuarter = jest.fn()
Expand All @@ -13,23 +13,28 @@ export class BuffettCodeApiClientV2 {
this.mockQuarter.mockReturnValue(quarter)
}

company(ticker): object | null {
const company = this.mockCompany()[ticker]
return company ? company[0] : null
company(): object | null {
const company = this.mockCompany()['data']
return company ? company : null
}

quarter(ticker): object | null {
const quarter = this.mockQuarter()[ticker]
return quarter ? quarter[0] : null
quarter(): object | null {
const quarter = this.mockQuarter()['data']
return quarter ? quarter : null
}

daily(ticker): object | null {
const daily = this.mockDaily()[ticker]
return daily ? daily[0] : null
daily(): object | null {
const daily = this.mockDaily()['data']
return daily ? daily : null
}

ondemandQuarter(ticker): object | null {
const quarter = this.mockQuarter()[ticker]
return quarter ? quarter[0] : null
ondemandDaily(): object | null {
const daily = this.mockDaily()['data']
return daily ? daily : null
}

ondemandQuarter(): object | null {
const quarter = this.mockQuarter()['data']
return quarter ? quarter : null
}
}
1 change: 1 addition & 0 deletions src/__mocks__/fixtures/v3/daily.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ module.exports = {
}
},
data: {
day: '2020-09-06',
cash_market_capital_ratio: 4.98944759676063,
debt_market_capital_ratio: 1.48298604408628,
dividend_yield_actual: 1.40154169586545,
Expand Down
23 changes: 23 additions & 0 deletions src/__mocks__/services/daily-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DateParam } from '~/fiscal-periods/date-param'

export class DailyCache {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここ、resource 毎にcache class 分ける今みたいな実装と、 end_point + params で cache の key を作って cache としては1つにするか 2つやり方がありそう。

excel の方は後者の作戦だね、リソース管理がめんどくさいから。

static readonly cache = {}

static get(ticker: string, date: Date | DateParam): object | null {
if (date instanceof Date) {
date = new DateParam(date)
}

const cached = DailyCache.cache[`${ticker}-${date}`]
return cached === undefined ? null : cached
}

static put(ticker: string, daily: object): void {
DailyCache.cache[`${ticker}-${daily['day']}`] = daily
}

// for testing
static clearAll(): void {
Object.keys(this.cache).forEach(key => delete this.cache[key])
}
}
182 changes: 182 additions & 0 deletions src/api/v3/caching-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { CompanyCache } from '~/__mocks__/services/company-cache'
import { QuarterCache } from '~/__mocks__/services/quarter-cache'
import { CachingBuffettCodeApiClientV3 } from '~/api/v3/caching-client'
import { DateParam } from '~/fiscal-periods/date-param'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { DailyCache } from '~/services/daily-cache'

jest.mock('~/api/v3/client', () =>
jest.requireActual('~/__mocks__/api/v3/client')
)
jest.mock('~/services/company-cache', () =>
jest.requireActual('~/__mocks__/services/company-cache')
)
jest.mock('~/services/daily-cache', () =>
jest.requireActual('~/__mocks__/services/daily-cache')
)
jest.mock('~/services/quarter-cache', () =>
jest.requireActual('~/__mocks__/services/quarter-cache')
)

describe('company', () => {
const ticker = '2371'

test('(uncached)', () => {
expect(CompanyCache.get(ticker)).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.company(ticker)
expect(res).not.toBeNull()

expect(CompanyCache.get(ticker)).toEqual(res)
})

test('(cached)', () => {
const cached = CompanyCache.get(ticker)
expect(cached).not.toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.company(ticker)
expect(res).toEqual(cached)

expect(CompanyCache.get(ticker)).toEqual(cached)
})
})

describe('daily', () => {
const ticker = '2371'

test('(uncached)', () => {
const date = new DateParam(new Date('2020-09-06'))
expect(DailyCache.get(ticker, date)).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.daily(ticker, date)
expect(res).not.toBeNull()

expect(DailyCache.get(ticker, date)).toEqual(res)
})

test('(cached)', () => {
const date = new DateParam(new Date('2020-09-06'))
const cached = DailyCache.get(ticker, date)
expect(cached).not.toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.daily(ticker, date)
expect(res).toEqual(cached)

expect(DailyCache.get(ticker, date)).toEqual(cached)
})
})

describe('quarter', () => {
const ticker = '2371'

describe('(FY, FQ)', () => {
beforeAll(() => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam(2018, 1)

test('(uncached)', () => {
expect(QuarterCache.get(ticker, period.toYearQuarter())).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.quarter(ticker, period)
expect(res).not.toBeNull()
expect(res['fiscal_year']).toBe(period.year)
expect(res['fiscal_quarter']).toBe(period.quarter)

expect(QuarterCache.get(ticker, period.toYearQuarter())).toEqual(res)
})

test('(cached)', () => {
const cached = QuarterCache.get(ticker, period.toYearQuarter())
expect(cached).not.toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.quarter(ticker, period)
expect(res).toEqual(cached)
expect(res['fiscal_year']).toBe(period.year)
expect(res['fiscal_quarter']).toBe(period.quarter)

expect(QuarterCache.get(ticker, period.toYearQuarter())).toEqual(cached)
})
})

describe('(LY, LQ)', () => {
beforeAll(() => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')

test('(uncached)', () => {
expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.quarter(ticker, period)
expect(res).not.toBeNull()
expect(res['fiscal_year']).toBe(2018)
expect(res['fiscal_quarter']).toBe(1)

expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toEqual(res)
})
})
})

describe('ondemandQuarter', () => {
const ticker = '2371'

describe('(FY, FQ)', () => {
beforeAll(() => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam(2018, 1)

test('(uncached)', () => {
expect(QuarterCache.get(ticker, period.toYearQuarter())).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.ondemandQuarter(ticker, period)
expect(res).not.toBeNull()

expect(QuarterCache.get(ticker, period.toYearQuarter())).toEqual(res)
})

test('(cached)', () => {
const cached = QuarterCache.get(ticker, period.toYearQuarter())
expect(cached).not.toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.ondemandQuarter(ticker, period)
expect(res).toEqual(cached)

expect(QuarterCache.get(ticker, period.toYearQuarter())).toEqual(cached)
})
})

describe('(LY, LQ)', () => {
beforeAll(() => {
QuarterCache.clearAll()
})

const period = new YearQuarterParam('LY', 'LQ')

test('(uncached)', () => {
expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toBeNull()

const client = new CachingBuffettCodeApiClientV3('token')
const res = client.ondemandQuarter(ticker, period)
expect(res).not.toBeNull()
expect(res['fiscal_year']).toBe(2018)
expect(res['fiscal_quarter']).toBe(1)

expect(QuarterCache.get(ticker, new YearQuarter(2018, 1))).toEqual(res)
})
})
})
94 changes: 94 additions & 0 deletions src/api/v3/caching-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { BuffettCodeApiClientV3 } from '~/api/v3/client'
import { DateParam } from '~/fiscal-periods/date-param'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { CompanyCache } from '~/services/company-cache'
import { DailyCache } from '~/services/daily-cache'
import { QuarterCache } from '~/services/quarter-cache'

export class CachingBuffettCodeApiClientV3 extends BuffettCodeApiClientV3 {
constructor(private token: string) {
super(token)
}

company(ticker: string): object {
const cached = CompanyCache.get(ticker)
if (cached) {
return cached
}

const company = super.company(ticker)
CompanyCache.put(ticker, company)

return company
}

daily(ticker: string, date: DateParam): object | null {
const cached = DailyCache.get(ticker, date)
if (cached) {
return cached
}

const daily = super.daily(ticker, date)
if (!daily) {
return null
}

DailyCache.put(ticker, daily)

return daily
}

quarter(ticker: string, period: YearQuarterParam): object | null {
if (period.convertibleToYearQuarter()) {
const cached = QuarterCache.get(ticker, period.toYearQuarter())
if (cached) {
return cached
}
}

const quarter = super.quarter(ticker, period)
if (!quarter) {
return null
}

QuarterCache.put(ticker, quarter)

return quarter
}

ondemandDaily(ticker: string, date: DateParam): object | null {
const cached = DailyCache.get(ticker, date)
if (cached) {
return cached
}

const daily = super.ondemandDaily(ticker, date)
if (!daily) {
return null
}

DailyCache.put(ticker, daily)

return daily
}

ondemandQuarter(ticker: string, period: YearQuarterParam): object | null {
if (period.convertibleToYearQuarter()) {
const cached = QuarterCache.get(ticker, period.toYearQuarter())
if (cached) {
return cached
}
}

const quarter = super.ondemandQuarter(ticker, period)
if (!quarter) {
return null
}

QuarterCache.put(ticker, quarter)

return quarter
}

// TODO: Add bulkDaily and bulkQuarter support
}
Loading