From 47f72ea6d219e85c708e8ede70cd23e19111501e Mon Sep 17 00:00:00 2001 From: Daniel Bachler Date: Wed, 6 Mar 2024 13:06:12 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20remove=20most=20typeorm=20classe?= =?UTF-8?q?s,=20start=20work=20on=20Links=20to=20turn=20them=20into=20obje?= =?UTF-8?q?cts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/model/Chart.ts | 60 +++++----- db/model/ChartRevision.ts | 46 ++++---- db/model/Dataset.ts | 46 +++----- db/model/GdocXImage.ts | 14 +-- db/model/GdocXTag.ts | 14 +-- db/model/Image.ts | 37 +----- db/model/Link.ts | 106 ++++++++---------- db/model/User.ts | 38 ------- .../types/src/gdocTypes/Gdoc.ts | 2 +- 9 files changed, 140 insertions(+), 223 deletions(-) diff --git a/db/model/Chart.ts b/db/model/Chart.ts index 6149a06dde6..20b6f9cb4a3 100644 --- a/db/model/Chart.ts +++ b/db/model/Chart.ts @@ -1,17 +1,17 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - BaseEntity, - ManyToOne, - OneToMany, - type Relation, -} from "typeorm" +// import { +// Entity, +// PrimaryGeneratedColumn, +// Column, +// BaseEntity, +// ManyToOne, +// OneToMany, +// type Relation, +// } from "typeorm" import * as lodash from "lodash" import * as db from "../db.js" import { getDataForMultipleVariables } from "./Variable.js" -import { User } from "./User.js" -import { ChartRevision } from "./ChartRevision.js" +// import { User } from "./User.js" +// import { ChartRevision } from "./ChartRevision.js" import { JsonError, KeyChartLevel, @@ -42,25 +42,25 @@ export const PUBLIC_TAG_PARENT_IDS = [ 1505, 1508, 1512, 1510, 1834, 1835, ] -@Entity("charts") -export class Chart extends BaseEntity { - @PrimaryGeneratedColumn() id!: number - @Column({ type: "json" }) config!: GrapherInterface - @Column() lastEditedAt!: Date - @Column() lastEditedByUserId!: number - @Column({ nullable: true }) publishedAt!: Date - @Column({ nullable: true }) publishedByUserId!: number - @Column() createdAt!: Date - @Column() updatedAt!: Date - @Column() isExplorable!: boolean - - @ManyToOne(() => User, (user) => user.lastEditedCharts) - lastEditedByUser!: Relation - @ManyToOne(() => User, (user) => user.publishedCharts) - publishedByUser!: Relation - @OneToMany(() => ChartRevision, (rev) => rev.chart) - logs!: Relation -} +// @Entity("charts") +// export class Chart extends BaseEntity { +// @PrimaryGeneratedColumn() id!: number +// @Column({ type: "json" }) config!: GrapherInterface +// @Column() lastEditedAt!: Date +// @Column() lastEditedByUserId!: number +// @Column({ nullable: true }) publishedAt!: Date +// @Column({ nullable: true }) publishedByUserId!: number +// @Column() createdAt!: Date +// @Column() updatedAt!: Date +// @Column() isExplorable!: boolean + +// @ManyToOne(() => User, (user) => user.lastEditedCharts) +// lastEditedByUser!: Relation +// @ManyToOne(() => User, (user) => user.publishedCharts) +// publishedByUser!: Relation +// @OneToMany(() => ChartRevision, (rev) => rev.chart) +// logs!: Relation +// } // Only considers published charts, because only in that case the mapping slug -> id is unique export async function mapSlugsToIds( knex: db.KnexReadonlyTransaction diff --git a/db/model/ChartRevision.ts b/db/model/ChartRevision.ts index 0125b14b420..4f9bd840ceb 100644 --- a/db/model/ChartRevision.ts +++ b/db/model/ChartRevision.ts @@ -1,27 +1,27 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - BaseEntity, - ManyToOne, - type Relation, -} from "typeorm" -import { Chart } from "./Chart.js" -import { User } from "./User.js" +// import { +// Entity, +// PrimaryGeneratedColumn, +// Column, +// BaseEntity, +// ManyToOne, +// type Relation, +// } from "typeorm" +// // import { Chart } from "./Chart.js" +// import { User } from "./User.js" -@Entity("chart_revisions") -export class ChartRevision extends BaseEntity { - @PrimaryGeneratedColumn() id!: number - @Column() chartId!: number - @Column({ type: "json" }) config: any - @Column() userId!: number +// @Entity("chart_revisions") +// export class ChartRevision extends BaseEntity { +// @PrimaryGeneratedColumn() id!: number +// @Column() chartId!: number +// @Column({ type: "json" }) config: any +// @Column() userId!: number - @Column() createdAt!: Date - @Column() updatedAt!: Date +// @Column() createdAt!: Date +// @Column() updatedAt!: Date - @ManyToOne(() => User, (user) => user.editedCharts) - user!: Relation +// @ManyToOne(() => User, (user) => user.editedCharts) +// user!: Relation - @ManyToOne(() => Chart, (chart) => chart.logs) - chart!: Relation -} +// @ManyToOne(() => Chart, (chart) => chart.logs) +// chart!: Relation +// } diff --git a/db/model/Dataset.ts b/db/model/Dataset.ts index 68110afcab6..d47bd47c55d 100644 --- a/db/model/Dataset.ts +++ b/db/model/Dataset.ts @@ -1,15 +1,5 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - BaseEntity, - ManyToOne, - Unique, - type Relation, -} from "typeorm" import { Writable } from "stream" -import { User } from "./User.js" import { getSourcesForDataset, sourceToDatapackage } from "./Source.js" import * as db from "../db.js" @@ -23,25 +13,25 @@ import { DbRawVariable, } from "@ourworldindata/types" -@Entity("datasets") -@Unique(["name", "namespace"]) -export class Dataset extends BaseEntity { - @PrimaryGeneratedColumn() id!: number - @Column() name!: string - @Column({ default: "owid" }) namespace!: string - @Column({ default: "" }) description!: string - @Column() createdAt!: Date - @Column() updatedAt!: Date - @Column() metadataEditedAt!: Date - @Column() metadataEditedByUserId!: number - @Column() dataEditedAt!: Date - @Column() dataEditedByUserId!: number - @Column({ default: false }) isPrivate!: boolean - @Column({ default: false }) nonRedistributable!: boolean +// @Entity("datasets") +// @Unique(["name", "namespace"]) +// export class Dataset extends BaseEntity { +// @PrimaryGeneratedColumn() id!: number +// @Column() name!: string +// @Column({ default: "owid" }) namespace!: string +// @Column({ default: "" }) description!: string +// @Column() createdAt!: Date +// @Column() updatedAt!: Date +// @Column() metadataEditedAt!: Date +// @Column() metadataEditedByUserId!: number +// @Column() dataEditedAt!: Date +// @Column() dataEditedByUserId!: number +// @Column({ default: false }) isPrivate!: boolean +// @Column({ default: false }) nonRedistributable!: boolean - @ManyToOne(() => User, (user) => user.createdDatasets) - createdByUser!: Relation -} +// @ManyToOne(() => User, (user) => user.createdDatasets) +// createdByUser!: Relation +// } export async function getDatasetById( knex: db.KnexReadonlyTransaction, diff --git a/db/model/GdocXImage.ts b/db/model/GdocXImage.ts index d8cd2b961ad..8a1a28c46e4 100644 --- a/db/model/GdocXImage.ts +++ b/db/model/GdocXImage.ts @@ -1,8 +1,8 @@ -import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm" +// import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm" -@Entity("posts_gdocs_x_images") -export class GdocXImage extends BaseEntity { - @PrimaryGeneratedColumn() id!: number - @Column() gdocId!: string - @Column() imageId!: number -} +// @Entity("posts_gdocs_x_images") +// export class GdocXImage extends BaseEntity { +// @PrimaryGeneratedColumn() id!: number +// @Column() gdocId!: string +// @Column() imageId!: number +// } diff --git a/db/model/GdocXTag.ts b/db/model/GdocXTag.ts index c9682eaeb4d..d1c09dac128 100644 --- a/db/model/GdocXTag.ts +++ b/db/model/GdocXTag.ts @@ -1,8 +1,8 @@ -import { Entity, BaseEntity, PrimaryColumn } from "typeorm" +// import { Entity, BaseEntity, PrimaryColumn } from "typeorm" -@Entity("posts_gdocs_x_tags") -export class GdocXTag extends BaseEntity { - static table = "posts_gdocs_x_tags" - @PrimaryColumn() gdocId!: string - @PrimaryColumn() tagId!: number -} +// @Entity("posts_gdocs_x_tags") +// export class GdocXTag extends BaseEntity { +// static table = "posts_gdocs_x_tags" +// @PrimaryColumn() gdocId!: string +// @PrimaryColumn() tagId!: number +// } diff --git a/db/model/Image.ts b/db/model/Image.ts index 98fa284e1f0..4566903f114 100644 --- a/db/model/Image.ts +++ b/db/model/Image.ts @@ -1,10 +1,3 @@ -import { - Entity, - Column, - BaseEntity, - PrimaryGeneratedColumn, - ValueTransformer, -} from "typeorm" import { drive_v3, google } from "googleapis" import { PutObjectCommand, @@ -133,32 +126,12 @@ const s3Client = new S3Client({ secretAccessKey: IMAGE_HOSTING_SPACE_SECRET_ACCESS_KEY, }, }) - -// https://github.com/typeorm/typeorm/issues/873#issuecomment-424643086 -// otherwise epochs are retrieved as string instead of number -export class ColumnNumericTransformer implements ValueTransformer { - to(data: number): number { - return data - } - from(data: string): number { - return parseFloat(data) - } -} - -@Entity("images") -export class Image extends BaseEntity implements ImageMetadata { - @PrimaryGeneratedColumn() id!: number - @Column() googleId!: string - @Column() filename!: string - @Column() defaultAlt!: string - @Column({ - transformer: new ColumnNumericTransformer(), - }) +export class Image implements ImageMetadata { + id!: number + googleId!: string + filename!: string + defaultAlt!: string updatedAt!: number - @Column({ - transformer: new ColumnNumericTransformer(), - nullable: true, - }) originalWidth?: number get isSvg(): boolean { diff --git a/db/model/Link.ts b/db/model/Link.ts index da5085a20d9..074d23d3a87 100644 --- a/db/model/Link.ts +++ b/db/model/Link.ts @@ -1,64 +1,56 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - BaseEntity, - ManyToOne, - type Relation, - In, -} from "typeorm" import { getLinkType, getUrlTarget } from "@ourworldindata/components" import { OwidGdocLinkJSON, Url } from "@ourworldindata/utils" import { GdocBase } from "./Gdoc/GdocBase.js" import { formatUrls } from "../../site/formatting.js" -import { OwidGdocLinkType } from "@ourworldindata/types" - -@Entity("posts_gdocs_links") -export class Link extends BaseEntity implements OwidGdocLinkJSON { - @PrimaryGeneratedColumn() id!: number - @ManyToOne(() => GdocBase, (gdoc) => gdoc.id) source!: Relation - @Column() linkType!: OwidGdocLinkType - @Column() target!: string - @Column() queryString!: string - @Column() hash!: string - @Column() componentType!: string - @Column() text!: string +import { + DbInsertPostGdocLink, + DbPlainPostGdocLink, + OwidGdocLinkType, +} from "@ourworldindata/types" +import { KnexReadonlyTransaction, knexRaw } from "../db.js" - static async getPublishedLinksTo( - ids: string[], - linkType?: Link["linkType"] - ): Promise { - return Link.find({ - where: { target: In(ids), linkType }, - relations: ["source"], - }).then((links) => links.filter((link) => link.source.published)) - } +export async function getPublishedLinksTo( + knex: KnexReadonlyTransaction, + ids: string[], + linkType?: OwidGdocLinkType +): Promise { + const rows = await knexRaw( + knex, + `-- sql + select posts_gdocs_links.* from posts_gdocs_links + join posts_gdocs on posts_gdocs_links.source = posts_gdocs.id + where target in (?) and linkType = ? + and published = true + `, + [ids, linkType] + ) + return rows +} - static createFromUrl({ - url, - source, - text = "", - componentType = "", - }: { - url: string - source: GdocBase - text?: string - componentType?: string - }): Link { - const formattedUrl = formatUrls(url) - const urlObject = Url.fromURL(formattedUrl) - const linkType = getLinkType(formattedUrl) - const target = getUrlTarget(formattedUrl) - const queryString = urlObject.queryStr - const hash = urlObject.hash - return Link.create({ - target, - linkType, - queryString, - hash, - source, - text, - componentType, - }) - } +export function createFromUrl({ + url, + source, + text = "", + componentType = "", +}: { + url: string + source: GdocBase + text?: string + componentType?: string +}): DbInsertPostGdocLink { + const formattedUrl = formatUrls(url) + const urlObject = Url.fromURL(formattedUrl) + const linkType = getLinkType(formattedUrl) + const target = getUrlTarget(formattedUrl) + const queryString = urlObject.queryStr + const hash = urlObject.hash + return { + target, + linkType, + queryString, + hash, + text, + componentType, + sourceId: source.id, + } satisfies DbInsertPostGdocLink } diff --git a/db/model/User.ts b/db/model/User.ts index 8901c31d2f0..68deeede570 100644 --- a/db/model/User.ts +++ b/db/model/User.ts @@ -1,14 +1,3 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - BaseEntity, - OneToMany, - type Relation, -} from "typeorm" -import { Chart } from "./Chart.js" -import { Dataset } from "./Dataset.js" -import { ChartRevision } from "./ChartRevision.js" import { BCryptHasher } from "../hashers.js" import { DbPlainUser, @@ -16,33 +5,6 @@ import { UsersTableName, } from "@ourworldindata/types" import { KnexReadWriteTransaction, KnexReadonlyTransaction } from "../db.js" - -@Entity("users") -export class User extends BaseEntity { - @PrimaryGeneratedColumn() id!: number - @Column({ unique: true }) email!: string - @Column({ length: 128 }) password!: string - @Column({ default: "" }) fullName!: string - @Column({ default: true }) isActive!: boolean - @Column({ default: false }) isSuperuser!: boolean - @Column() createdAt!: Date - @Column() updatedAt!: Date - @Column() lastLogin!: Date - @Column() lastSeen!: Date - - @OneToMany(() => Chart, (chart) => chart.lastEditedByUser) - lastEditedCharts!: Relation - - @OneToMany(() => Chart, (chart) => chart.publishedByUser) - publishedCharts!: Relation - - @OneToMany(() => ChartRevision, (rev) => rev.user) - editedCharts!: Relation - - @OneToMany(() => Dataset, (dataset) => dataset.createdByUser) - createdDatasets!: Relation -} - export async function setPassword( knex: KnexReadWriteTransaction, id: number, diff --git a/packages/@ourworldindata/types/src/gdocTypes/Gdoc.ts b/packages/@ourworldindata/types/src/gdocTypes/Gdoc.ts index 445b32e3511..8749ed7c298 100644 --- a/packages/@ourworldindata/types/src/gdocTypes/Gdoc.ts +++ b/packages/@ourworldindata/types/src/gdocTypes/Gdoc.ts @@ -184,7 +184,7 @@ export enum OwidGdocLinkType { } export interface OwidGdocLinkJSON { - source: Record + // source: Record linkType: OwidGdocLinkType target: string componentType: string