Skip to content

Commit

Permalink
🔨 crude extraction of fetching functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
danyx23 committed Dec 25, 2024
1 parent a4d3539 commit c3986a5
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 143 deletions.
10 changes: 5 additions & 5 deletions packages/@ourworldindata/explorer/src/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ export class Explorer
grapher.setAuthoredVersion(config)
grapher.reset()
grapher.updateFromObject(config)
grapher.downloadData()
// grapher.downloadData()
}

@action.bound async updateGrapherFromExplorerUsingVariableIds() {
Expand Down Expand Up @@ -742,11 +742,11 @@ export class Explorer
if (dimensions.length === 0) {
// If dimensions are empty, explicitly set the table to an empty table
// so we don't end up confusingly showing stale data from a previous chart
grapher.receiveOwidData(new Map())
// grapher.receiveOwidData(new Map())
} else {
await grapher.downloadLegacyDataFromOwidVariableIds(
inputTableTransformer
)
// await grapher.downloadLegacyDataFromOwidVariableIds(
// inputTableTransformer
// )
}
}

Expand Down
156 changes: 156 additions & 0 deletions packages/@ourworldindata/grapher/src/core/FetchingGrapher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import {
GrapherInterface,
MultipleOwidVariableDataDimensionsMap,
OwidVariableDataMetadataDimensions,
} from "@ourworldindata/types"
import React from "react"
import { Grapher } from "./Grapher.js"
import { loadVariableDataAndMetadata } from "./loadVariable.js"
import { legacyToOwidTableAndDimensions } from "./LegacyToOwidTable.js"
import { OwidTable } from "@ourworldindata/core-table"

export interface FetchingGrapherProps {
config?: GrapherInterface
configUrl?: string
queryString?: string
dataApiUrl: string
}
export async function FetchingGrapher(
props: FetchingGrapherProps
): Promise<React.JSX.Element | null> {
// if config is not provided, fetch it from configUrl

const [config, setConfig] = React.useState<GrapherInterface | undefined>(
undefined
)

const [inputTable, setInputTable] = React.useState<OwidTable | undefined>(
undefined
)

React.useEffect(() => {
async function fetchConfigAndLoadData(): Promise<void> {
if (!config && props.configUrl) {
const fetchedConfig = await fetch(props.configUrl).then((res) =>
res.json()
)
setConfig(fetchedConfig)
}
if (!config) return
const dimensions = config.dimensions || []
if (dimensions.length === 0) return
const variables = dimensions.map((d) => d.variableId)
const variablesDataMap = await loadVariablesDataSite(
variables,
props.dataApiUrl
)
const inputTable = legacyToOwidTableAndDimensions(
variablesDataMap,
dimensions
)
setInputTable(inputTable)
}
void fetchConfigAndLoadData()
}, [props.configUrl, config, props.dataApiUrl])

if (!config) return null
if (!inputTable) return null
return <Grapher table={inputTable} queryStr={props.queryString} />
}

// async function loadVariablesDataAdmin(
// variableFetchBaseUrl: string | undefined,
// variableIds: number[]
// ): Promise<MultipleOwidVariableDataDimensionsMap> {
// const dataFetchPath = (variableId: number): string =>
// variableFetchBaseUrl
// ? `${variableFetchBaseUrl}/v1/variableById/data/${variableId}`
// : `/api/data/variables/data/${variableId}.json`
// const metadataFetchPath = (variableId: number): string =>
// variableFetchBaseUrl
// ? `${variableFetchBaseUrl}/v1/variableById/metadata/${variableId}`
// : `/api/data/variables/metadata/${variableId}.json`

// const loadVariableDataPromises = variableIds.map(async (variableId) => {
// const dataPromise = window.admin.getJSON(
// dataFetchPath(variableId)
// ) as Promise<OwidVariableMixedData>
// const metadataPromise = window.admin.getJSON(
// metadataFetchPath(variableId)
// ) as Promise<OwidVariableWithSourceAndDimension>
// const [data, metadata] = await Promise.all([
// dataPromise,
// metadataPromise,
// ])
// return { data, metadata: { ...metadata, id: variableId } }
// })
// const variablesData: OwidVariableDataMetadataDimensions[] =
// await Promise.all(loadVariableDataPromises)
// const variablesDataMap = new Map(
// variablesData.map((data) => [data.metadata.id, data])
// )
// return variablesDataMap
// }

