Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔨 (db) add chart_configs table / TAS-563 #3767

Merged
merged 2 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 194 additions & 109 deletions adminSiteServer/apiRouter.ts

Large diffs are not rendered by default.

88 changes: 57 additions & 31 deletions adminSiteServer/testPageRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import {
import { grapherToSVG } from "../baker/GrapherImageBaker.js"
import {
ChartTypeName,
ChartsTableName,
ColorSchemeName,
DbRawChart,
DbRawChartConfig,
DbPlainChart,
EntitySelectionMode,
GrapherTabOption,
StackMode,
parseChartsRow,
parseChartConfig,
} from "@ourworldindata/types"
import { ExplorerAdminServer } from "../explorerAdminServer/ExplorerAdminServer.js"
import { GIT_CMS_DIR } from "../gitCms/GitCmsConstants.js"
Expand Down Expand Up @@ -140,27 +140,28 @@ async function propsFromQueryParams(

let query = knex
.table("charts")
.whereRaw("publishedAt IS NOT NULL")
.orderBy("id", "DESC")
.join({ cc: "chart_configs" }, "charts.configId", "cc.id")
.whereRaw("charts.publishedAt IS NOT NULL")
.orderBy("charts.id", "DESC")
console.error(query.toSQL())

let tab = params.tab

if (params.type) {
if (params.type === ChartTypeName.WorldMap) {
query = query.andWhereRaw(`config->>"$.hasMapTab" = "true"`)
query = query.andWhereRaw(`cc.full->>"$.hasMapTab" = "true"`)
tab = tab || GrapherTabOption.map
} else {
if (params.type === "LineChart") {
query = query.andWhereRaw(
`(
config->"$.type" = "LineChart"
OR config->"$.type" IS NULL
) AND COALESCE(config->>"$.hasChartTab", "true") = "true"`
cc.full->"$.type" = "LineChart"
OR cc.full->"$.type" IS NULL
) AND COALESCE(cc.full->>"$.hasChartTab", "true") = "true"`
)
} else {
query = query.andWhereRaw(
`config->"$.type" = :type AND COALESCE(config->>"$.hasChartTab", "true") = "true"`,
`cc.full->"$.type" = :type AND COALESCE(cc.full->>"$.hasChartTab", "true") = "true"`,
{ type: params.type }
)
}
Expand All @@ -170,27 +171,27 @@ async function propsFromQueryParams(

if (params.logLinear) {
query = query.andWhereRaw(
`config->>'$.yAxis.canChangeScaleType' = "true" OR config->>'$.xAxis.canChangeScaleType' = "true"`
`cc.full->>'$.yAxis.canChangeScaleType' = "true" OR cc.full->>'$.xAxis.canChangeScaleType' = "true"`
)
tab = GrapherTabOption.chart
}

if (params.comparisonLines) {
query = query.andWhereRaw(
`config->'$.comparisonLines[0].yEquals' != ''`
`cc.full->'$.comparisonLines[0].yEquals' != ''`
)
tab = GrapherTabOption.chart
}

if (params.stackMode) {
query = query.andWhereRaw(`config->'$.stackMode' = :stackMode`, {
query = query.andWhereRaw(`cc.full->'$.stackMode' = :stackMode`, {
stackMode: params.stackMode,
})
tab = GrapherTabOption.chart
}

if (params.relativeToggle) {
query = query.andWhereRaw(`config->>'$.hideRelativeToggle' = "false"`)
query = query.andWhereRaw(`cc.full->>'$.hideRelativeToggle' = "false"`)
tab = GrapherTabOption.chart
}

Expand All @@ -199,7 +200,7 @@ async function propsFromQueryParams(
// have a visible categorial legend, and can leave out some that have one.
// But in practice it seems to work reasonably well.
query = query.andWhereRaw(
`json_length(config->'$.map.colorScale.customCategoryColors') > 1`
`json_length(cc.full->'$.map.colorScale.customCategoryColors') > 1`
)
tab = GrapherTabOption.map
}
Expand All @@ -225,13 +226,13 @@ async function propsFromQueryParams(
const mode = params.addCountryMode
if (mode === EntitySelectionMode.MultipleEntities) {
query = query.andWhereRaw(
`config->'$.addCountryMode' IS NULL OR config->'$.addCountryMode' = :mode`,
`cc.full->'$.addCountryMode' IS NULL OR cc.full->'$.addCountryMode' = :mode`,
{
mode: EntitySelectionMode.MultipleEntities,
}
)
} else {
query = query.andWhereRaw(`config->'$.addCountryMode' = :mode`, {
query = query.andWhereRaw(`cc.full->'$.addCountryMode' = :mode`, {
mode,
})
}
Expand All @@ -242,10 +243,10 @@ async function propsFromQueryParams(
}

if (tab === GrapherTabOption.map) {
query = query.andWhereRaw(`config->>"$.hasMapTab" = "true"`)
query = query.andWhereRaw(`cc.full->>"$.hasMapTab" = "true"`)
} else if (tab === GrapherTabOption.chart) {
query = query.andWhereRaw(
`COALESCE(config->>"$.hasChartTab", "true") = "true"`
`COALESCE(cc.full->>"$.hasChartTab", "true") = "true"`
)
}

Expand Down Expand Up @@ -283,7 +284,7 @@ async function propsFromQueryParams(

const chartsQuery = query
.clone()
.select("id", "slug")
.select(knex.raw("charts.id, cc.slug"))
.limit(perPage)
.offset(perPage * (page - 1))

Expand Down Expand Up @@ -473,13 +474,26 @@ getPlainRouteWithROTransaction(
"/embeds/:id",
async (req, res, trx) => {
const id = req.params.id
const chartRaw: DbRawChart = await trx
.table(ChartsTableName)
.where({ id: id })
.first()
const chartEnriched = parseChartsRow(chartRaw)
const viewProps = await getViewPropsFromQueryParams(req.query)
if (chartEnriched) {
const chartRaw = await db.knexRawFirst<
Pick<DbPlainChart, "id"> & { config: DbRawChartConfig["full"] }
>(
trx,
`--sql
select ca.id, cc.full as config
from charts ca
join chart_configs cc
on ca.configId = cc.id
where ca.id = ?
`,
[id]
)

if (chartRaw) {
const chartEnriched = {
...chartRaw,
config: parseChartConfig(chartRaw.config),
}
const viewProps = await getViewPropsFromQueryParams(req.query)
const charts = [
{
id: chartEnriched.id,
Expand Down Expand Up @@ -727,9 +741,15 @@ getPlainRouteWithROTransaction(
testPageRouter,
"/previews",
async (req, res, trx) => {
const rows = await db.knexRaw(
const rows = await db.knexRaw<{ config: DbRawChartConfig["full"] }>(
trx,
`SELECT config FROM charts LIMIT 200`
`--sql
SELECT cc.full as config
FROM charts ca
JOIN chart_configs cc
ON ca.configId = cc.id
LIMIT 200
`
)
const charts = rows.map((row: any) => JSON.parse(row.config))

Expand All @@ -741,9 +761,15 @@ getPlainRouteWithROTransaction(
testPageRouter,
"/embedVariants",
async (req, res, trx) => {
const rows = await db.knexRaw(
const rows = await db.knexRaw<{ config: DbRawChartConfig["full"] }>(
trx,
`SELECT config FROM charts WHERE id=64`
`--sql
SELECT cc.full as config
FROM charts ca
JOIN chart_configs cc
ON ca.configId = cc.id
WHERE ca.id=64
`
)
const charts = rows.map((row: any) => JSON.parse(row.config))
const viewProps = getViewPropsFromQueryParams(req.query)
Expand Down
28 changes: 19 additions & 9 deletions baker/GrapherBaker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {
OwidChartDimensionInterface,
FaqEntryData,
ImageMetadata,
DbPlainChart,
DbRawChartConfig,
} from "@ourworldindata/types"
import ProgressBar from "progress"
import {
Expand Down Expand Up @@ -399,16 +401,24 @@ export const bakeSingleGrapherChart = async (
export const bakeAllChangedGrapherPagesVariablesPngSvgAndDeleteRemovedGraphers =
// TODO: this transaction is only RW because somewhere inside it we fetch images
async (bakedSiteDir: string, knex: db.KnexReadWriteTransaction) => {
const chartsToBake: { id: number; config: string; slug: string }[] =
await knexRaw(
knex,
`-- sql
SELECT
id, config, config->>'$.slug' as slug
FROM charts WHERE JSON_EXTRACT(config, "$.isPublished")=true
ORDER BY JSON_EXTRACT(config, "$.slug") ASC
const chartsToBake = await knexRaw<
Pick<DbPlainChart, "id"> & {
config: DbRawChartConfig["full"]
slug: string
}
>(
knex,
`-- sql
SELECT
c.id,
cc.full as config,
cc.slug
FROM charts c
JOIN chart_configs cc ON c.configId = cc.id
WHERE JSON_EXTRACT(cc.full, "$.isPublished")=true
ORDER BY cc.slug ASC
`
)
)

const newSlugs = chartsToBake.map((row) => row.slug)
await fs.mkdirp(bakedSiteDir + "/grapher")
Expand Down
7 changes: 6 additions & 1 deletion baker/GrapherBakingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ export const bakeGrapherUrls = async (

const rows = await db.knexRaw<{ version: number }>(
knex,
`SELECT charts.config->>"$.version" AS version FROM charts WHERE charts.id=?`,
`-- sql
SELECT cc.full->>"$.version" AS version
FROM charts c
JOIN chart_configs cc ON c.configId = cc.id
WHERE c.id=?
`,
[chartId]
)
if (!rows.length) {
Expand Down
16 changes: 12 additions & 4 deletions baker/GrapherImageBaker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
DbPlainChartSlugRedirect,
DbRawChart,
DbPlainChart,
GrapherInterface,
DbRawChartConfig,
} from "@ourworldindata/types"
import { Grapher, GrapherProgrammaticInterface } from "@ourworldindata/grapher"
import { MultipleOwidVariableDataDimensionsMap } from "@ourworldindata/utils"
Expand Down Expand Up @@ -78,9 +79,16 @@ export async function getPublishedGraphersBySlug(
const graphersById: Map<number, GrapherInterface> = new Map()

// Select all graphers that are published
const sql = `SELECT id, config FROM charts WHERE config->>"$.isPublished" = "true"`

const query = db.knexRaw<Pick<DbRawChart, "id" | "config">>(knex, sql)
const sql = `-- sql
SELECT c.id, cc.full as config
FROM charts c
JOIN chart_configs cc ON c.configId = cc.id
WHERE cc.full ->> "$.isPublished" = 'true'
`

const query = db.knexRaw<
Pick<DbPlainChart, "id"> & { config: DbRawChartConfig["full"] }
>(knex, sql)
for (const row of await query) {
const grapher = JSON.parse(row.config)

Expand Down
18 changes: 10 additions & 8 deletions baker/SiteBaker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -724,19 +724,21 @@ export class SiteBaker {
knex,
`-- sql
SELECT
config ->> '$.slug' as slug,
config ->> '$.subtitle' as subtitle,
config ->> '$.note' as note
cc.slug,
cc.full ->> '$.subtitle' as subtitle,
cc.full ->> '$.note' as note
FROM
charts
charts c
JOIN
chart_configs cc ON c.configId = cc.id
WHERE
JSON_EXTRACT(config, "$.isPublished") = true
JSON_EXTRACT(cc.full, "$.isPublished") = true
AND (
JSON_EXTRACT(config, "$.subtitle") LIKE "%#dod:%"
OR JSON_EXTRACT(config, "$.note") LIKE "%#dod:%"
JSON_EXTRACT(cc.full, "$.subtitle") LIKE "%#dod:%"
OR JSON_EXTRACT(cc.full, "$.note") LIKE "%#dod:%"
)
ORDER BY
JSON_EXTRACT(config, "$.slug") ASC
cc.slug ASC
`
)

Expand Down
15 changes: 8 additions & 7 deletions baker/algolia/indexChartsToAlgolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,20 @@ const getChartsRecords = async (
`-- sql
WITH indexable_charts_with_entity_names AS (
SELECT c.id,
config ->> "$.slug" AS slug,
config ->> "$.title" AS title,
config ->> "$.variantName" AS variantName,
config ->> "$.subtitle" AS subtitle,
JSON_LENGTH(config ->> "$.dimensions") AS numDimensions,
cc.slug,
cc.full ->> "$.title" AS title,
cc.full ->> "$.variantName" AS variantName,
cc.full ->> "$.subtitle" AS subtitle,
JSON_LENGTH(cc.full ->> "$.dimensions") AS numDimensions,
c.publishedAt,
c.updatedAt,
JSON_ARRAYAGG(e.name) AS entityNames
FROM charts c
LEFT JOIN chart_configs cc ON c.configId = cc.id
LEFT JOIN charts_x_entities ce ON c.id = ce.chartId
LEFT JOIN entities e ON ce.entityId = e.id
WHERE config ->> "$.isPublished" = 'true'
AND isIndexable IS TRUE
WHERE cc.full ->> "$.isPublished" = 'true'
AND c.isIndexable IS TRUE
GROUP BY c.id
)
SELECT c.id,
Expand Down
23 changes: 16 additions & 7 deletions baker/countryProfiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
DbEnrichedVariable,
VariablesTableName,
parseVariablesRow,
DbRawChartConfig,
parseChartConfig,
} from "@ourworldindata/types"
import * as lodash from "lodash"
import {
Expand Down Expand Up @@ -45,13 +47,20 @@ const countryIndicatorGraphers = async (
trx: db.KnexReadonlyTransaction
): Promise<GrapherInterface[]> =>
bakeCache(countryIndicatorGraphers, async () => {
const graphers = (
await trx
.table("charts")
.whereRaw(
"publishedAt is not null and config->>'$.isPublished' = 'true' and isIndexable is true"
)
).map((c: any) => JSON.parse(c.config)) as GrapherInterface[]
const configs = await db.knexRaw<{ config: DbRawChartConfig["full"] }>(
trx,
`-- sql
SELECT cc.full as config
FROM charts c
JOIN chart_configs cc ON cc.id = c.configId
WHERE
c.publishedAt is not null
AND cc.full->>'$.isPublished' = 'true'
AND c.isIndexable is true
`
)

const graphers = configs.map((c: any) => parseChartConfig(c.config))

return graphers.filter(checkShouldShowIndicator)
})
Expand Down
8 changes: 5 additions & 3 deletions baker/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@ export const getGrapherRedirectsMap = async (
}>(
knex,
`-- sql
SELECT chart_slug_redirects.slug as oldSlug, charts.config ->> "$.slug" as newSlug
FROM chart_slug_redirects INNER JOIN charts ON charts.id=chart_id
`
SELECT chart_slug_redirects.slug as oldSlug, chart_configs.slug as newSlug
FROM chart_slug_redirects
INNER JOIN charts ON charts.id=chart_id
INNER JOIN chart_configs ON chart_configs.id=charts.configId
`
)) as Array<{ oldSlug: string; newSlug: string }>

return new Map(
Expand Down
Loading