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
13 changes: 13 additions & 0 deletions src/__mocks__/api/v3/client.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { HTTPResnpose } from '~/__mocks__/api/v3/http-response'
import { default as company } from '~/__mocks__/fixtures/v3/company.js'
import { default as daily } from '~/__mocks__/fixtures/v3/daily.js'
import { default as monthly } from '~/__mocks__/fixtures/v3/monthly.js'
import { default as quarter } from '~/__mocks__/fixtures/v3/quarter.js'
import { HttpError } from '~/api/http-error'
import { Company } from '~/entities/v3/company'
import { Daily } from '~/entities/v3/daily'
import { Monthly } from '~/entities/v3/monthly'
import { Quarter } from '~/entities/v3/quarter'

export class BuffettCodeApiClientV3 {
public mockCompany = jest.fn()
public mockDaily = jest.fn()
public mockMonthly = jest.fn()
public mockQuarter = jest.fn()

constructor(readonly token: string) {
this.mockCompany.mockReturnValue(company)
this.mockDaily.mockReturnValue(daily)
this.mockMonthly.mockReturnValue(monthly)
this.mockQuarter.mockReturnValue(quarter)
}

Expand Down Expand Up @@ -62,4 +66,13 @@ export class BuffettCodeApiClientV3 {

return Quarter.fromResponse(this.mockQuarter())
}

monthly(ticker: string): Monthly {
if (ticker !== '2371') {
const res = new HTTPResnpose()
throw new HttpError('/v3/company', res)
}

return Monthly.fromResponse(this.mockMonthly())
}
}
155 changes: 155 additions & 0 deletions src/__mocks__/fixtures/v3/monthly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
module.exports = {
data: {
ticker: "2371",
year: 2022,
month: 5,
beta: {
years_2: {
start_date: "2020-06-01",
end_date: "2022-05-31",
beta: -0.16,
alpha: -0.01,
r: -0.19,
r_squared: 0.04,
count: 24
},
years_3: {
start_date: "2019-06-01",
end_date: "2022-05-31",
beta: 0.07,
alpha: 0.0,
r: 0.11,
r_squared: 0.01,
count: 36
},
years_5: {
start_date: "2017-06-01",
end_date: "2022-05-31",
beta: 0.12,
alpha: 0.0,
r: 0.19,
r_squared: 0.04,
count: 60
}
},
kpi: [{
name: "全店 売上(円)",
value: 3477000000.0
}]
},
column_description: {
ticker: {
name_jp: "ティッカー",
unit: "なし"
},
year: {
name_jp: "年",
unit: "なし"
},
month: {
name_jp: "月",
unit: "なし"
},
beta: {
years_2: {
start_date: {
name_jp: "開始日",
unit: "日付"
},
end_date: {
name_jp: "終了日",
unit: "日付"
},
beta: {
name_jp: "β",
unit: "なし"
},
alpha: {
name_jp: "α",
unit: "なし"
},
r: {
name_jp: "相関係数",
unit: "なし"
},
r_squared: {
name_jp: "決定係数",
unit: "なし"
},
count: {
name_jp: "利用データ数",
unit: "個"}
},
years_3: {
start_date: {
name_jp: "開始日",
unit: "日付"
},
end_date: {
name_jp: "終了日",
unit: "日付"
},
beta: {
name_jp: "β",
unit: "なし"
},
alpha: {
name_jp: "α",
unit: "なし"
},
r: {
name_jp: "相関係数",
unit: "なし"
},
r_squared: {
name_jp: "決定係数",
unit: "なし"
},
count: {
name_jp: "利用データ数",
unit: "個"
}
},
years_5: {
start_date: {
name_jp: "開始日",
unit: "日付"
},
end_date: {
name_jp: "終了日",
unit: "日付"
},
beta: {
name_jp: "β",
unit: "なし"
},
alpha: {
name_jp: "α",
unit: "なし"
},
r: {
name_jp: "相関係数",
unit: "なし"
},
r_squared: {
name_jp: "決定係数",
unit: "なし"
},
count: {
name_jp: "利用データ数",
unit: "個"
}
}
},
kpi: {
name: {
name_jp: "指標",
unit: "なし"
},
value: {
name_jp: "値",
unit: "指標による"
}
}
}
}
44 changes: 44 additions & 0 deletions src/__mocks__/services/monthly-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Monthly } from '~/entities/v3/monthly'
import { YearMonth } from '~/fiscal-periods/year-month'

