From a21e1d9feab996dd1402be856b562e9453473b2e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 25 Nov 2023 13:18:51 -0500 Subject: [PATCH] chore: Expose createDatabaseInstance, createMigrationRunner methods --- .../DocumentPublishedOrUpdatedEmail.tsx | 2 +- server/index.ts | 2 +- server/models/Revision.ts | 7 +- .../tasks/RevisionCreatedNotificationsTask.ts | 2 +- server/routes/api/revisions/revisions.ts | 4 +- server/storage/database.ts | 148 ++++++++++-------- 6 files changed, 96 insertions(+), 69 deletions(-) diff --git a/server/emails/templates/DocumentPublishedOrUpdatedEmail.tsx b/server/emails/templates/DocumentPublishedOrUpdatedEmail.tsx index 9d967c7ab..452a73d9c 100644 --- a/server/emails/templates/DocumentPublishedOrUpdatedEmail.tsx +++ b/server/emails/templates/DocumentPublishedOrUpdatedEmail.tsx @@ -65,7 +65,7 @@ export default class DocumentPublishedOrUpdatedEmail extends BaseEmail< const revision = await Revision.findByPk(revisionId); if (revision) { - const before = await revision.previous(); + const before = await revision.before(); const content = await DocumentHelper.toEmailDiff(before, revision, { includeTitle: false, centered: false, diff --git a/server/index.ts b/server/index.ts index 863ca4224..542fc547a 100644 --- a/server/index.ts +++ b/server/index.ts @@ -50,7 +50,7 @@ if (serviceNames.includes("collaboration")) { // This function will only be called once in the original process async function master() { - await checkConnection(); + await checkConnection(sequelize); await checkEnv(); await checkPendingMigrations(); diff --git a/server/models/Revision.ts b/server/models/Revision.ts index ef5210d8f..4336a02e3 100644 --- a/server/models/Revision.ts +++ b/server/models/Revision.ts @@ -127,7 +127,12 @@ class Revision extends IdModel { // instance methods - previous(): Promise { + /** + * Find the revision for the document before this one. + * + * @returns A Promise that resolves to a Revision, or null if this is the first revision. + */ + before(): Promise { return (this.constructor as typeof Revision).findOne({ where: { documentId: this.documentId, diff --git a/server/queues/tasks/RevisionCreatedNotificationsTask.ts b/server/queues/tasks/RevisionCreatedNotificationsTask.ts index fa1adeaa6..95c28e4ac 100644 --- a/server/queues/tasks/RevisionCreatedNotificationsTask.ts +++ b/server/queues/tasks/RevisionCreatedNotificationsTask.ts @@ -25,7 +25,7 @@ export default class RevisionCreatedNotificationsTask extends BaseTask - process.env.DEBUG?.includes("database") && Logger.debug("database", msg), - typeValidation: true, - logQueryParameters: env.isDevelopment, - dialectOptions: { - ssl: - env.isProduction && !isSSLDisabled - ? { - // Ref.: https://github.com/brianc/node-postgres/issues/2009 - rejectUnauthorized: false, - } - : false, - }, - models: Object.values(models), - pool: { - max: poolMax, - min: poolMin, - acquire: 30000, - idle: 10000, - }, -}); +export function createDatabaseInstance( + url: string, + models: { [key: string]: typeof Model } +) { + return new Sequelize(url, { + logging: (msg) => + process.env.DEBUG?.includes("database") && Logger.debug("database", msg), + typeValidation: true, + logQueryParameters: env.isDevelopment, + dialectOptions: { + ssl: + env.isProduction && !isSSLDisabled + ? { + // Ref.: https://github.com/brianc/node-postgres/issues/2009 + rejectUnauthorized: false, + } + : false, + }, + models: Object.values(models) as any, + pool: { + max: poolMax, + min: poolMin, + acquire: 30000, + idle: 10000, + }, + }); +} /** * This function is used to test the database connection on startup. It will * throw a descriptive error if the connection fails. */ -export const checkConnection = async () => { +export const checkConnection = async (db: Sequelize) => { try { - await sequelize.authenticate(); + await db.authenticate(); } catch (error) { if (error.message.includes("does not support SSL")) { Logger.fatal( @@ -55,38 +57,58 @@ export const checkConnection = async () => { } }; -export const migrations = new Umzug({ - migrations: { - glob: ["migrations/*.js", { cwd: path.resolve("server") }], - resolve: ({ name, path, context }) => { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const migration = require(path as string); - return { - name, - up: async () => migration.up(context, Sequelize), - down: async () => migration.down(context, Sequelize), - }; +export function createMigrationRunner( + db: Sequelize, + glob: + | string + | [ + string, + { + cwd?: string | undefined; + ignore?: string | string[] | undefined; + } + ] +) { + return new Umzug({ + migrations: { + glob, + resolve: ({ name, path, context }) => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const migration = require(path as string); + return { + name, + up: async () => migration.up(context, Sequelize), + down: async () => migration.down(context, Sequelize), + }; + }, }, - }, - context: sequelize.getQueryInterface(), - storage: new SequelizeStorage({ sequelize }), - logger: { - warn: (params) => Logger.warn("database", params), - error: (params: Record & MigrationError) => - Logger.error(params.message, params), - info: (params) => - Logger.info( - "database", - params.event === "migrating" - ? `Migrating ${params.name}…` - : `Migrated ${params.name} in ${params.durationSeconds}s` - ), - debug: (params) => - Logger.debug( - "database", - params.event === "migrating" - ? `Migrating ${params.name}…` - : `Migrated ${params.name} in ${params.durationSeconds}s` - ), - }, -}); + context: db.getQueryInterface(), + storage: new SequelizeStorage({ sequelize: db }), + logger: { + warn: (params) => Logger.warn("database", params), + error: (params: Record & MigrationError) => + Logger.error(params.message, params), + info: (params) => + Logger.info( + "database", + params.event === "migrating" + ? `Migrating ${params.name}…` + : `Migrated ${params.name} in ${params.durationSeconds}s` + ), + debug: (params) => + Logger.debug( + "database", + params.event === "migrating" + ? `Migrating ${params.name}…` + : `Migrated ${params.name} in ${params.durationSeconds}s` + ), + }, + }); +} + +export const sequelize = createDatabaseInstance(url, models); + +export const migrations = createMigrationRunner(sequelize, [ + "migrations/*.js", + { cwd: path.resolve("server") }, +]);