diff --git a/api/src/jobs/cron.ts b/api/src/jobs/cron.ts index 34442f8..fdcae22 100644 --- a/api/src/jobs/cron.ts +++ b/api/src/jobs/cron.ts @@ -10,6 +10,9 @@ export default async function cronRouter( case '* * * * *': console.log('every minute'); break; + case '0 4 7,14,21,28 * *': + await updateThemeparkData(env); + break; default: console.log('its me - the cron router'); break; diff --git a/api/src/jobs/update-themepark-data.ts b/api/src/jobs/update-themepark-data.ts new file mode 100644 index 0000000..c927a3d --- /dev/null +++ b/api/src/jobs/update-themepark-data.ts @@ -0,0 +1,53 @@ +import { getDbEnv } from '../db/client' +import { themepark } from '../db/schema' +import { countryCodesDE } from '../lib/countries' +import fetchData from '../lib/fetch-data' + +interface Park { + id: string, + name: string, + land: string +} + +export async function updateThemeparkData(env: Env): Promise{ + try{ + // fetch all available themeparks from external API + const endpoint = "https://api.wartezeiten.app/v1/parks" + const headers = { + 'language':'de' + } + const availableThemeparks = await fetchData(endpoint, headers); + + // internal db queries + const db = getDbEnv(env); + const currentThemeparks = await db.select({ + apiName: themepark.apiName + }).from(themepark); + + let newParks = []; + + for (let park of availableThemeparks){ + if(currentThemeparks.length == 0 || !currentThemeparks.some(id => id.apiName == park.id)){ // checks if id already exists in db + newParks.push({ + name: park.name, + apiName: park.id, + countrycode: countryCodesDE[park.land] + }); + console.log(`${park.id} is missing in DB`) + } + } + + // only run queries, when new parks were found + if (newParks.length != 0){ + // split into multiple batches, to apply with D1's limits + const batchSize = 20; + for (let i = 0; i < newParks.length; i += batchSize){ + const batch = newParks.slice(i, i + batchSize); + await db.insert(themepark).values(batch); + } + } + } + catch(e){ + console.error(`Failed to update themepark data: ${e}`); + } +} \ No newline at end of file diff --git a/api/src/lib/countries.ts b/api/src/lib/countries.ts new file mode 100644 index 0000000..1e44dbd --- /dev/null +++ b/api/src/lib/countries.ts @@ -0,0 +1,37 @@ +// key value pair countryname (german) to countrycode +// incomplete list with just the countries from the external api (api.wartezeiten.app) +export const countryCodesDE: Record = { + "Belgien":"BE", + "Deutschland":"DE", + "Dänemark":"DK", + "Frankreich":"FR", + "Großbritannien":"GB", + "Italien":"IT", + "Niederlande":"NL", + "Polen":"PL", + "Schweden":"SE", + "Schweiz":"CH", + "Spanien":"ES", + "Vereinigte Staaten":"US", + "Vereinigtes Königreich":"UK", + "Österreich":"AT" +}; + +export const countryCodesEN: Record = { + "Austria":"AT", + "Belgium":"BE", + "Denmark":"DK", + "France":"FR", + "Germany":"DE", + "Great Britain":"GB", + "Italy":"IT", + "Netherlands":"NL", + "Poland":"PL", + "Spain":"ES", + "Sweden":"SE", + "Switzerland":"CH", + "United Kingdom":"UK", + "United States":"US" +}; + +// source: https://de.wikipedia.org/wiki/ISO-3166-1-Kodierliste diff --git a/api/src/lib/fetch-data.ts b/api/src/lib/fetch-data.ts new file mode 100644 index 0000000..c2a07bf --- /dev/null +++ b/api/src/lib/fetch-data.ts @@ -0,0 +1,15 @@ +// typesafe api fetch function +export default async function fetchData(endpoint: string, headers: Record = {}, method: string = 'GET'): Promise{ + async function gatherResponse(response: Response): Promise{ + return await response.json(); + } + + const response: Response = await fetch(endpoint, { method: method, headers: headers}); + + if (!response.ok){ + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const result: T = await gatherResponse(response); + return result; +} \ No newline at end of file