diff --git a/src/custom-functions/bcode-v2.ts b/src/custom-functions/bcode-v2.ts new file mode 100644 index 0000000..9475aa2 --- /dev/null +++ b/src/custom-functions/bcode-v2.ts @@ -0,0 +1,123 @@ +import { HttpError } from '~/api/http-error' +import { CachingBuffettCodeApiClientV2 } from '~/api/v2/caching-client' +import { CachingIndicatorProperty } from '~/api/v2/caching-indicator-property' +import { QuarterProperty } from '~/api/v2/quarter-property' +import { bcodeIndicator } from '~/custom-functions/bcode-indicator' +import { bcodeQuarter } from '~/custom-functions/bcode-quarter' +import { BcodeResult } from '~/custom-functions/bcode-result' +import { + ApiResponseError, + OndemandApiNotEnabledError, + UnsupportedTickerError +} from '~/custom-functions/error' +import { + InvalidLYLQError, + InvalidYearError, + InvalidQuarterError +} from '~/fiscal-periods/error' +import { Setting } from '~/setting' + +function validate( + ticker: string, + fiscalYear: string, + fiscalQuarter: string, + propertyName: string +): void { + if (!ticker) { + throw new Error('<>') + } + + if (!propertyName) { + throw new Error('<>') + } + + const isQuarterProperty = QuarterProperty.isQuarterProperty(propertyName) + const isIndicatorProperty = CachingIndicatorProperty.isIndicatorProperty( + propertyName + ) + + if (!isQuarterProperty && !isIndicatorProperty) { + throw new Error(`<<指定された項目が見つかりません: ${propertyName}>>`) + } +} + +// TODO: エラーハンドリングの改善 +// TODO: fiscalYearとfiscalQuarterの型をstringではなく'LY'と'LQ'に変更する +export function bcodeV2( + ticker: string, + fiscalYear: string | number, + fiscalQuarter: string | number, + propertyName: string, + isRawValue = false, + isWithUnits = false +): number | string { + validate( + ticker, + fiscalYear.toString(), + fiscalQuarter.toString(), + propertyName + ) + + const setting = Setting.load() + if (!setting.token) { + throw new Error('<>') + } + + const client = new CachingBuffettCodeApiClientV2(setting.token) + + try { + let result: BcodeResult + if (fiscalYear && fiscalQuarter) { + result = bcodeQuarter( + client, + ticker, + fiscalYear === 'LY' ? fiscalYear : parseInt(fiscalYear.toString(), 10), + fiscalQuarter === 'LQ' + ? fiscalQuarter + : parseInt(fiscalQuarter.toString(), 10), + propertyName, + setting.ondemandApiEnabled + ) + } else { + result = bcodeIndicator(client, ticker, propertyName) + } + + return result.format(isRawValue, isWithUnits) + } catch (e) { + if (e instanceof ApiResponseError) { + throw new Error('<<指定されたデータを取得できませんでした>>') + } else if (e instanceof OndemandApiNotEnabledError) { + throw new Error('<<従量課金APIが有効になっていません>>') + } else if (e instanceof UnsupportedTickerError) { + throw new Error('<<サポートされていないtickerです>>') + } else if (e instanceof HttpError) { + const code = e.response.getResponseCode() + + if (e.isInvalidTestingRequest()) { + throw new Error('<<テスト用のAPIキーでは取得できないデータです>>') + } else if (code === 403) { + throw new Error('<>') + } else if (code === 429) { + throw new Error('<>') + } else if (Math.floor(code / 100) === 4) { + throw new Error(`<<無効なリクエストです。${e.name}: ${e.message}>>`) + } else { + console.error('システムエラー', e.name, e.message) + throw new Error( + `<<システムエラーが発生しました。${e.name}: ${e.message}>>` + ) + } + } else if (e instanceof InvalidLYLQError) { + throw new Error('<>') + } else if (e instanceof InvalidYearError) { + throw new Error(`<<無効な決算年度が指定されています: ${fiscalYear}>>`) + } else if (e instanceof InvalidQuarterError) { + throw new Error(`<<無効な四半期が指定されています: ${fiscalQuarter}>>`) + } else { + console.error('未定義のエラー', e.name, e.message) + throw new Error( + `<<未定義のエラーが発生しました。${e.name}: ${e.message}>>` + ) + } + } +} diff --git a/src/custom-functions/bcode.test.ts b/src/custom-functions/bcode.test.ts new file mode 100644 index 0000000..78798a6 --- /dev/null +++ b/src/custom-functions/bcode.test.ts @@ -0,0 +1,28 @@ +import { castStringAsBoolean, isV3Call } from '~/custom-functions/bcode' + +test('castStringAsBoolean', () => { + expect(castStringAsBoolean(true)).toBeTruthy() + expect(castStringAsBoolean('true')).toBeTruthy() + expect(castStringAsBoolean('TRUE')).toBeTruthy() + expect(castStringAsBoolean('True')).toBeTruthy() + expect(castStringAsBoolean(false)).toBeFalsy() + expect(castStringAsBoolean('false')).toBeFalsy() + expect(castStringAsBoolean('FALSE')).toBeFalsy() + expect(castStringAsBoolean('False')).toBeFalsy() + expect(castStringAsBoolean('t')).toBeFalsy() + expect(castStringAsBoolean('f')).toBeFalsy() + expect(castStringAsBoolean('')).toBeFalsy() +}) + +test('isV3Call', () => { + expect(isV3Call(2020, 1)).toBeFalsy() + expect(isV3Call(2020, '1')).toBeFalsy() + expect(isV3Call('2020', 1)).toBeFalsy() + expect(isV3Call('2020', '1')).toBeFalsy() + expect(isV3Call('LY', '4')).toBeFalsy() + expect(isV3Call('ly', '4')).toBeFalsy() + expect(isV3Call('2020', 'LQ')).toBeFalsy() + expect(isV3Call('2020', 'lq')).toBeFalsy() + expect(isV3Call('', '')).toBeFalsy() + expect(isV3Call('2020Q1', 'net_sales')).toBeTruthy() +}) diff --git a/src/custom-functions/bcode.ts b/src/custom-functions/bcode.ts index 0da73fc..90cf674 100644 --- a/src/custom-functions/bcode.ts +++ b/src/custom-functions/bcode.ts @@ -1,111 +1,46 @@ -import { HttpError } from '~/api/http-error' -import { CachingBuffettCodeApiClientV2 } from '~/api/v2/caching-client' -import { CachingIndicatorProperty } from '~/api/v2/caching-indicator-property' -import { QuarterProperty } from '~/api/v2/quarter-property' -import { bcodeIndicator } from '~/custom-functions/bcode-indicator' -import { bcodeQuarter } from '~/custom-functions/bcode-quarter' -import { BcodeResult } from '~/custom-functions/bcode-result' -import { - ApiResponseError, - OndemandApiNotEnabledError, - UnsupportedTickerError -} from '~/custom-functions/error' -import { - InvalidLYLQError, - InvalidYearError, - InvalidQuarterError -} from '~/fiscal-periods/error' -import { Setting } from '~/setting' +import { bcodeV2 } from '~/custom-functions/bcode-v2' -function validate( - ticker: string, - fiscalYear: string, - fiscalQuarter: string, - propertyName: string -): void { - if (!ticker) { - throw new Error('<>') - } - - if (!propertyName) { - throw new Error('<>') - } - - const isQuarterProperty = QuarterProperty.isQuarterProperty(propertyName) - const isIndicatorProperty = CachingIndicatorProperty.isIndicatorProperty( - propertyName - ) +export function castStringAsBoolean(bool: string | boolean): boolean { + return typeof bool === 'string' ? bool.toLowerCase() === 'true' : bool +} - if (!isQuarterProperty && !isIndicatorProperty) { - throw new Error(`<<指定された項目が見つかりません: ${propertyName}>>`) +export function isV3Call( + param1: string | number, + param2: string | number +): boolean { + if (typeof param1 === 'number' || typeof param2 === 'number') { + return false + } else if (param1 === '' || param2 === '') { + return false + } else if (param1.toUpperCase() === 'LY' || param2.toUpperCase() === 'LQ') { + return false + } else if (param1.match(/^\d+$/) || param1.match(/^\d+$/)) { + return false + } else { + return true } } -// TODO: エラーハンドリングの改善 export function bcode( ticker: string, - fiscalYear: string, - fiscalQuarter: string, - propertyName: string, - isRawValue = false, - isWithUnits = false + param1: string | number | Date, + param2: string | number, + param3: string | boolean = false, + param4: string | boolean = false, + param5: string | boolean = false ): number | string { - validate(ticker, fiscalYear, fiscalQuarter, propertyName) - - const setting = Setting.load() - if (!setting.token) { - throw new Error('<>') - } - - const client = new CachingBuffettCodeApiClientV2(setting.token) - - try { - let result: BcodeResult - if (fiscalYear && fiscalQuarter) { - result = bcodeQuarter( - client, - ticker, - fiscalYear === 'LY' ? fiscalYear : parseInt(fiscalYear, 10), - fiscalQuarter === 'LQ' ? fiscalQuarter : parseInt(fiscalQuarter, 10), - propertyName, - setting.ondemandApiEnabled - ) - } else { - result = bcodeIndicator(client, ticker, propertyName) - } - - return result.format(isRawValue, isWithUnits) - } catch (e) { - if (e instanceof ApiResponseError) { - throw new Error('<<指定されたデータを取得できませんでした>>') - } else if (e instanceof OndemandApiNotEnabledError) { - throw new Error('<<従量課金APIが有効になっていません>>') - } else if (e instanceof UnsupportedTickerError) { - throw new Error('<<サポートされていないtickerです>>') - } else if (e instanceof HttpError) { - const code = e.response.getResponseCode() - - if (e.isInvalidTestingRequest()) { - throw new Error('<<テスト用のAPIキーでは取得できないデータです>>') - } else if (code === 403) { - throw new Error('<>') - } else if (code === 429) { - throw new Error('<>') - } else if (Math.floor(code / 100) === 4) { - throw new Error('<<無効なリクエストです>>') - } else { - console.error('システムエラー', e.name, e.message) - throw new Error('<<システムエラーが発生しました>>') - } - } else if (e instanceof InvalidLYLQError) { - throw new Error('<>') - } else if (e instanceof InvalidYearError) { - throw new Error(`<<無効な決算年度が指定されています: ${fiscalYear}>>`) - } else if (e instanceof InvalidQuarterError) { - throw new Error(`<<無効な四半期が指定されています: ${fiscalQuarter}>>`) - } else { - console.error('未定義のエラー', e.name, e.message) - throw new Error(`<<未定義のエラー: ${e.name}: ${e.message}>>`) - } + if (param1 instanceof Date || isV3Call(param1, param2)) { + throw new Error( + `<<引数が不正な形式です。param1: ${param1} (${typeof param1}), param2: ${param2} (${typeof param2})>>` + ) + } else { + return bcodeV2( + ticker, + param1, + param2, + param3.toString(), + castStringAsBoolean(param4), + castStringAsBoolean(param5) + ) } }