async function loadVariablesDataSite(
variableIds: number[],
dataApiUrl: string
): Promise<MultipleOwidVariableDataDimensionsMap> {
const loadVariableDataPromises = variableIds.map((variableId) =>
loadVariableDataAndMetadata(variableId, dataApiUrl)
)
const variablesData: OwidVariableDataMetadataDimensions[] =
await Promise.all(loadVariableDataPromises)
const variablesDataMap = new Map(
variablesData.map((data) => [data.metadata.id, data])
)
return variablesDataMap
}

// function downloadData(): void {
// if (this.manuallyProvideData) {
// } else if (this.owidDataset) {
// this._receiveOwidDataAndApplySelection(this.owidDataset)
// } else void this.downloadLegacyDataFromOwidVariableIds()
// }

// async function downloadLegacyDataFromOwidVariableIds(
// inputTableTransformer?: ChartTableTransformer
// ): Promise<void> {
// if (this.variableIds.length === 0)
// // No data to download
// return

// try {
// let variablesDataMap: MultipleOwidVariableDataDimensionsMap

// const startMark = performance.now()
// if (this.useAdminAPI) {
// // TODO grapher model: switch this to downloading multiple data and metadata files
// variablesDataMap = await loadVariablesDataAdmin(
// this.dataApiUrlForAdmin,
// this.variableIds
// )
// } else {
// variablesDataMap = await loadVariablesDataSite(
// this.variableIds,
// this.dataApiUrl
// )
// }
// this.createPerformanceMeasurement("downloadVariablesData", startMark)

// this._receiveOwidDataAndApplySelection(
// variablesDataMap,
// inputTableTransformer
// )
// } catch (err) {
// // eslint-disable-next-line no-console
// console.log(`Error fetching '${err}'`)
// console.error(err)
// Bugsnag?.notify(`Error fetching variables: ${err}`, (event) => {
// event.addMetadata("context", {
// variableIds: this.variableIds,
// })
// })
// }
// }
141 changes: 4 additions & 137 deletions packages/@ourworldindata/grapher/src/core/Grapher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,55 +240,6 @@ declare global {
}
}

async function loadVariablesDataAdmin(
variableFetchBaseUrl: string | undefined,
variableIds: number[]
): Promise<MultipleOwidVariableDataDimensionsMap> {
const dataFetchPath = (variableId: number): string =>
variableFetchBaseUrl
? `${variableFetchBaseUrl}/v1/variableById/data/${variableId}`
: `/api/data/variables/data/${variableId}.json`
const metadataFetchPath = (variableId: number): string =>
variableFetchBaseUrl
? `${variableFetchBaseUrl}/v1/variableById/metadata/${variableId}`
: `/api/data/variables/metadata/${variableId}.json`

const loadVariableDataPromises = variableIds.map(async (variableId) => {
const dataPromise = window.admin.getJSON(
dataFetchPath(variableId)
) as Promise<OwidVariableMixedData>
const metadataPromise = window.admin.getJSON(
metadataFetchPath(variableId)
) as Promise<OwidVariableWithSourceAndDimension>
const [data, metadata] = await Promise.all([
dataPromise,
metadataPromise,
])
return { data, metadata: { ...metadata, id: variableId } }
})
const variablesData: OwidVariableDataMetadataDimensions[] =
await Promise.all(loadVariableDataPromises)
const variablesDataMap = new Map(
variablesData.map((data) => [data.metadata.id, data])
)
return variablesDataMap
}

async function loadVariablesDataSite(
variableIds: number[],
dataApiUrl: string
): Promise<MultipleOwidVariableDataDimensionsMap> {
const loadVariableDataPromises = variableIds.map((variableId) =>
loadVariableDataAndMetadata(variableId, dataApiUrl)
)
const variablesData: OwidVariableDataMetadataDimensions[] =
await Promise.all(loadVariableDataPromises)
const variablesDataMap = new Map(
variablesData.map((data) => [data.metadata.id, data])
)
return variablesDataMap
}

const DEFAULT_MS_PER_TICK = 100

// Exactly the same as GrapherInterface, but contains options that developers want but authors won't be touching.
Expand Down Expand Up @@ -560,8 +511,6 @@ export class Grapher
this.updateFromObject(props)
}

if (!props.table) this.downloadData()

this.populateFromQueryParams(
legacyToCurrentGrapherQueryParams(props.queryStr ?? "")
)
Expand Down Expand Up @@ -607,13 +556,6 @@ export class Grapher
return obj
}

@action.bound downloadData(): void {
if (this.manuallyProvideData) {
} else if (this.owidDataset) {
this._receiveOwidDataAndApplySelection(this.owidDataset)
} else void this.downloadLegacyDataFromOwidVariableIds()
}