export class MonthlyCache {
static readonly cache = {}

static get(ticker: string, yearMonth: YearMonth): Monthly | null {
const cachedData = this.getData(ticker, yearMonth)
const cachedColumnDescription = this.getColumnDescription()
if (cachedData == undefined || cachedColumnDescription == undefined) {
return null
}

return new Monthly(cachedData, cachedColumnDescription)
}

private static getData(ticker: string, yearMonth: YearMonth): object | null {
const cached = this.cache[`${ticker}-${yearMonth}`]
return cached === undefined ? null : cached
}

private static getColumnDescription(): object | null {
const cached = this.cache['column-description']
return cached === undefined ? null : cached
}

static put(ticker: string, monthly: Monthly): void {
this.putData(ticker, monthly)
this.putColumnDescription(monthly.columnDescription)
}

private static putData(ticker: string, monthly: Monthly): void {
this.cache[`${ticker}-${monthly.period()}`] = monthly.data
}

private static putColumnDescription(columnDescription: object): void {
this.cache['column-description'] = columnDescription
}

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

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/monthly-cache', () => jest.requireActual('~/__mocks__/services/monthly-cache'))
jest.mock('~/services/quarter-cache', () => jest.requireActual('~/__mocks__/services/quarter-cache'))

const LY = new LyWithOffset()
Expand Down Expand Up @@ -208,3 +211,36 @@ describe('ondemandDaily', () => {
expect(DailyCache.get(ticker, period)).toEqual(cached)
})
})

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

beforeAll(() => {
MonthlyCache.clearAll()
})

const period = new YearMonth(2022, 5)

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

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

expect(MonthlyCache.get(ticker, period)).toEqual(res)
})

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

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

expect(MonthlyCache.get(ticker, period)).toEqual(cached)
})
})
15 changes: 15 additions & 0 deletions src/api/v3/caching-client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { BuffettCodeApiClientV3 } from '~/api/v3/client'
import { Company } from '~/entities/v3/company'
import { Daily } from '~/entities/v3/daily'
import { Monthly } from '~/entities/v3/monthly'
import { Quarter } from '~/entities/v3/quarter'
import { DateParam } from '~/fiscal-periods/date-param'
import { YearMonth } from '~/fiscal-periods/year-month'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { CompanyCache } from '~/services/company-cache'
import { DailyCache } from '~/services/daily-cache'
import { MonthlyCache } from '~/services/monthly-cache'
import { QuarterCache } from '~/services/quarter-cache'

export class CachingBuffettCodeApiClientV3 extends BuffettCodeApiClientV3 {
Expand Down Expand Up @@ -77,5 +80,17 @@ export class CachingBuffettCodeApiClientV3 extends BuffettCodeApiClientV3 {
return quarter
}

monthly(ticker: string, period: YearMonth): Monthly {
const cached = MonthlyCache.get(ticker, period)
if (cached) {
return cached
}

const monthly = super.monthly(ticker, period)
MonthlyCache.put(ticker, monthly)

return monthly
}

// TODO: Add bulkDaily and bulkQuarter support
}
19 changes: 19 additions & 0 deletions src/api/v3/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import * as company from '~/__mocks__/fixtures/v3/company'
import * as daily from '~/__mocks__/fixtures/v3/daily'
import * as monthly from '~/__mocks__/fixtures/v3/monthly'
import * as quarter from '~/__mocks__/fixtures/v3/quarter'
import { HttpError } from '~/api/http-error'
import { useMockedUrlFetchApp } from '~/api/test-helper'
import { BuffettCodeApiClientV3 } from '~/api/v3/client'
import { Company } from '~/entities/v3/company'
import { Daily } from '~/entities/v3/daily'
import { Monthly } from '~/entities/v3/monthly'
import { Quarter } from '~/entities/v3/quarter'
import { DateParam } from '~/fiscal-periods/date-param'
import { DateRange } from '~/fiscal-periods/date-range'
import { LqWithOffset } from '~/fiscal-periods/lq-with-offset'
import { LyWithOffset } from '~/fiscal-periods/ly-with-offset'
import { YearMonth } from '~/fiscal-periods/year-month'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
import { YearQuarterRange } from '~/fiscal-periods/year-quarter-range'
Expand Down Expand Up @@ -210,4 +213,20 @@ describe('BuffettCodeApiClientV3', () => {
muteHttpExceptions: true
})
})

test('monthly', () => {
const mockFetch = useMockedUrlFetchApp(200, JSON.stringify(monthly))

const client = new BuffettCodeApiClientV3('foo')
const ticker = '2371'
const period = new YearMonth(2018, 1)
expect(client.monthly(ticker, period)).toEqual(Monthly.fromResponse(monthly))
expect(mockFetch.mock.calls.length).toBe(1)
expect(mockFetch.mock.calls[0].length).toBe(2)
expect(mockFetch.mock.calls[0][0]).toBe('https://api.buffett-code.com/api/v3/monthly?ticker=2371&year=2018&month=1')
expect(mockFetch.mock.calls[0][1]).toEqual({
headers: { 'x-api-key': 'foo' },
muteHttpExceptions: true
})
})
})
Loading