directus

Форк
0
148 строк · 4.4 Кб
1
import { useEnv } from '@directus/env';
2
import formatTitle from '@directus/format-title';
3
import fse from 'fs-extra';
4
import type { Knex } from 'knex';
5
import { orderBy } from 'lodash-es';
6
import { dirname } from 'node:path';
7
import { fileURLToPath } from 'node:url';
8
import path from 'path';
9
import { flushCaches } from '../../cache.js';
10
import { useLogger } from '../../logger.js';
11
import type { Migration } from '../../types/index.js';
12
import getModuleDefault from '../../utils/get-module-default.js';
13

14
const __dirname = dirname(fileURLToPath(import.meta.url));
15

16
export default async function run(database: Knex, direction: 'up' | 'down' | 'latest', log = true): Promise<void> {
17
	const env = useEnv();
18
	const logger = useLogger();
19

20
	let migrationFiles = await fse.readdir(__dirname);
21

22
	const customMigrationsPath = path.resolve(env['MIGRATIONS_PATH'] as string);
23

24
	let customMigrationFiles =
25
		((await fse.pathExists(customMigrationsPath)) && (await fse.readdir(customMigrationsPath))) || [];
26

27
	migrationFiles = migrationFiles.filter((file: string) => /^[0-9]+[A-Z]-[^.]+\.(?:js|ts)$/.test(file));
28

29
	customMigrationFiles = customMigrationFiles.filter((file: string) => file.includes('-') && /\.(c|m)?js$/.test(file));
30

31
	const completedMigrations = await database.select<Migration[]>('*').from('directus_migrations').orderBy('version');
32

33
	const migrations = [
34
		...migrationFiles.map((path) => parseFilePath(path)),
35
		...customMigrationFiles.map((path) => parseFilePath(path, true)),
36
	].sort((a, b) => (a.version! > b.version! ? 1 : -1));
37

38
	const migrationKeys = new Set(migrations.map((m) => m.version));
39

40
	if (migrations.length > migrationKeys.size) {
41
		throw new Error('Migration keys collide! Please ensure that every migration uses a unique key.');
42
	}
43

44
	function parseFilePath(filePath: string, custom = false) {
45
		const version = filePath.split('-')[0];
46
		const name = formatTitle(filePath.split('-').slice(1).join('_').split('.')[0]!);
47
		const completed = !!completedMigrations.find((migration) => migration.version === version);
48

49
		return {
50
			file: custom ? path.join(customMigrationsPath, filePath) : path.join(__dirname, filePath),
51
			version,
52
			name,
53
			completed,
54
		};
55
	}
56

57
	if (direction === 'up') await up();
58
	if (direction === 'down') await down();
59
	if (direction === 'latest') await latest();
60

61
	async function up() {
62
		const currentVersion = completedMigrations[completedMigrations.length - 1];
63

64
		let nextVersion: any;
65

66
		if (!currentVersion) {
67
			nextVersion = migrations[0];
68
		} else {
69
			nextVersion = migrations.find((migration) => {
70
				return migration.version! > currentVersion.version && migration.completed === false;
71
			});
72
		}
73

74
		if (!nextVersion) {
75
			throw Error('Nothing to upgrade');
76
		}
77

78
		const { up } = await import(`file://${nextVersion.file}`);
79

80
		if (!up) {
81
			logger.warn(`Couldn't find the "up" function from migration ${nextVersion.file}`);
82
		}
83

84
		if (log) {
85
			logger.info(`Applying ${nextVersion.name}...`);
86
		}
87

88
		await up(database);
89
		await database.insert({ version: nextVersion.version, name: nextVersion.name }).into('directus_migrations');
90

91
		await flushCaches(true);
92
	}
93

94
	async function down() {
95
		const lastAppliedMigration = orderBy(completedMigrations, ['timestamp', 'version'], ['desc', 'desc'])[0];
96

97
		if (!lastAppliedMigration) {
98
			throw Error('Nothing to downgrade');
99
		}
100

101
		const migration = migrations.find((migration) => migration.version === lastAppliedMigration.version);
102

103
		if (!migration) {
104
			throw new Error("Couldn't find migration");
105
		}
106

107
		const { down } = await import(`file://${migration.file}`);
108

109
		if (!down) {
110
			logger.warn(`Couldn't find the "down" function from migration ${migration.file}`);
111
		}
112

113
		if (log) {
114
			logger.info(`Undoing ${migration.name}...`);
115
		}
116

117
		await down(database);
118
		await database('directus_migrations').delete().where({ version: migration.version });
119

120
		await flushCaches(true);
121
	}
122

123
	async function latest() {
124
		let needsCacheFlush = false;
125

126
		for (const migration of migrations) {
127
			if (migration.completed === false) {
128
				needsCacheFlush = true;
129
				const { up } = getModuleDefault(await import(`file://${migration.file}`));
130

131
				if (!up) {
132
					logger.warn(`Couldn't find the "up" function from migration ${migration.file}`);
133
				}
134

135
				if (log) {
136
					logger.info(`Applying ${migration.name}...`);
137
				}
138

139
				await up(database);
140
				await database.insert({ version: migration.version, name: migration.name }).into('directus_migrations');
141
			}
142
		}
143

144
		if (needsCacheFlush) {
145
			await flushCaches(true);
146
		}
147
	}
148
}
149

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.