diff --git a/deno.json b/deno.json index 63286cb..a13d20f 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@bedna/czech-covid-data-api-lib", - "version": "1.3.0", + "version": "1.4.0", "exports": "./src/index.ts", "license": "MIT", "tasks": { diff --git a/src/basic-overview/basic-overview.ts b/src/basic-overview/basic-overview.ts index 2be7716..ea2362f 100644 --- a/src/basic-overview/basic-overview.ts +++ b/src/basic-overview/basic-overview.ts @@ -23,7 +23,7 @@ export default class BasicOverview { * @param param0.itemsPerPage * @param param0.properties */ - public async getBasicOverviewV3({ + public getBasicOverviewV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -31,7 +31,7 @@ export default class BasicOverview { page?: number; itemsPerPage?: number; properties?: string[]; - } = {}): Promise<[BasicOverviewItemArr, null] | [null, GetApiError]> { + } = {}): Promise<[BasicOverviewItemArr, null] | [null, GetApiError]> => { return await new ApiCallBuilder({ token: this.token, }) @@ -40,7 +40,7 @@ export default class BasicOverview { { itemsPerPage }, { properties }, ]).build(); - } + }; /** * Handles call to `/api/v3/zakladni-prehled/:date`. diff --git a/src/client/client.ts b/src/client/client.ts index abfb2c8..f6fcd94 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -7,6 +7,7 @@ import VaccinationPlaces from "../vaccination/vaccination-places.ts"; import VaccinationFacilities from "../vaccination/vaccination-facilities.ts"; import VaccinationDeaths from "../vaccination/vaccination-deaths.ts"; import VaccinationDemographic from "../vaccination/vaccination-demographic.ts"; +import Helpers from "../helpers/helpers.ts"; /** * Represents single entrypoint for calling supported @@ -35,6 +36,8 @@ export default class Client { public readonly vaccinationDeaths: VaccinationDeaths; /** @property vaccinationDemographic - represents instance of the VaccinationDemographic class */ public readonly vaccinationDemographic: VaccinationDemographic; + /** @property helpers - represents instance of the Helpers class */ + public readonly helpers: Helpers; /** @property instance - holds the singleton instance of the class */ private static instance: Client; @@ -61,6 +64,8 @@ export default class Client { this.vaccinationFacilities = new VaccinationFacilities(this.token); this.vaccinationDeaths = new VaccinationDeaths(this.token); this.vaccinationDemographic = new VaccinationDemographic(this.token); + + this.helpers = new Helpers(this.token); } /** diff --git a/src/deaths/deaths.ts b/src/deaths/deaths.ts index f273ad5..89b51c7 100644 --- a/src/deaths/deaths.ts +++ b/src/deaths/deaths.ts @@ -8,7 +8,7 @@ export default class Deaths { this.token = token; } - public async getDeathsV3({ + public getDeathsV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -38,7 +38,7 @@ export default class Deaths { vekLte?: string; pohlavi?: string | string[]; krajNutsKod?: string; - } = {}): Promise<[DeathsItemArr, null] | [null, GetApiError]> { + } = {}): Promise<[DeathsItemArr, null] | [null, GetApiError]> => { return await new ApiCallBuilder({ token: this.token, }) @@ -58,7 +58,7 @@ export default class Deaths { { pohlavi }, { krajNutsKod }, ]).build(); - } + }; public async getDeathsOfIdV3( { id }: { id: string }, diff --git a/src/helpers/helpers.ts b/src/helpers/helpers.ts new file mode 100644 index 0000000..83243bd --- /dev/null +++ b/src/helpers/helpers.ts @@ -0,0 +1,12 @@ +import Sequential from "./sequential.ts"; +export default class Helpers { + private readonly token: string; + + public readonly sequential: Sequential; + + constructor(token: string) { + this.token = token; + + this.sequential = new Sequential(); + } +} diff --git a/src/helpers/sequential.ts b/src/helpers/sequential.ts new file mode 100644 index 0000000..b5c2311 --- /dev/null +++ b/src/helpers/sequential.ts @@ -0,0 +1,42 @@ +import type { GetApiError } from "../common/api.ts"; + +export default class Sequential { + constructor() {} + + public async callEndpoint( + handler: ( + { page, itemsPerPage }: { page?: number; itemsPerPage?: number }, + ) => Promise<[T, null] | [null, GetApiError]>, + options: { + pages: { start?: number; end?: number }; + itemsPerPage?: number; + waitAfterCall?: number; + }, + ): Promise> { + const data: Array<[T, null] | [null, GetApiError]> = []; + + const startPage = options.pages.start || 1; + const endPage = options.pages.end || Infinity; + + for (let page = startPage; page <= endPage; page++) { + const result = await handler({ + page, + itemsPerPage: options.itemsPerPage, + }); + + if (Array.isArray(result[0]) && result[0].length === 0) { + break; + } + + data.push(result); + + if (typeof options.waitAfterCall === "number") { + await new Promise((resolve) => + setTimeout(resolve, options.waitAfterCall) + ); + } + } + + return data; + } +} diff --git a/src/helpers/sequential_test.ts b/src/helpers/sequential_test.ts new file mode 100644 index 0000000..660ba7e --- /dev/null +++ b/src/helpers/sequential_test.ts @@ -0,0 +1,66 @@ +import { beforeAll, describe, it } from "@std/testing/bdd"; +import { expect } from "@std/expect"; +import "@std/dotenv/load"; +import Client from "../index.ts"; + +let client: Client; + +describe("helpers", () => { + beforeAll(() => { + client = Client.getInstance({ token: Deno.env.get("CLIENT_TOKEN") }); + }); + + describe("call sequentially same api endpoint", () => { + it("happy - hospitalizations - should return data of all called pages", async () => { + const result = await client.helpers.sequential.callEndpoint( + client.hospitalization.getHospitalizationsV3, + { pages: { start: 1, end: 10 }, itemsPerPage: 1 }, + ); + + expect(result).toBeInstanceOf(Array); + expect(result).toHaveLength(10); + expect(result[0]).toBeInstanceOf(Array); + expect(result[0][1]).toBeNull(); + expect(result[0][0]).toHaveLength(1); + }); + + it("happy - deaths - should return data of all called pages", async () => { + const result = await client.helpers.sequential.callEndpoint( + client.deaths.getDeathsV3, + { pages: { start: 5, end: 20 }, itemsPerPage: 1 }, + ); + + expect(result).toBeInstanceOf(Array); + expect(result).toHaveLength(16); + expect(result[0]).toBeInstanceOf(Array); + expect(result[0][1]).toBeNull(); + expect(result[0][0]).toHaveLength(1); + }); + + it("happy - deaths - do not provide pages.start and itemsPerPage options returns data", async () => { + const result = await client.helpers.sequential.callEndpoint( + client.deaths.getDeathsV3, + { pages: { end: 2 } }, + ); + + expect(result).toBeInstanceOf(Array); + expect(result).toHaveLength(2); + expect(result[0]).toBeInstanceOf(Array); + expect(result[0][1]).toBeNull(); + expect(result[0][0]).toHaveLength(100); + }); + + it("happy - hospitalizations - should return data of all called pages with 1 second wait after each call", async () => { + const result = await client.helpers.sequential.callEndpoint( + client.hospitalization.getHospitalizationsV3, + { pages: { end: 2 }, itemsPerPage: 1, waitAfterCall: 1000 }, + ); + + expect(result).toBeInstanceOf(Array); + expect(result).toHaveLength(2); + expect(result[0]).toBeInstanceOf(Array); + expect(result[0][1]).toBeNull(); + expect(result[0][0]).toHaveLength(1); + }); + }); +}); diff --git a/src/hospitalizations/hospitalizations.ts b/src/hospitalizations/hospitalizations.ts index afe2483..7a94a54 100644 --- a/src/hospitalizations/hospitalizations.ts +++ b/src/hospitalizations/hospitalizations.ts @@ -7,7 +7,7 @@ export default class Hospitalizations { this.token = token; } - public async getHospitalizationsV3( + public getHospitalizationsV3 = async ( { page = 1, itemsPerPage = 100, @@ -25,7 +25,7 @@ export default class Hospitalizations { datumAfter?: string; datumStrictlyAfter?: string; } = {}, - ): Promise<[HospitalizationsDataItemArr, null] | [null, GetApiError]> { + ): Promise<[HospitalizationsDataItemArr, null] | [null, GetApiError]> => { return await new ApiCallBuilder({ token: this.token, }) @@ -42,7 +42,7 @@ export default class Hospitalizations { { datumStrictlyAfter }, ], ).build(); - } + }; public async getHospitalizationOfId( { id }: { id: string }, diff --git a/src/incidence/incidence.ts b/src/incidence/incidence.ts index 6488891..db95688 100644 --- a/src/incidence/incidence.ts +++ b/src/incidence/incidence.ts @@ -7,7 +7,7 @@ export default class Incidence { this.token = token; } - public async getIncidence714CzV3({ + public getIncidence714CzV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -23,7 +23,7 @@ export default class Incidence { datumAfter?: string; datumStrictlyBefore?: string; datumStrictlyAfter?: string; - } = {}): Promise<[IncidenceDataItemArr, null] | [null, GetApiError]> { + } = {}): Promise<[IncidenceDataItemArr, null] | [null, GetApiError]> => { const [data, err] = await new ApiCallBuilder({ token: this.token }) .provideEndpoint("/api/v3/incidence-7-14-cr").provideQueryParams([ { page }, @@ -40,7 +40,7 @@ export default class Incidence { } return [data as IncidenceDataItemArr, null]; - } + }; public async getIncidence714CzOfIdV3({ id, diff --git a/src/vaccination/vaccination-aggregated.ts b/src/vaccination/vaccination-aggregated.ts index cb0e143..7af283b 100644 --- a/src/vaccination/vaccination-aggregated.ts +++ b/src/vaccination/vaccination-aggregated.ts @@ -8,7 +8,7 @@ export default class VaccinationAggregated { this.token = token; } - public async getVaccinationV3({ + public getVaccinationV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -34,7 +34,7 @@ export default class VaccinationAggregated { vekovaSkupina?: string | string[]; } = {}): Promise< [VaccinationAggregatedItemArr, null] | [null, GetApiError] - > { + > => { return await new ApiCallBuilder({ token: this.token, }) @@ -51,7 +51,7 @@ export default class VaccinationAggregated { { krajNazev }, { vekovaSkupina }, ]).build(); - } + }; public async getVaccinationOfIdV3( { id }: { id: string }, diff --git a/src/vaccination/vaccination-deaths.ts b/src/vaccination/vaccination-deaths.ts index d3a2b8a..f64d67d 100644 --- a/src/vaccination/vaccination-deaths.ts +++ b/src/vaccination/vaccination-deaths.ts @@ -8,7 +8,7 @@ export default class VaccinationDeaths { this.token = token; } - public async getVaccinationDeathsV3({ + public getVaccinationDeathsV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -24,7 +24,7 @@ export default class VaccinationDeaths { datumStrictlyBefore?: string; datumAfter?: string; datumStrictlyAfter?: string; - } = {}): Promise<[VaccinationDeathsItemArr, null] | [null, GetApiError]> { + } = {}): Promise<[VaccinationDeathsItemArr, null] | [null, GetApiError]> => { return await new ApiCallBuilder({ token: this.token, }).provideEndpoint("/api/v3/ockovani-umrti").provideQueryParams([ @@ -36,7 +36,7 @@ export default class VaccinationDeaths { { datumAfter }, { datumStrictlyAfter }, ]).build(); - } + }; public async getVaccinationDeathsOfIdV3( { id }: { id: string }, diff --git a/src/vaccination/vaccination-demographic.ts b/src/vaccination/vaccination-demographic.ts index 1b13c9b..cc059b4 100644 --- a/src/vaccination/vaccination-demographic.ts +++ b/src/vaccination/vaccination-demographic.ts @@ -8,7 +8,7 @@ export default class VaccinationDemographic { this.token = token; } - public async getVaccinationDemographicDataV3({ + public getVaccinationDemographicDataV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -32,7 +32,7 @@ export default class VaccinationDemographic { pohlavi?: "M" | "Z" | ("M" | "Z")[]; } = {}): Promise< [VaccinationDemographicDataItemArr, null] | [null, GetApiError] - > { + > => { return await new ApiCallBuilder({ token: this.token, }).provideEndpoint( @@ -49,7 +49,7 @@ export default class VaccinationDemographic { { poradiDavky }, { pohlavi }, ]).build(); - } + }; public async getVaccinationDemographicDataOfIdV3( { id }: { id: string }, diff --git a/src/vaccination/vaccination-facilities.ts b/src/vaccination/vaccination-facilities.ts index f28472d..ec47fd0 100644 --- a/src/vaccination/vaccination-facilities.ts +++ b/src/vaccination/vaccination-facilities.ts @@ -8,7 +8,7 @@ export default class VaccinationFacilities { this.token = token; } - public async getVaccinationFacilitiesV3({ + public getVaccinationFacilitiesV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -42,7 +42,7 @@ export default class VaccinationFacilities { praktickyLekarDospeli?: boolean; } = {}): Promise< [VaccinationFacilitiesItemArr, null] | [null, GetApiError] - > { + > => { return await new ApiCallBuilder({ token: this.token, }).provideEndpoint( @@ -64,7 +64,7 @@ export default class VaccinationFacilities { { praktickyLekarDeti }, { praktickyLekarDospeli }, ]).build(); - } + }; public async getVaccinationFacilitiesOfIdV3( { id }: { id: string }, diff --git a/src/vaccination/vaccination-places.ts b/src/vaccination/vaccination-places.ts index 3867415..ff41af4 100644 --- a/src/vaccination/vaccination-places.ts +++ b/src/vaccination/vaccination-places.ts @@ -8,7 +8,7 @@ export default class VaccinationPlaces { this.token = token; } - public async getVaccinationPlacesV3({ + public getVaccinationPlacesV3 = async ({ page = 1, itemsPerPage = 100, properties, @@ -36,7 +36,7 @@ export default class VaccinationPlaces { zarizeniKod?: string | string[]; zarizeniNazev?: string | string[]; poradiDavky?: 1 | 2 | 3 | number[]; - } = {}): Promise<[VaccinationPlacesItemArr, null] | [null, GetApiError]> { + } = {}): Promise<[VaccinationPlacesItemArr, null] | [null, GetApiError]> => { return await new ApiCallBuilder({ token: this.token, }) @@ -55,7 +55,7 @@ export default class VaccinationPlaces { { zarizeniNazev }, { poradiDavky }, ]).build(); - } + }; public async getVaccinationPlacesOfIdV3( { id }: { id: string },