@action.bound updateFromObject(obj?: GrapherProgrammaticInterface): void {
if (!obj) return

Expand Down Expand Up @@ -1088,63 +1030,9 @@ export class Grapher
// In old browsers, the above may throw an error - just ignore it
}
}

@action.bound
async downloadLegacyDataFromOwidVariableIds(
inputTableTransformer?: ChartTableTransformer
): Promise<void> {
if (this.variableIds.length === 0)
// No data to download
return

try {
let variablesDataMap: MultipleOwidVariableDataDimensionsMap

const startMark = performance.now()
if (this.useAdminAPI) {
// TODO grapher model: switch this to downloading multiple data and metadata files
variablesDataMap = await loadVariablesDataAdmin(
this.dataApiUrlForAdmin,
this.variableIds
)
} else {
variablesDataMap = await loadVariablesDataSite(
this.variableIds,
this.dataApiUrl
)
}
this.createPerformanceMeasurement(
"downloadVariablesData",
startMark
)

this._receiveOwidDataAndApplySelection(
variablesDataMap,
inputTableTransformer
)
} catch (err) {
// eslint-disable-next-line no-console
console.log(`Error fetching '${err}'`)
console.error(err)
Bugsnag?.notify(`Error fetching variables: ${err}`, (event) => {
event.addMetadata("context", {
variableIds: this.variableIds,
})
})
}
}

@action.bound receiveOwidData(
json: MultipleOwidVariableDataDimensionsMap
): void {
// TODO grapher model: switch this to downloading multiple data and metadata files
this._receiveOwidDataAndApplySelection(json)
}

@action.bound private _setInputTable(
json: MultipleOwidVariableDataDimensionsMap,
legacyConfig: Partial<LegacyGrapherInterface>,
inputTableTransformer?: ChartTableTransformer
legacyConfig: Partial<LegacyGrapherInterface>
): void {
// TODO grapher model: switch this to downloading multiple data and metadata files

Expand All @@ -1167,9 +1055,7 @@ export class Grapher
startMark
)

if (inputTableTransformer)
this.inputTable = inputTableTransformer(tableWithColors)
else this.inputTable = tableWithColors
this.inputTable = tableWithColors

// We need to reset the dimensions because some of them may have changed slugs in the legacy
// transformation (can happen when columns use targetTime)
Expand All @@ -1184,30 +1070,17 @@ export class Grapher
} else this.applyOriginalSelectionAsAuthored()
}

@action rebuildInputOwidTable(
inputTableTransformer?: ChartTableTransformer
): void {
@action rebuildInputOwidTable(): void {
// TODO grapher model: switch this to downloading multiple data and metadata files
if (!this.legacyVariableDataJson) return
this._setInputTable(
this.legacyVariableDataJson,
this.legacyConfigAsAuthored,
inputTableTransformer
this.legacyConfigAsAuthored
)
}

@observable
private legacyVariableDataJson?: MultipleOwidVariableDataDimensionsMap

@action.bound private _receiveOwidDataAndApplySelection(
json: MultipleOwidVariableDataDimensionsMap,
inputTableTransformer?: ChartTableTransformer
): void {
this.legacyVariableDataJson = json

this.rebuildInputOwidTable(inputTableTransformer)
}

@action.bound appendNewEntitySelectionOptions(): void {
const { selection } = this
const currentEntities = selection.availableEntityNameSet
Expand Down Expand Up @@ -1431,12 +1304,6 @@ export class Grapher
// todo: can we remove this?
// I believe these states can only occur during editing.
@action.bound private ensureValidConfigWhenEditing(): void {
this.disposers.push(
reaction(
() => this.variableIds,
() => this.downloadLegacyDataFromOwidVariableIds()
)
)
const disposers = [
autorun(() => {
if (!this.availableTabs.includes(this.activeTab))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ export const legacyToOwidTableAndDimensions = (
const valueColumnColor = dimension.display?.color
// Ensure the column slug is unique by copying it from the dimensions
// (there can be two columns of the same variable with different targetTimes)
valueColumnDef.slug = dimension.slug
if (dimension.slug) valueColumnDef.slug = dimension.slug
else throw new Error("Dimension slug was undefined")
// Because database columns can contain mixed types, we want to avoid
// parsing for Grapher data until we fix that.
valueColumnDef.skipParsing = true
Expand Down

0 comments on commit c3986a5

Please sign in to comment.