chore: Expose createDatabaseInstance, createMigrationRunner methods
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -127,7 +127,12 @@ class Revision extends IdModel {
|
||||
|
||||
// instance methods
|
||||
|
||||
previous(): Promise<Revision | null> {
|
||||
/**
|
||||
* 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<Revision | null> {
|
||||
return (this.constructor as typeof Revision).findOne({
|
||||
where: {
|
||||
documentId: this.documentId,
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class RevisionCreatedNotificationsTask extends BaseTask<RevisionE
|
||||
await createSubscriptionsForDocument(document, event);
|
||||
|
||||
// Send notifications to mentioned users first
|
||||
const before = await revision.previous();
|
||||
const before = await revision.before();
|
||||
const oldMentions = before ? DocumentHelper.parseMentions(before) : [];
|
||||
const newMentions = DocumentHelper.parseMentions(document);
|
||||
const mentions = differenceBy(newMentions, oldMentions, "id");
|
||||
|
||||
@@ -34,7 +34,7 @@ router.post(
|
||||
});
|
||||
authorize(user, "read", document);
|
||||
after = revision;
|
||||
before = await revision.previous();
|
||||
before = await revision.before();
|
||||
} else if (documentId) {
|
||||
const document = await Document.findByPk(documentId, {
|
||||
userId: user.id,
|
||||
@@ -94,7 +94,7 @@ router.post(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
before = await revision.previous();
|
||||
before = await revision.before();
|
||||
}
|
||||
|
||||
const accept = ctx.request.headers["accept"];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import path from "path";
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
import { Model, Sequelize } from "sequelize-typescript";
|
||||
import { Umzug, SequelizeStorage, MigrationError } from "umzug";
|
||||
import env from "@server/env";
|
||||
import Logger from "../logging/Logger";
|
||||
@@ -8,41 +8,43 @@ import * as models from "../models";
|
||||
const isSSLDisabled = env.PGSSLMODE === "disable";
|
||||
const poolMax = env.DATABASE_CONNECTION_POOL_MAX ?? 5;
|
||||
const poolMin = env.DATABASE_CONNECTION_POOL_MIN ?? 0;
|
||||
const url =
|
||||
env.DATABASE_CONNECTION_POOL_URL ||
|
||||
env.DATABASE_URL ||
|
||||
"postgres://localhost:5432/outline";
|
||||
const url = env.DATABASE_CONNECTION_POOL_URL || env.DATABASE_URL;
|
||||
|
||||
export const sequelize = 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),
|
||||
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<string, unknown> & 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<string, unknown> & 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") },
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user