From a58712015d488a3b5787efa535f853327553b8ba Mon Sep 17 00:00:00 2001 From: Sophia Mersmann Date: Tue, 10 Dec 2024 18:10:26 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20migrate=20slope=20chart=20config?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...207-RemoveColorDimensionFromSlopeCharts.ts | 32 + .../1733850122191-MigrateSlopeCharts.ts | 600 ++++++++++++++++++ .../utils/src/grapherConfigUtils.ts | 32 +- packages/@ourworldindata/utils/src/index.ts | 1 + 4 files changed, 655 insertions(+), 10 deletions(-) create mode 100644 db/migration/1733850063207-RemoveColorDimensionFromSlopeCharts.ts create mode 100644 db/migration/1733850122191-MigrateSlopeCharts.ts diff --git a/db/migration/1733850063207-RemoveColorDimensionFromSlopeCharts.ts b/db/migration/1733850063207-RemoveColorDimensionFromSlopeCharts.ts new file mode 100644 index 00000000000..e5fae9b5cb1 --- /dev/null +++ b/db/migration/1733850063207-RemoveColorDimensionFromSlopeCharts.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class RemoveColorDimensionFromSlopeCharts1733850063207 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + // remove color dimension for all slope charts + // the y-dimension always comes first and the color dimension second, + // so it's safe to keep the first dimension only + await queryRunner.query(` + -- sql + UPDATE chart_configs + SET + patch = JSON_REPLACE(patch, '$.dimensions', JSON_ARRAY(patch -> '$.dimensions[0]')), + full = JSON_REPLACE(full, '$.dimensions', JSON_ARRAY(full -> '$.dimensions[0]')) + WHERE + chartType = 'SlopeChart' + `) + + // remove the color dimension for slope charts from the chart_dimensions table + await queryRunner.query(` + -- sql + DELETE cd FROM chart_dimensions cd + JOIN charts c ON c.id = cd.chartId + JOIN chart_configs cc ON c.configId = cc.id + WHERE cc.chartType = 'SlopeChart' AND cd.property = 'color' + `) + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public async down(): Promise {} +} diff --git a/db/migration/1733850122191-MigrateSlopeCharts.ts b/db/migration/1733850122191-MigrateSlopeCharts.ts new file mode 100644 index 00000000000..d035ab9543f --- /dev/null +++ b/db/migration/1733850122191-MigrateSlopeCharts.ts @@ -0,0 +1,600 @@ +import { + EntitySelectionMode, + GrapherInterface, + ScaleType, + simpleMerge, +} from "@ourworldindata/utils" +import { MigrationInterface, QueryRunner } from "typeorm" + +export class MigrateSlopeCharts1733850122191 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const slopeCharts = await queryRunner.query(` + -- sql + SELECT c.id, cc.id AS configId, cc.patch, cc.full + FROM charts c + JOIN chart_configs cc ON cc.id = c.configId + WHERE + cc.chartType = 'SlopeChart' + AND cc.full ->> '$.isPublished' = 'true' + `) + + const configUpdatesById = new Map( + configUpdates.map(({ id, config }) => [id, config]) + ) + + for (const chart of slopeCharts) { + const migrationConfig = configUpdatesById.get(chart.id) + if (!migrationConfig) continue + + const patchConfig = JSON.parse(chart.patch) + const fullConfig = JSON.parse(chart.full) + + const newPatchConfig = simpleMerge(patchConfig, migrationConfig) + const newFullConfig = simpleMerge(fullConfig, migrationConfig) + + await queryRunner.query( + ` + -- sql + UPDATE chart_configs + SET + patch = ?, + full = ? + WHERE id = ? + `, + [ + JSON.stringify(newPatchConfig), + JSON.stringify(newFullConfig), + chart.configId, + ] + ) + } + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public async down(): Promise {} +} + +const configUpdates: { id: number; config: GrapherInterface }[] = [ + { + id: 414, + config: { + selectedEntityNames: [ + "Colombia", + "Guatemala", + "Indonesia", + "Iran", + "Jamaica", + "Pakistan", + "Trinidad and Tobago", + "Botswana", + "Bolivia", + "Japan", + "United States", + "Sweden", + "Germany", + "Netherlands", + "Belgium", + "France", + "Ireland", + "United Kingdom", + ], + hideRelativeToggle: true, + }, + }, + { + id: 415, + config: { + selectedEntityNames: [ + "Congenital heart anomalies", + "Neonatal preterm birth", + "Neonatal encephalopathy due to birth asphyxia and trauma", + "Congenital birth defects", + "Diarrheal diseases", + "Malaria", + ], + entityType: "cause", + entityTypePlural: "causes", + hideRelativeToggle: true, + hideLegend: false, + }, + }, + { + id: 679, + config: { + selectedEntityNames: [ + "Low-income countries", + "High-income countries", + "Lower-middle-income countries", + "Upper-middle-income countries", + ], + hideRelativeToggle: true, + yAxis: { + scaleType: ScaleType.linear, + }, + }, + }, + { + id: 874, + config: { + selectedEntityNames: [ + "North America (WB)", + "South Asia (WB)", + "Europe and Central Asia (WB)", + "Latin America and Caribbean (WB)", + ], + hideRelativeToggle: true, + }, + }, + { + id: 875, + config: { + selectedEntityNames: [ + "India", + "United States", + "Indonesia", + "Pakistan", + "Nigeria", + ], + hideRelativeToggle: true, + }, + }, + { + id: 1004, + config: { + selectedEntityNames: [ + "Europe (UN)", + "Asia (UN)", + "Africa (UN)", + "Oceania (UN)", + "Northern America (UN)", + "Latin America and the Caribbean (UN)", + ], + }, + }, + { id: 1459, config: {} }, + { + id: 1975, + config: { + selectedEntityNames: [ + "North America", + "South America", + "Europe", + "Asia", + "Oceania", + "Africa", + ], + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2832, + config: { + selectedEntityNames: [ + "Italy", + "France", + "Finland", + "Norway", + "Estonia", + "United Kingdom", + "Spain", + "Germany", + "Belgium", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2833, + config: { + selectedEntityNames: [ + "Belgium", + "Poland", + "Italy", + "Germany", + "Norway", + "Spain", + "France", + "Finland", + "United Kingdom", + "Estonia", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2834, + config: { + selectedEntityNames: [ + "Belgium", + "Italy", + "Spain", + "Norway", + "France", + "Poland", + "Estonia", + "United Kingdom", + "Finland", + "Germany", + ], + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2835, + config: { + selectedEntityNames: [ + "Estonia", + "Norway", + "Poland", + "United Kingdom", + "France", + "Finland", + "Germany", + "Belgium", + "Italy", + "Spain", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2975, + config: { + selectedEntityNames: [ + "Germany", + "Poland", + "United Kingdom", + "Finland", + "Estonia", + "Spain", + "Italy", + "Norway", + "France", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2976, + config: { + selectedEntityNames: [ + "Poland", + "Italy", + "Spain", + "Estonia", + "France", + "Germany", + "Belgium", + "United Kingdom", + "Norway", + "Finland", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2977, + config: { + selectedEntityNames: [ + "Poland", + "Norway", + "Estonia", + "Finland", + "Germany", + "Belgium", + "United Kingdom", + "Spain", + "Italy", + "France", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2978, + config: { + selectedEntityNames: [ + "Poland", + "Norway", + "Belgium", + "Estonia", + "Italy", + "Finland", + "Germany", + "United Kingdom", + "Spain", + "France", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 2979, + config: { + selectedEntityNames: [ + "United Kingdom", + "Estonia", + "Belgium", + "Italy", + "France", + "Spain", + "Germany", + "Poland", + "Finland", + "Norway", + ], + hideTimeline: true, + addCountryMode: EntitySelectionMode.Disabled, + }, + }, + { + id: 3249, + config: { + selectedEntityNames: [ + "France", + "Italy", + "Japan", + "Portugal", + "Germany", + "Mexico", + "Norway", + "Sweden", + "Taiwan", + "Sri Lanka", + "United Kingdom", + "United States", + ], + }, + }, + { + id: 3359, + config: { + selectedEntityNames: [ + "Mali", + "South Africa", + "Nigeria", + "Niger", + "Chad", + "Ethiopia", + "Kenya", + "Uganda", + "Rwanda", + "Burundi", + "Tanzania", + "Mozambique", + "Madagascar", + "Zambia", + "Congo", + "Democratic Republic of Congo", + "Central African Republic", + "Cameroon", + "Togo", + "Benin", + "Sierra Leone", + "Cote d'Ivoire", + "Burkina Faso", + "Guinea-Bissau", + "Papua New Guinea", + "Senegal", + "Angola", + ], + }, + }, + { + id: 3364, + config: { + selectedEntityNames: [ + "India", + "Indonesia", + "United States", + "Pakistan", + ], + }, + }, + { + id: 3433, + config: {}, + }, + { + id: 3434, + config: {}, + }, + { + id: 3580, + config: { + entityTypePlural: "species", + }, + }, + { + id: 3620, + config: { + selectedEntityNames: [ + "Low income", + "High income", + "Middle income", + "Low & middle income", + "Lower middle income", + "Upper middle income", + ], + }, + }, + { + id: 3627, + config: { + selectedEntityNames: [ + "Low income", + "High income", + "Middle income", + "Low & middle income", + "Lower middle income", + "Upper middle income", + ], + hideTimeline: true, + }, + }, + { + id: 4408, + config: { + selectedEntityNames: [ + "East Asia (MPD)", + "Latin America (MPD)", + "Eastern Europe (MPD)", + "Western Europe (MPD)", + "Western offshoots (MPD)", + "Sub Saharan Africa (MPD)", + "South and South East Asia (MPD)", + "Middle East and North Africa (MPD)", + "World", + ], + }, + }, + { + id: 4764, + config: { + entityTypePlural: "species", + }, + }, + { + id: 6219, + config: { + hideRelativeToggle: true, + }, + }, + { + id: 6529, + config: { + selectedEntityNames: [ + "North America", + "Europe", + "Asia", + "South America", + "Oceania", + "Africa", + ], + }, + }, + { + id: 7150, + config: { + selectedEntityNames: [ + "Ethiopia", + "Myanmar", + "Niger", + "Chad", + "Colombia", + "Indonesia", + "Nigeria", + ], + }, + }, + { + id: 7206, + config: { + selectedEntityNames: [ + "Americas (excl. USA)", + "Asia (excl. China and India)", + "China", + "Europe", + "India", + "Middle East & North Africa", + "Oceania", + "Sub-Saharan Africa", + "United States", + "World", + ], + }, + }, + { + id: 7220, + config: { + selectedEntityNames: [ + "Americas (excl. USA)", + "Asia (excl. China and India)", + "China", + "Europe", + "India", + "Middle East & North Africa", + "Oceania", + "Sub-Saharan Africa", + "United States", + "World", + ], + }, + }, + { + id: 7221, + config: { + selectedEntityNames: [ + "Americas (excl. USA)", + "Asia (excl. China and India)", + "China", + "Europe", + "India", + "Middle East & North Africa", + "Oceania", + "Sub-Saharan Africa", + "United States", + "World", + ], + }, + }, + { + id: 7226, + config: { + selectedEntityNames: [ + "Americas (excl. USA)", + "Asia (excl. China and India)", + "China", + "Europe", + "India", + "Middle East & North Africa", + "Oceania", + "Sub-Saharan Africa", + "United States", + "World", + ], + }, + }, + { + id: 7344, + config: { + selectedEntityNames: [ + "United States", + "Romania", + "France", + "United Kingdom", + "Colombia", + "Mexico", + "Japan", + ], + }, + }, + { + id: 7448, + config: { + addCountryMode: EntitySelectionMode.MultipleEntities, + hideRelativeToggle: true, + }, + }, + { + id: 8157, + config: { + selectedEntityNames: [ + "South Asia (WB)", + "North America (WB)", + "Sub-Saharan Africa (WB)", + "East Asia and Pacific (WB)", + "Europe and Central Asia (WB)", + "Latin America and Caribbean (WB)", + "Middle East and North Africa (WB)", + ], + }, + }, +] diff --git a/packages/@ourworldindata/utils/src/grapherConfigUtils.ts b/packages/@ourworldindata/utils/src/grapherConfigUtils.ts index 2a8db8e0120..b885c9e4dfb 100644 --- a/packages/@ourworldindata/utils/src/grapherConfigUtils.ts +++ b/packages/@ourworldindata/utils/src/grapherConfigUtils.ts @@ -22,6 +22,27 @@ const KEYS_EXCLUDED_FROM_INHERITANCE = [ "isPublished", ] +/** + * Simple merge function that doesn't do any Grapher-specific checks. + * + * You usually want to use `mergeGrapherConfigs` instead that implements the + * inheritance model correctly. Only use this if you're sure this is what you need. + */ +export function simpleMerge( + ...grapherConfigs: GrapherInterface[] +): GrapherInterface { + return mergeWith( + {}, // mergeWith mutates the first argument + ...grapherConfigs, + (_: unknown, childValue: unknown): any => { + // don't concat arrays, just use the last one + if (Array.isArray(childValue)) { + return childValue + } + } + ) +} + export function mergeGrapherConfigs( ...grapherConfigs: GrapherInterface[] ): GrapherInterface { @@ -60,16 +81,7 @@ export function mergeGrapherConfigs( return omit(config, KEYS_EXCLUDED_FROM_INHERITANCE) }) - return mergeWith( - {}, // mergeWith mutates the first argument - ...cleanedConfigs, - (_: unknown, childValue: unknown): any => { - // don't concat arrays, just use the last one - if (Array.isArray(childValue)) { - return childValue - } - } - ) + return simpleMerge(...cleanedConfigs) } export function diffGrapherConfigs( diff --git a/packages/@ourworldindata/utils/src/index.ts b/packages/@ourworldindata/utils/src/index.ts index ce1d4e5aed3..3508d88054d 100644 --- a/packages/@ourworldindata/utils/src/index.ts +++ b/packages/@ourworldindata/utils/src/index.ts @@ -339,6 +339,7 @@ export { isAndroid, isIOS } from "./BrowserUtils.js" export { diffGrapherConfigs, mergeGrapherConfigs, + simpleMerge, } from "./grapherConfigUtils.js" export {