-
-
Notifications
You must be signed in to change notification settings - Fork 229
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🎉 (grapher) make charts inherit indicator-level settings
- Loading branch information
1 parent
4ec3a29
commit b74f932
Showing
4 changed files
with
315 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
db/migration/1721134584504-MoveIndicatorChartsToTheChartsConfigTable.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
import { defaultGrapherConfig } from "@ourworldindata/grapher" | ||
import { DimensionProperty, GrapherInterface } from "@ourworldindata/types" | ||
import { | ||
diffGrapherConfigs, | ||
mergeGrapherConfigs, | ||
omit, | ||
} from "@ourworldindata/utils" | ||
import { MigrationInterface, QueryRunner } from "typeorm" | ||
|
||
export class MoveIndicatorChartsToTheChartsConfigTable1721134584504 | ||
implements MigrationInterface | ||
{ | ||
public async up(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query(`-- sql | ||
ALTER TABLE variables | ||
ADD COLUMN grapherConfigIdAdmin binary(16) UNIQUE AFTER sort, | ||
ADD COLUMN grapherConfigIdETL binary(16) UNIQUE AFTER grapherConfigIdAdmin, | ||
ADD CONSTRAINT fk_variables_grapherConfigIdAdmin | ||
FOREIGN KEY (grapherConfigIdAdmin) | ||
REFERENCES chart_configs (id) | ||
ON DELETE RESTRICT | ||
ON UPDATE RESTRICT, | ||
ADD CONSTRAINT fk_variables_grapherConfigIdETL | ||
FOREIGN KEY (grapherConfigIdETL) | ||
REFERENCES chart_configs (id) | ||
ON DELETE RESTRICT | ||
ON UPDATE RESTRICT | ||
`) | ||
|
||
// note that we copy the ETL-authored configs to the chart_configs table, | ||
// but drop the admin-authored configs | ||
|
||
const variables = await queryRunner.query(`-- sql | ||
SELECT id, grapherConfigETL | ||
FROM variables | ||
WHERE grapherConfigETL IS NOT NULL | ||
`) | ||
|
||
for (const { id: variableId, grapherConfigETL } of variables) { | ||
let config: GrapherInterface = JSON.parse(grapherConfigETL) | ||
|
||
// if the config has no schema, assume it's the default version | ||
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 }, | ||
] | ||
} | ||
|
||
// we have v3 configs in the database (the current version is v4); | ||
// turn these into v4 configs by removing the `data` property | ||
// which was the breaking change that lead to v4 | ||
// (we don't have v2 or v1 configs in the database, so we don't need to handle those) | ||
if ( | ||
config.$schema === | ||
"https://files.ourworldindata.org/schemas/grapher-schema.003.json" | ||
) { | ||
config = omit(config, "data") | ||
config.$schema = defaultGrapherConfig.$schema | ||
} | ||
|
||
// ETL configs inherit from the default config | ||
const patchConfig = diffGrapherConfigs(config, defaultGrapherConfig) | ||
const fullConfig = mergeGrapherConfigs(defaultGrapherConfig, config) | ||
|
||
// insert config into the chart_configs table | ||
const configId = await getBinaryUUID(queryRunner) | ||
await queryRunner.query( | ||
`-- sql | ||
INSERT INTO chart_configs (id, patch, full) | ||
VALUES (?, ?, ?) | ||
`, | ||
[ | ||
configId, | ||
JSON.stringify(patchConfig), | ||
JSON.stringify(fullConfig), | ||
] | ||
) | ||
|
||
// update reference in the variables table | ||
await queryRunner.query( | ||
`-- sql | ||
UPDATE variables | ||
SET grapherConfigIdETL = ? | ||
WHERE id = ? | ||
`, | ||
[configId, variableId] | ||
) | ||
} | ||
|
||
// drop `grapherConfigAdmin` and `grapherConfigETL` columns | ||
await queryRunner.query(`-- sql | ||
ALTER TABLE variables | ||
DROP COLUMN grapherConfigAdmin, | ||
DROP COLUMN grapherConfigETL | ||
`) | ||
|
||
await queryRunner.query(`-- sql | ||
CREATE VIEW inheritance_indicators_x_charts AS ( | ||
WITH y_dimensions AS ( | ||
SELECT | ||
* | ||
FROM | ||
chart_dimensions | ||
WHERE | ||
property = 'y' | ||
), | ||
single_y_indicator_charts As ( | ||
SELECT | ||
c.id as chartId, | ||
cc.patch as patchConfig, | ||
max(yd.variableId) as variableId | ||
FROM | ||
charts c | ||
JOIN chart_configs cc ON cc.id = c.configId | ||
JOIN y_dimensions yd ON c.id = yd.chartId | ||
WHERE | ||
cc.full ->> '$.type' != 'ScatterPlot' | ||
GROUP BY | ||
c.id | ||
HAVING | ||
COUNT(distinct yd.variableId) = 1 | ||
) | ||
SELECT | ||
variableId, | ||
chartId | ||
FROM | ||
single_y_indicator_charts | ||
ORDER BY | ||
variableId | ||
) | ||
`) | ||
} | ||
|
||
public async down(queryRunner: QueryRunner): Promise<void> { | ||
// add back the `grapherConfigAdmin` and `grapherConfigETL` columns | ||
await queryRunner.query(`-- sql | ||
ALTER TABLE variables | ||
ADD COLUMN grapherConfigAdmin json AFTER sort, | ||
ADD COLUMN grapherConfigETL json AFTER grapherConfigAdmin | ||
`) | ||
|
||
// copy configs from the chart_configs table to the variables table | ||
await queryRunner.query(`-- sql | ||
UPDATE variables v | ||
JOIN chart_configs cc ON v.grapherConfigIdETL = cc.id | ||
SET v.grapherConfigETL = cc.patch | ||
`) | ||
|
||
// remove constraints on the `grapherConfigIdAdmin` and `grapherConfigIdETL` columns | ||
await queryRunner.query(`-- sql | ||
ALTER TABLE variables | ||
DROP CONSTRAINT fk_variables_grapherConfigIdAdmin, | ||
DROP CONSTRAINT fk_variables_grapherConfigIdETL | ||
`) | ||
|
||
// drop rows from the chart_configs table | ||
await queryRunner.query(`-- sql | ||
DELETE FROM chart_configs | ||
WHERE id IN ( | ||
SELECT grapherConfigIdETL FROM variables | ||
WHERE grapherConfigIdETL IS NOT NULL | ||
) | ||
`) | ||
|
||
// remove the `grapherConfigIdAdmin` and `grapherConfigIdETL` columns | ||
await queryRunner.query(`-- sql | ||
ALTER TABLE variables | ||
DROP COLUMN grapherConfigIdAdmin, | ||
DROP COLUMN grapherConfigIdETL | ||
`) | ||
} | ||
} | ||
|
||
const getBinaryUUID = async (queryRunner: QueryRunner): Promise<Buffer> => { | ||
const rows = await queryRunner.query(`SELECT UUID_TO_BIN(UUID(), 1) AS id`) | ||
return rows[0].id | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
packages/@ourworldindata/types/src/dbTypes/InheritingCharts.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export const InheritingChartsTableName = "inheriting_charts" | ||
|
||
export interface DbInsertInheritingChart { | ||
variableId: number | ||
chartId: number | ||
} | ||
|
||
export type DbPlainInheritingChart = Required<DbInsertInheritingChart> |