diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 3ab0385..ac2fbde 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -18,13 +18,11 @@ interface IRequestParams { state?: string } -interface IGetAttrDataParams { - attribute: string, +interface IGetItemParams { + requestString: string, + countyOrState: string, geographicLevel: string, - cropUnits: string, - location: string, year: string - state?: string } export const fetchDataWithRetry = async (req: string, maxRetries = 3) => { @@ -134,7 +132,14 @@ export const createTableFromSelections = async (selectedOptions: IStateOptions) const {geographicLevel, states, cropUnits, years, ...subOptions} = selectedOptions; try { const allAttrs = getAllAttrs(selectedOptions); - const items = await getItems(selectedOptions); + const requests = getAllRequests(selectedOptions); + const promises = []; + for (const req of requests) { + const {requestString, year, countyOrState} = req; + const res = getItem({requestString, year, countyOrState, geographicLevel: req.geographicLevel}); + promises.push(res); + } + const items = await Promise.all(promises); await connect.getNewDataContext(); await connect.createTopCollection(geographicLevel); await connect.createSubCollection(geographicLevel, allAttrs); @@ -148,97 +153,79 @@ export const createTableFromSelections = async (selectedOptions: IStateOptions) } }; -const getItems = async (selectedOptions: IStateOptions) => { +const getAllRequests = (selectedOptions: IStateOptions) => { let {states, years} = selectedOptions; - const multipleStatesSelected = states.length > 1 || states[0] === "All States"; - const multipleYearsSelected = years.length > 1; const countySelected = selectedOptions.geographicLevel === "County"; if (states[0] === "All States") { states = fiftyStates; } - const promises = []; - - if (multipleStatesSelected) { - for (const state of states) { - if (multipleYearsSelected) { - for (const year of years) { - if (countySelected) { - const allCounties = countyData[state]; - for (const county of allCounties) { - const item = getDataForSingleYearAndState(selectedOptions, county, year, state); - promises.push(item); - } - } else { - const item = getDataForSingleYearAndState(selectedOptions, state, year); - promises.push(item); - } + const requests = []; + + for (const state of states) { + const locations = countySelected ? countyData[state] : [state]; + for (const year of years) { + for (const location of locations) { + const req = getRequest(selectedOptions, location, year, state); + if (req) { + requests.push(req); } - } else { - const item = getDataForSingleYearAndState(selectedOptions, state, years[0]); - promises.push(item); } } - } else { - if (countySelected) { - const allCounties = countyData[states[0]]; - for (const county of allCounties) { - const item = getDataForSingleYearAndState(selectedOptions, county, years[0], states[0]); - promises.push(item); - } - } else { - const item = getDataForSingleYearAndState(selectedOptions, states[0], years[0]); - promises.push(item); - } } - return await Promise.all(promises); -}; -const getDataForSingleYearAndState = async (selectedOptions: IStateOptions, countyOrState: string, year: string, state?: string) => { - const {geographicLevel, states, years, cropUnits, ...subOptions} = selectedOptions; + return requests; +}; - let item: any = { - [geographicLevel]: countyOrState, - "Year": year, - }; +const getItem = async ({requestString, countyOrState, geographicLevel, year}: IGetItemParams) => { + const attrData = await getAttrData(requestString); + if (Object.keys(attrData).length) { + return { + [geographicLevel]: countyOrState, + "Year": year, + ...attrData + }; + } +}; +const getRequest = (selectedOptions: IStateOptions, countyOrState: string, year: string, state?: string) => { + const {geographicLevel, states, years, cropUnits, ...subOptions} = selectedOptions; for (const key in subOptions) { const value = subOptions[key as keyof typeof subOptions]; - if (value && Array.isArray(value)) { - for (const attribute of value) { - const queryParams = getQueryParams(attribute); - const yearAvailable = queryParams?.years[geographicLevel].includes(year); - const isMultiStateRegion = queryParams?.geographicAreas[0] === "REGION : MULTI-STATE"; - const geoLevel = isMultiStateRegion ? "REGION : MULTI-STATE" : geographicLevel; - if (yearAvailable) { - let location = countyOrState; - if (isMultiStateRegion) { - const itemToCheck = state ? state : countyOrState; - const regData = multiRegions.find((region) => region.States.includes(itemToCheck)); - location = regData?.Region ? regData.Region : countyOrState; - } - const params: IGetAttrDataParams = {attribute, geographicLevel: geoLevel, location, year, cropUnits}; - if (geoLevel === "County") { - params.state = state; - } - const attrData = await getAttrData(params); - item = {...item, ...attrData}; + for (const attribute of value) { + const queryParams = getQueryParams(attribute); + const yearAvailable = queryParams?.years[geographicLevel].includes(year); + const isMultiStateRegion = queryParams?.geographicAreas[0] === "REGION : MULTI-STATE"; + const geoLevel = isMultiStateRegion ? "REGION : MULTI-STATE" : geographicLevel; + if (yearAvailable) { + let location = countyOrState; + if (isMultiStateRegion) { + const itemToCheck = state ? state : countyOrState; + const regData = multiRegions.find((region) => region.States.includes(itemToCheck)); + location = regData?.Region ? regData.Region : countyOrState; + } + const params: IRequestParams = {attribute, geographicLevel: geoLevel, location, year}; + if (geoLevel === "County") { + params.state = state; } + if (cropOptions.options.includes(attribute) && cropUnits) { + params.cropCategory = cropUnits as keyof ICropDataItem; + } + return { + requestString: createRequest(params), + countyOrState, + geographicLevel, + year + }; } } - } - return item; + } }; -const getAttrData = async (params: IGetAttrDataParams) => { - const {attribute, geographicLevel, location, year, cropUnits, state} = params; - const reqParams: IRequestParams = {attribute, geographicLevel, location, year, state}; - if (cropOptions.options.includes(attribute) && cropUnits) { - reqParams.cropCategory = cropUnits as keyof ICropDataItem; - } - const req = createRequest(reqParams); + +const getAttrData = async (req: string) => { const res = await fetchDataWithRetry(req); const values: any = {}; if (res) { @@ -249,7 +236,7 @@ const getAttrData = async (params: IGetAttrDataParams) => { }); } else { // eslint-disable-next-line no-console - console.log(`Error: did not receive response for item with these params: ${params}`); + console.log(`Error: did not receive response for this request:`, req); } return values; };