diff --git a/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts index 76fc2ec69ef..7d11c1b11e4 100644 --- a/adminSiteServer/apiRouter.ts +++ b/adminSiteServer/apiRouter.ts @@ -85,6 +85,7 @@ import { DbInsertUser, FlatTagGraph, DbRawChartConfig, + parseChartConfig, } from "@ourworldindata/types" import { defaultGrapherConfig, @@ -1288,6 +1289,121 @@ getRouteWithROTransaction( } ) +postRouteWithRWTransaction( + apiRouter, + "/variables/:variableId/grapherConfigETL/new", + async (req, res, trx) => { + const variableId = expectInt(req.params.variableId) + // const user = res.locals.user + const config = req.body + + // if no schema is given, assume it's the latest + if (!config.$schema) { + config.$schema = defaultGrapherConfig.$schema + } + + // check if the given dimensions are correct + if (config.dimensions && config.dimensions.length >= 1) { + // make sure there is only a single entry + config.dimensions = config.dimensions.slice(0, 1) + // make sure the variable id matches + config.dimensions[0].variableId = variableId + } + + // fill dimensions if not given to make the config plottable + if (!config.dimensions || config.dimensions.length === 0) { + config.dimensions = [{ property: DimensionProperty.y, variableId }] + } + + // ETL configs inherit from the default + const patchConfigETL = diffGrapherConfigs(config, defaultGrapherConfig) + const fullConfigETL = mergeGrapherConfigs( + defaultGrapherConfig, + patchConfigETL + ) + + // insert chart config into the database + const configId = await getBinaryUUID(trx) + await db.knexRaw( + trx, + `-- sql + INSERT INTO chart_configs (id, patch, full) + VALUES (?, ?, ?) + `, + [ + configId, + JSON.stringify(patchConfigETL), + JSON.stringify(fullConfigETL), + ] + ) + + // make a reference to the config from the variables table + await db.knexRaw( + trx, + `-- sql + UPDATE variables + SET grapherConfigIdETL = ? + WHERE id = ? + `, + [configId, variableId] + ) + + // grab the admin-authored indicator chart if there is one + let patchConfigAdmin: GrapherInterface = {} + const row = await db.knexRawFirst<{ + adminConfig: DbRawChartConfig["full"] // TODO: type + }>( + trx, + `-- sql + SELECT cc.patch as adminConfig + FROM chart_configs cc + JOIN variables v ON cc.id = v.grapherConfigIdAdmin + WHERE v.id = ? + `, + [variableId] + ) + if (row) { + patchConfigAdmin = parseChartConfig(row.adminConfig) + } + + // find all charts that inherit from the indicator + const children = await db.knexRaw<{ + chartId: number + patchConfig: string + }>( + trx, + `-- sql + SELECT c.id as chartId, cc.patch as patchConfig + FROM inheriting_charts ic + JOIN charts c ON c.id = ic.chartId + JOIN chart_configs cc ON cc.id = c.configId + WHERE ic.variableId = ? + `, + [variableId] + ) + + for (const child of children) { + const patchConfigChild = JSON.parse(child.patchConfig) + const fullConfigChild = mergeGrapherConfigs( + defaultGrapherConfig, + patchConfigETL, + patchConfigAdmin, + patchConfigChild + ) + await db.knexRaw( + trx, + `-- sql + UPDATE chart_configs cc + JOIN charts c ON c.configId = cc.id + SET cc.full = ? + WHERE c.id = ? + `, + [JSON.stringify(fullConfigChild), child.chartId] + ) + } + } +) + getRouteWithROTransaction( apiRouter, "/datasets.json", diff --git a/packages/@ourworldindata/grapher/src/schema/grapher-schema.004.yaml b/packages/@ourworldindata/grapher/src/schema/grapher-schema.004.yaml index 1d51b63eff6..cc716cc2435 100644 --- a/packages/@ourworldindata/grapher/src/schema/grapher-schema.004.yaml +++ b/packages/@ourworldindata/grapher/src/schema/grapher-schema.004.yaml @@ -185,7 +185,7 @@ $defs: description: The minimum bracket of the first bin additionalProperties: false required: - - title + - $schema - version - dimensions type: object diff --git a/packages/@ourworldindata/types/src/dbTypes/InheritingCharts.ts b/packages/@ourworldindata/types/src/dbTypes/InheritingCharts.ts new file mode 100644 index 00000000000..3a956f68cc7 --- /dev/null +++ b/packages/@ourworldindata/types/src/dbTypes/InheritingCharts.ts @@ -0,0 +1,8 @@ +export const InheritingChartsTableName = "inheriting_charts" + +export interface DbInsertInheritingChart { + variableId: number + chartId: number +} + +export type DbPlainInheritingChart = Required