mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Server: Added commands to control db migrations - list, down, up
This commit is contained in:
parent
c8ccab808f
commit
2c79ce25fa
@ -8,3 +8,5 @@ packages/app-mobile
|
|||||||
packages/app-clipper
|
packages/app-clipper
|
||||||
packages/generator-joplin
|
packages/generator-joplin
|
||||||
packages/plugin-repo-cli
|
packages/plugin-repo-cli
|
||||||
|
packages/server/db-*.sqlite
|
||||||
|
packages/server/temp
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start-dev": "nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
|
"start-dev": "nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
|
||||||
|
"start-dev-no-watch": "node dist/app.js --env dev",
|
||||||
"devCreateDb": "node dist/app.js --env dev --create-db",
|
"devCreateDb": "node dist/app.js --env dev --create-db",
|
||||||
"devDropTables": "node dist/app.js --env dev --drop-tables",
|
"devDropTables": "node dist/app.js --env dev --drop-tables",
|
||||||
"devDropDb": "node dist/app.js --env dev --drop-db",
|
"devDropDb": "node dist/app.js --env dev --drop-db",
|
||||||
"start": "node dist/app.js",
|
"start": "node dist/app.js",
|
||||||
"generateTypes": "rm -f db-buildTypes.sqlite && npm run start -- --migrate-db --env buildTypes && node dist/tools/generateTypes.js && mv db-buildTypes.sqlite schema.sqlite",
|
"generateTypes": "rm -f db-buildTypes.sqlite && npm run start -- --migrate-latest --env buildTypes && node dist/tools/generateTypes.js && mv db-buildTypes.sqlite schema.sqlite",
|
||||||
"tsc": "tsc --project tsconfig.json",
|
"tsc": "tsc --project tsconfig.json",
|
||||||
"test": "jest --verbose=false",
|
"test": "jest --verbose=false",
|
||||||
"test-ci": "npm run test",
|
"test-ci": "npm run test",
|
||||||
|
@ -7,7 +7,7 @@ import { argv } from 'yargs';
|
|||||||
import Logger, { LoggerWrapper, TargetType } from '@joplin/lib/Logger';
|
import Logger, { LoggerWrapper, TargetType } from '@joplin/lib/Logger';
|
||||||
import config, { initConfig, runningInDocker, EnvVariables } from './config';
|
import config, { initConfig, runningInDocker, EnvVariables } from './config';
|
||||||
import { createDb, dropDb } from './tools/dbTools';
|
import { createDb, dropDb } from './tools/dbTools';
|
||||||
import { dropTables, connectDb, disconnectDb, migrateDb, waitForConnection, sqliteDefaultDir } from './db';
|
import { dropTables, connectDb, disconnectDb, migrateLatest, waitForConnection, sqliteDefaultDir, migrateList, migrateUp, migrateDown } from './db';
|
||||||
import { AppContext, Env, KoaNext } from './utils/types';
|
import { AppContext, Env, KoaNext } from './utils/types';
|
||||||
import FsDriverNode from '@joplin/lib/fs-driver-node';
|
import FsDriverNode from '@joplin/lib/fs-driver-node';
|
||||||
import routeHandler from './middleware/routeHandler';
|
import routeHandler from './middleware/routeHandler';
|
||||||
@ -205,10 +205,23 @@ async function main() {
|
|||||||
fs.writeFileSync(pidFile, `${process.pid}`);
|
fs.writeFileSync(pidFile, `${process.pid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv.migrateDb) {
|
let runCommandAndExitApp = true;
|
||||||
|
|
||||||
|
if (argv.migrateLatest) {
|
||||||
const db = await connectDb(config().database);
|
const db = await connectDb(config().database);
|
||||||
await migrateDb(db);
|
await migrateLatest(db);
|
||||||
await disconnectDb(db);
|
await disconnectDb(db);
|
||||||
|
} else if (argv.migrateUp) {
|
||||||
|
const db = await connectDb(config().database);
|
||||||
|
await migrateUp(db);
|
||||||
|
await disconnectDb(db);
|
||||||
|
} else if (argv.migrateDown) {
|
||||||
|
const db = await connectDb(config().database);
|
||||||
|
await migrateDown(db);
|
||||||
|
await disconnectDb(db);
|
||||||
|
} else if (argv.migrateList) {
|
||||||
|
const db = await connectDb(config().database);
|
||||||
|
console.info(await migrateList(db));
|
||||||
} else if (argv.dropDb) {
|
} else if (argv.dropDb) {
|
||||||
await dropDb(config().database, { ignoreIfNotExists: true });
|
await dropDb(config().database, { ignoreIfNotExists: true });
|
||||||
} else if (argv.dropTables) {
|
} else if (argv.dropTables) {
|
||||||
@ -218,6 +231,8 @@ async function main() {
|
|||||||
} else if (argv.createDb) {
|
} else if (argv.createDb) {
|
||||||
await createDb(config().database);
|
await createDb(config().database);
|
||||||
} else {
|
} else {
|
||||||
|
runCommandAndExitApp = false;
|
||||||
|
|
||||||
appLogger().info(`Starting server v${config().appVersion} (${env}) on port ${config().port} and PID ${process.pid}...`);
|
appLogger().info(`Starting server v${config().appVersion} (${env}) on port ${config().port} and PID ${process.pid}...`);
|
||||||
appLogger().info('Running in Docker:', runningInDocker());
|
appLogger().info('Running in Docker:', runningInDocker());
|
||||||
appLogger().info('Public base URL:', config().baseUrl);
|
appLogger().info('Public base URL:', config().baseUrl);
|
||||||
@ -239,7 +254,7 @@ async function main() {
|
|||||||
await initializeJoplinUtils(config(), ctx.joplinBase.models, ctx.joplinBase.services.mustache);
|
await initializeJoplinUtils(config(), ctx.joplinBase.models, ctx.joplinBase.services.mustache);
|
||||||
|
|
||||||
appLogger().info('Migrating database...');
|
appLogger().info('Migrating database...');
|
||||||
await migrateDb(ctx.joplinBase.db);
|
await migrateLatest(ctx.joplinBase.db);
|
||||||
|
|
||||||
appLogger().info('Starting services...');
|
appLogger().info('Starting services...');
|
||||||
await startServices(ctx.joplinBase.services);
|
await startServices(ctx.joplinBase.services);
|
||||||
@ -248,6 +263,8 @@ async function main() {
|
|||||||
|
|
||||||
app.listen(config().port);
|
app.listen(config().port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runCommandAndExitApp) process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error: any) => {
|
main().catch((error: any) => {
|
||||||
|
@ -121,14 +121,85 @@ export async function disconnectDb(db: DbConnection) {
|
|||||||
await db.destroy();
|
await db.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function migrateDb(db: DbConnection) {
|
export async function migrateLatest(db: DbConnection) {
|
||||||
await db.migrate.latest({
|
await db.migrate.latest({
|
||||||
directory: migrationDir,
|
directory: migrationDir,
|
||||||
// Disable transactions because the models might open one too
|
|
||||||
disableTransactions: true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function migrateUp(db: DbConnection) {
|
||||||
|
await db.migrate.up({
|
||||||
|
directory: migrationDir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateDown(db: DbConnection) {
|
||||||
|
await db.migrate.down({
|
||||||
|
directory: migrationDir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateList(db: DbConnection, asString: boolean = true) {
|
||||||
|
const migrations: any = await db.migrate.list({
|
||||||
|
directory: migrationDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
// The migration array has a rather inconsistent format:
|
||||||
|
//
|
||||||
|
// [
|
||||||
|
// // Done migrations
|
||||||
|
// [
|
||||||
|
// '20210809222118_email_key_fix.js',
|
||||||
|
// '20210814123815_testing.js',
|
||||||
|
// '20210814123816_testing.js'
|
||||||
|
// ],
|
||||||
|
// // Not done migrations
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// file: '20210814123817_testing.js',
|
||||||
|
// directory: '/path/to/packages/server/dist/migrations'
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// ]
|
||||||
|
|
||||||
|
if (!asString) return migrations;
|
||||||
|
|
||||||
|
const formatName = (migrationInfo: any) => {
|
||||||
|
const name = migrationInfo.file ? migrationInfo.file : migrationInfo;
|
||||||
|
|
||||||
|
const s = name.split('.');
|
||||||
|
s.pop();
|
||||||
|
return s.join('.');
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Line {
|
||||||
|
text: string;
|
||||||
|
done: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const output: Line[] = [];
|
||||||
|
|
||||||
|
for (const s of migrations[0]) {
|
||||||
|
output.push({
|
||||||
|
text: formatName(s),
|
||||||
|
done: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const s of migrations[1]) {
|
||||||
|
output.push({
|
||||||
|
text: formatName(s),
|
||||||
|
done: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
output.sort((a, b) => {
|
||||||
|
return a.text < b.text ? -1 : +1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return output.map(l => `${l.done ? '✓' : '✗'} ${l.text}`).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
function allTableNames(): string[] {
|
function allTableNames(): string[] {
|
||||||
const tableNames = Object.keys(databaseSchema);
|
const tableNames = Object.keys(databaseSchema);
|
||||||
tableNames.push('knex_migrations');
|
tableNames.push('knex_migrations');
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Knex } from 'knex';
|
// import { Knex } from 'knex';
|
||||||
import { DbConnection } from '../db';
|
import { DbConnection } from '../db';
|
||||||
|
|
||||||
export async function up(db: DbConnection): Promise<any> {
|
export async function up(_db: DbConnection): Promise<any> {
|
||||||
try {
|
// try {
|
||||||
await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
// await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
||||||
table.dropUnique(['recipient_email', 'key']);
|
// table.dropUnique(['recipient_email', 'key']);
|
||||||
});
|
// });
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.warn('Could not drop unique constraint - this is not an error.', error);
|
// // console.warn('Could not drop unique constraint - this is not an error.', error);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(_db: DbConnection): Promise<any> {
|
export async function down(_db: DbConnection): Promise<any> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { connectDb, disconnectDb, migrateDb } from '../db';
|
import { connectDb, disconnectDb, migrateLatest } from '../db';
|
||||||
import * as fs from 'fs-extra';
|
import * as fs from 'fs-extra';
|
||||||
import { DatabaseConfig } from '../utils/types';
|
import { DatabaseConfig } from '../utils/types';
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ export async function createDb(config: DatabaseConfig, options: CreateDbOptions
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const db = await connectDb(config);
|
const db = await connectDb(config);
|
||||||
await migrateDb(db);
|
await migrateLatest(db);
|
||||||
await disconnectDb(db);
|
await disconnectDb(db);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
error.message += `: ${config.name}`;
|
error.message += `: ${config.name}`;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DbConnection, dropTables, migrateDb } from '../db';
|
import { DbConnection, dropTables, migrateLatest } from '../db';
|
||||||
import newModelFactory from '../models/factory';
|
import newModelFactory from '../models/factory';
|
||||||
import { AccountType } from '../models/UserModel';
|
import { AccountType } from '../models/UserModel';
|
||||||
import { Config } from '../utils/types';
|
import { Config } from '../utils/types';
|
||||||
@ -15,7 +15,7 @@ export async function handleDebugCommands(argv: any, db: DbConnection, config: C
|
|||||||
|
|
||||||
export async function createTestUsers(db: DbConnection, config: Config) {
|
export async function createTestUsers(db: DbConnection, config: Config) {
|
||||||
await dropTables(db);
|
await dropTables(db);
|
||||||
await migrateDb(db);
|
await migrateLatest(db);
|
||||||
|
|
||||||
const password = 'hunter1hunter2hunter3';
|
const password = 'hunter1hunter2hunter3';
|
||||||
const models = newModelFactory(db, config);
|
const models = newModelFactory(db, config);
|
||||||
|
@ -106,9 +106,9 @@ async function main() {
|
|||||||
|
|
||||||
fs.removeSync(`${serverRoot}/db-testing.sqlite`);
|
fs.removeSync(`${serverRoot}/db-testing.sqlite`);
|
||||||
|
|
||||||
// const migrateCommand = 'NODE_ENV=testing node dist/app.js --migrate-db --env dev';
|
// const migrateCommand = 'NODE_ENV=testing node dist/app.js --migrate-latest --env dev';
|
||||||
const clearCommand = 'node dist/app.js --env dev --drop-tables';
|
const clearCommand = 'node dist/app.js --env dev --drop-tables';
|
||||||
const migrateCommand = 'node dist/app.js --env dev --migrate-db';
|
const migrateCommand = 'node dist/app.js --env dev --migrate-latest';
|
||||||
|
|
||||||
await execCommand(clearCommand);
|
await execCommand(clearCommand);
|
||||||
await execCommand(migrateCommand);
|
await execCommand(migrateCommand);
|
||||||
|
Loading…
Reference in New Issue
Block a user