@mikro-orm/migrations 7.0.0-rc.0 → 7.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MigrationGenerator.js +2 -3
- package/MigrationStorage.d.ts +7 -4
- package/MigrationStorage.js +2 -8
- package/Migrator.d.ts +13 -60
- package/Migrator.js +67 -219
- package/package.json +3 -4
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +1 -1
package/MigrationGenerator.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { fs } from '@mikro-orm/core/fs-utils';
|
|
2
|
-
import { writeFile } from 'node:fs/promises';
|
|
3
1
|
export class MigrationGenerator {
|
|
4
2
|
driver;
|
|
5
3
|
namingStrategy;
|
|
@@ -13,6 +11,7 @@ export class MigrationGenerator {
|
|
|
13
11
|
* @inheritDoc
|
|
14
12
|
*/
|
|
15
13
|
async generate(diff, path, name) {
|
|
14
|
+
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
16
15
|
/* v8 ignore next */
|
|
17
16
|
const defaultPath = this.options.emit === 'ts' && this.options.pathTs ? this.options.pathTs : this.options.path;
|
|
18
17
|
path = fs.normalizePath(this.driver.config.get('baseDir'), path ?? defaultPath);
|
|
@@ -21,7 +20,7 @@ export class MigrationGenerator {
|
|
|
21
20
|
const className = this.namingStrategy.classToMigrationName(timestamp, name);
|
|
22
21
|
const fileName = `${this.options.fileName(timestamp, name)}.${this.options.emit}`;
|
|
23
22
|
const ret = await this.generateMigrationFile(className, diff);
|
|
24
|
-
await writeFile(path + '/' + fileName, ret, { flush: true });
|
|
23
|
+
await fs.writeFile(path + '/' + fileName, ret, { flush: true });
|
|
25
24
|
return [ret, fileName];
|
|
26
25
|
}
|
|
27
26
|
/**
|
package/MigrationStorage.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type MigrationsOptions, type Transaction, type EntitySchema } from '@mikro-orm/core';
|
|
2
2
|
import { type AbstractSqlDriver } from '@mikro-orm/sql';
|
|
3
|
-
import type { MigrationParams, UmzugStorage } from 'umzug';
|
|
4
3
|
import type { MigrationRow } from './typings.js';
|
|
5
|
-
export declare class MigrationStorage
|
|
4
|
+
export declare class MigrationStorage {
|
|
6
5
|
protected readonly driver: AbstractSqlDriver;
|
|
7
6
|
protected readonly options: MigrationsOptions;
|
|
8
7
|
private readonly connection;
|
|
@@ -11,8 +10,12 @@ export declare class MigrationStorage implements UmzugStorage {
|
|
|
11
10
|
private readonly platform;
|
|
12
11
|
constructor(driver: AbstractSqlDriver, options: MigrationsOptions);
|
|
13
12
|
executed(): Promise<string[]>;
|
|
14
|
-
logMigration(params:
|
|
15
|
-
|
|
13
|
+
logMigration(params: {
|
|
14
|
+
name: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
unlogMigration(params: {
|
|
17
|
+
name: string;
|
|
18
|
+
}): Promise<void>;
|
|
16
19
|
getExecutedMigrations(): Promise<MigrationRow[]>;
|
|
17
20
|
ensureTable(): Promise<void>;
|
|
18
21
|
setMasterMigration(trx: Transaction): void;
|
package/MigrationStorage.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { defineEntity, p } from '@mikro-orm/core';
|
|
2
2
|
import { DatabaseTable, } from '@mikro-orm/sql';
|
|
3
|
-
import { parse } from 'node:path';
|
|
4
3
|
export class MigrationStorage {
|
|
5
4
|
driver;
|
|
6
5
|
options;
|
|
@@ -37,7 +36,7 @@ export class MigrationStorage {
|
|
|
37
36
|
.orderBy({ id: 'asc' })
|
|
38
37
|
.execute('all', false);
|
|
39
38
|
return res.map(row => {
|
|
40
|
-
if (typeof row.executed_at === 'string') {
|
|
39
|
+
if (typeof row.executed_at === 'string' || typeof row.executed_at === 'number') {
|
|
41
40
|
row.executed_at = new Date(row.executed_at);
|
|
42
41
|
}
|
|
43
42
|
return row;
|
|
@@ -88,12 +87,7 @@ export class MigrationStorage {
|
|
|
88
87
|
* @internal
|
|
89
88
|
*/
|
|
90
89
|
getMigrationName(name) {
|
|
91
|
-
|
|
92
|
-
if (['.js', '.ts'].includes(parsedName.ext)) {
|
|
93
|
-
// strip extension
|
|
94
|
-
return parsedName.name;
|
|
95
|
-
}
|
|
96
|
-
return name;
|
|
90
|
+
return name.replace(/\.[jt]s$/, '');
|
|
97
91
|
}
|
|
98
92
|
/**
|
|
99
93
|
* @internal
|
package/Migrator.d.ts
CHANGED
|
@@ -1,32 +1,18 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import {
|
|
3
|
-
import { DatabaseSchema, type EntityManager } from '@mikro-orm/sql';
|
|
4
|
-
import type { Migration } from './Migration.js';
|
|
1
|
+
import { type IMigrationGenerator, type IMigrationRunner, type IMigratorStorage, type MikroORM } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractMigrator } from '@mikro-orm/core/migrations';
|
|
3
|
+
import { type AbstractSqlDriver, DatabaseSchema, type EntityManager } from '@mikro-orm/sql';
|
|
5
4
|
import { MigrationStorage } from './MigrationStorage.js';
|
|
6
|
-
import type {
|
|
7
|
-
export declare class Migrator
|
|
8
|
-
private readonly em;
|
|
9
|
-
private umzug;
|
|
10
|
-
private runner;
|
|
11
|
-
private storage;
|
|
12
|
-
private generator;
|
|
13
|
-
private readonly driver;
|
|
5
|
+
import type { MigrationResult } from './typings.js';
|
|
6
|
+
export declare class Migrator extends AbstractMigrator<AbstractSqlDriver> {
|
|
14
7
|
private readonly schemaGenerator;
|
|
15
|
-
private
|
|
16
|
-
private readonly options;
|
|
17
|
-
private readonly absolutePath;
|
|
18
|
-
private readonly snapshotPath;
|
|
8
|
+
private snapshotPath?;
|
|
19
9
|
constructor(em: EntityManager);
|
|
20
|
-
/**
|
|
21
|
-
* Checks if `src` folder exists, it so, tries to adjust the migrations and seeders paths automatically to use it.
|
|
22
|
-
* If there is a `dist` or `build` folder, it will be used for the JS variant (`path` option), while the `src` folder will be
|
|
23
|
-
* used for the TS variant (`pathTs` option).
|
|
24
|
-
*
|
|
25
|
-
* If the default folder exists (e.g. `/migrations`), the config will respect that, so this auto-detection should not
|
|
26
|
-
* break existing projects, only help with the new ones.
|
|
27
|
-
*/
|
|
28
|
-
private detectSourceFolder;
|
|
29
10
|
static register(orm: MikroORM): void;
|
|
11
|
+
protected createRunner(): IMigrationRunner;
|
|
12
|
+
protected createStorage(): IMigratorStorage;
|
|
13
|
+
protected getDefaultGenerator(): IMigrationGenerator;
|
|
14
|
+
private getSnapshotPath;
|
|
15
|
+
protected init(): Promise<void>;
|
|
30
16
|
/**
|
|
31
17
|
* @inheritDoc
|
|
32
18
|
*/
|
|
@@ -36,15 +22,7 @@ export declare class Migrator implements IMigrator {
|
|
|
36
22
|
* @inheritDoc
|
|
37
23
|
*/
|
|
38
24
|
createInitial(path?: string, name?: string, blank?: boolean): Promise<MigrationResult>;
|
|
39
|
-
|
|
40
|
-
* @inheritDoc
|
|
41
|
-
*/
|
|
42
|
-
on(eventName: MigratorEvent, listener: (event: UmzugMigration) => MaybePromise<void>): this;
|
|
43
|
-
/**
|
|
44
|
-
* @inheritDoc
|
|
45
|
-
*/
|
|
46
|
-
off(eventName: MigratorEvent, listener: (event: UmzugMigration) => MaybePromise<void>): this;
|
|
47
|
-
private createUmzug;
|
|
25
|
+
getStorage(): MigrationStorage;
|
|
48
26
|
/**
|
|
49
27
|
* Initial migration can be created only if:
|
|
50
28
|
* 1. no previous migrations were generated or executed
|
|
@@ -54,32 +32,7 @@ export declare class Migrator implements IMigrator {
|
|
|
54
32
|
* If only some of the tables are present, exception is thrown.
|
|
55
33
|
*/
|
|
56
34
|
private validateInitialMigration;
|
|
57
|
-
|
|
58
|
-
* @inheritDoc
|
|
59
|
-
*/
|
|
60
|
-
getExecuted(): Promise<MigrationRow[]>;
|
|
61
|
-
private ensureDatabase;
|
|
62
|
-
/**
|
|
63
|
-
* @inheritDoc
|
|
64
|
-
*/
|
|
65
|
-
getPending(): Promise<UmzugMigration[]>;
|
|
66
|
-
/**
|
|
67
|
-
* @inheritDoc
|
|
68
|
-
*/
|
|
69
|
-
up(options?: string | string[] | MigrateOptions): Promise<UmzugMigration[]>;
|
|
70
|
-
/**
|
|
71
|
-
* @inheritDoc
|
|
72
|
-
*/
|
|
73
|
-
down(options?: string | string[] | MigrateOptions): Promise<UmzugMigration[]>;
|
|
74
|
-
getStorage(): MigrationStorage;
|
|
75
|
-
protected resolve(params: MigrationParams<any>): RunnableMigration<any>;
|
|
76
|
-
protected getSchemaFromSnapshot(): DatabaseSchema | undefined;
|
|
35
|
+
protected getSchemaFromSnapshot(): Promise<DatabaseSchema | undefined>;
|
|
77
36
|
protected storeCurrentSchema(): Promise<void>;
|
|
78
|
-
protected initialize(MigrationClass: Constructor<Migration>, name: string): RunnableMigration<any>;
|
|
79
37
|
private getSchemaDiff;
|
|
80
|
-
private getMigrationFilename;
|
|
81
|
-
private prefix;
|
|
82
|
-
private runMigrations;
|
|
83
|
-
private runInTransaction;
|
|
84
|
-
private ensureMigrationsDirExists;
|
|
85
38
|
}
|
package/Migrator.js
CHANGED
|
@@ -1,82 +1,65 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { existsSync, writeFileSync } from 'node:fs';
|
|
4
|
-
import { t, Type, UnknownType, Utils, } from '@mikro-orm/core';
|
|
5
|
-
import { fs } from '@mikro-orm/core/fs-utils';
|
|
1
|
+
import { t, Type, UnknownType, } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractMigrator } from '@mikro-orm/core/migrations';
|
|
6
3
|
import { DatabaseSchema, DatabaseTable, } from '@mikro-orm/sql';
|
|
7
4
|
import { MigrationRunner } from './MigrationRunner.js';
|
|
8
5
|
import { MigrationStorage } from './MigrationStorage.js';
|
|
9
6
|
import { TSMigrationGenerator } from './TSMigrationGenerator.js';
|
|
10
7
|
import { JSMigrationGenerator } from './JSMigrationGenerator.js';
|
|
11
|
-
export class Migrator {
|
|
12
|
-
em;
|
|
13
|
-
umzug;
|
|
14
|
-
runner;
|
|
15
|
-
storage;
|
|
16
|
-
generator;
|
|
17
|
-
driver;
|
|
8
|
+
export class Migrator extends AbstractMigrator {
|
|
18
9
|
schemaGenerator;
|
|
19
|
-
config;
|
|
20
|
-
options;
|
|
21
|
-
absolutePath;
|
|
22
10
|
snapshotPath;
|
|
23
11
|
constructor(em) {
|
|
24
|
-
|
|
25
|
-
this.driver = this.em.getDriver();
|
|
26
|
-
this.config = this.em.config;
|
|
27
|
-
this.options = this.config.get('migrations');
|
|
12
|
+
super(em);
|
|
28
13
|
this.schemaGenerator = this.config.getExtension('@mikro-orm/schema-generator');
|
|
29
|
-
this.detectSourceFolder();
|
|
30
|
-
/* v8 ignore next */
|
|
31
|
-
const key = (this.config.get('preferTs', Utils.detectTypeScriptSupport()) && this.options.pathTs) ? 'pathTs' : 'path';
|
|
32
|
-
this.absolutePath = fs.absolutePath(this.options[key], this.config.get('baseDir'));
|
|
33
|
-
// for snapshots, we always want to use the path based on `emit` option, regardless of whether we run in TS context
|
|
34
|
-
/* v8 ignore next */
|
|
35
|
-
const snapshotPath = this.options.emit === 'ts' && this.options.pathTs ? this.options.pathTs : this.options.path;
|
|
36
|
-
const absoluteSnapshotPath = fs.absolutePath(snapshotPath, this.config.get('baseDir'));
|
|
37
|
-
const dbName = basename(this.config.get('dbName'));
|
|
38
|
-
const snapshotName = this.options.snapshotName ?? `.snapshot-${dbName}`;
|
|
39
|
-
this.snapshotPath = fs.normalizePath(absoluteSnapshotPath, `${snapshotName}.json`);
|
|
40
|
-
this.createUmzug();
|
|
41
14
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
15
|
+
static register(orm) {
|
|
16
|
+
orm.config.registerExtension('@mikro-orm/migrator', () => new Migrator(orm.em));
|
|
17
|
+
}
|
|
18
|
+
createRunner() {
|
|
19
|
+
return new MigrationRunner(this.driver, this.options, this.config);
|
|
20
|
+
}
|
|
21
|
+
createStorage() {
|
|
22
|
+
return new MigrationStorage(this.driver, this.options);
|
|
23
|
+
}
|
|
24
|
+
getDefaultGenerator() {
|
|
25
|
+
if (this.options.emit === 'js' || this.options.emit === 'cjs') {
|
|
26
|
+
return new JSMigrationGenerator(this.driver, this.config.getNamingStrategy(), this.options);
|
|
27
|
+
}
|
|
28
|
+
return new TSMigrationGenerator(this.driver, this.config.getNamingStrategy(), this.options);
|
|
29
|
+
}
|
|
30
|
+
async getSnapshotPath() {
|
|
31
|
+
if (!this.snapshotPath) {
|
|
32
|
+
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
33
|
+
// for snapshots, we always want to use the path based on `emit` option, regardless of whether we run in TS context
|
|
34
|
+
/* v8 ignore next */
|
|
35
|
+
const snapshotPath = this.options.emit === 'ts' && this.options.pathTs ? this.options.pathTs : this.options.path;
|
|
36
|
+
const absoluteSnapshotPath = fs.absolutePath(snapshotPath, this.config.get('baseDir'));
|
|
37
|
+
const dbName = this.config.get('dbName').replace(/\\/g, '/').split('/').pop();
|
|
38
|
+
const snapshotName = this.options.snapshotName ?? `.snapshot-${dbName}`;
|
|
39
|
+
this.snapshotPath = fs.normalizePath(absoluteSnapshotPath, `${snapshotName}.json`);
|
|
40
|
+
}
|
|
41
|
+
return this.snapshotPath;
|
|
42
|
+
}
|
|
43
|
+
async init() {
|
|
44
|
+
if (this.initialized) {
|
|
55
45
|
return;
|
|
56
46
|
}
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const buildDir = fs.pathExists(baseDir + '/build');
|
|
60
|
-
// if neither `dist` nor `build` exist, we use the `src` folder as it might be a JS project without building, but with `src` folder
|
|
47
|
+
await super.init();
|
|
48
|
+
const created = await this.schemaGenerator.ensureDatabase();
|
|
61
49
|
/* v8 ignore next */
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!this.options.path && !this.options.pathTs && !exists) {
|
|
65
|
-
this.options.path = `${path}/migrations`;
|
|
66
|
-
this.options.pathTs = './src/migrations';
|
|
50
|
+
if (created) {
|
|
51
|
+
this.initServices();
|
|
67
52
|
}
|
|
68
|
-
|
|
69
|
-
static register(orm) {
|
|
70
|
-
orm.config.registerExtension('@mikro-orm/migrator', () => new Migrator(orm.em));
|
|
53
|
+
await this.storage.ensureTable();
|
|
71
54
|
}
|
|
72
55
|
/**
|
|
73
56
|
* @inheritDoc
|
|
74
57
|
*/
|
|
75
58
|
async create(path, blank = false, initial = false, name) {
|
|
59
|
+
await this.init();
|
|
76
60
|
if (initial) {
|
|
77
61
|
return this.createInitial(path, name, blank);
|
|
78
62
|
}
|
|
79
|
-
this.ensureMigrationsDirExists();
|
|
80
63
|
const diff = await this.getSchemaDiff(blank, initial);
|
|
81
64
|
if (diff.up.length === 0) {
|
|
82
65
|
return { fileName: '', code: '', diff };
|
|
@@ -90,7 +73,7 @@ export class Migrator {
|
|
|
90
73
|
};
|
|
91
74
|
}
|
|
92
75
|
async checkSchema() {
|
|
93
|
-
this.
|
|
76
|
+
await this.init();
|
|
94
77
|
const diff = await this.getSchemaDiff(false, false);
|
|
95
78
|
return diff.up.length > 0;
|
|
96
79
|
}
|
|
@@ -98,13 +81,13 @@ export class Migrator {
|
|
|
98
81
|
* @inheritDoc
|
|
99
82
|
*/
|
|
100
83
|
async createInitial(path, name, blank = false) {
|
|
101
|
-
this.
|
|
84
|
+
await this.init();
|
|
102
85
|
const schemaExists = await this.validateInitialMigration(blank);
|
|
103
86
|
const diff = await this.getSchemaDiff(blank, true);
|
|
104
87
|
const migration = await this.generator.generate(diff, path, name);
|
|
105
88
|
await this.storeCurrentSchema();
|
|
106
89
|
if (schemaExists && !blank) {
|
|
107
|
-
await this.storage.logMigration({ name: migration[1]
|
|
90
|
+
await this.storage.logMigration({ name: migration[1] });
|
|
108
91
|
}
|
|
109
92
|
return {
|
|
110
93
|
fileName: migration[1],
|
|
@@ -112,57 +95,8 @@ export class Migrator {
|
|
|
112
95
|
diff,
|
|
113
96
|
};
|
|
114
97
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
*/
|
|
118
|
-
on(eventName, listener) {
|
|
119
|
-
this.umzug.on(eventName, listener);
|
|
120
|
-
return this;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* @inheritDoc
|
|
124
|
-
*/
|
|
125
|
-
off(eventName, listener) {
|
|
126
|
-
this.umzug.off(eventName, listener);
|
|
127
|
-
return this;
|
|
128
|
-
}
|
|
129
|
-
createUmzug() {
|
|
130
|
-
this.runner = new MigrationRunner(this.driver, this.options, this.config);
|
|
131
|
-
this.storage = new MigrationStorage(this.driver, this.options);
|
|
132
|
-
let migrations = {
|
|
133
|
-
glob: join(this.absolutePath, this.options.glob).replace(/\\/g, '/'),
|
|
134
|
-
resolve: (params) => this.resolve(params),
|
|
135
|
-
};
|
|
136
|
-
if (this.options.migrationsList) {
|
|
137
|
-
migrations = this.options.migrationsList.map(migration => {
|
|
138
|
-
if (typeof migration === 'function') {
|
|
139
|
-
return this.initialize(migration, migration.name);
|
|
140
|
-
}
|
|
141
|
-
return this.initialize(migration.class, migration.name);
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
this.umzug = new Umzug({
|
|
145
|
-
storage: this.storage,
|
|
146
|
-
logger: undefined,
|
|
147
|
-
migrations,
|
|
148
|
-
});
|
|
149
|
-
/* v8 ignore else */
|
|
150
|
-
if (!this.options.silent) {
|
|
151
|
-
const logger = this.config.getLogger();
|
|
152
|
-
this.umzug.on('migrating', event => logger.log('migrator', `Processing '${event.name}'`, { enabled: true }));
|
|
153
|
-
this.umzug.on('migrated', event => logger.log('migrator', `Applied '${event.name}'`, { enabled: true }));
|
|
154
|
-
this.umzug.on('reverting', event => logger.log('migrator', `Processing '${event.name}'`, { enabled: true }));
|
|
155
|
-
this.umzug.on('reverted', event => logger.log('migrator', `Reverted '${event.name}'`, { enabled: true }));
|
|
156
|
-
}
|
|
157
|
-
if (this.options.generator) {
|
|
158
|
-
this.generator = new this.options.generator(this.driver, this.config.getNamingStrategy(), this.options);
|
|
159
|
-
}
|
|
160
|
-
else if (this.options.emit === 'js' || this.options.emit === 'cjs') {
|
|
161
|
-
this.generator = new JSMigrationGenerator(this.driver, this.config.getNamingStrategy(), this.options);
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
this.generator = new TSMigrationGenerator(this.driver, this.config.getNamingStrategy(), this.options);
|
|
165
|
-
}
|
|
98
|
+
getStorage() {
|
|
99
|
+
return this.storage;
|
|
166
100
|
}
|
|
167
101
|
/**
|
|
168
102
|
* Initial migration can be created only if:
|
|
@@ -202,62 +136,16 @@ export class Migrator {
|
|
|
202
136
|
}
|
|
203
137
|
return expected.size === exists.size;
|
|
204
138
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
async getExecuted() {
|
|
209
|
-
await this.ensureDatabase();
|
|
210
|
-
return this.storage.getExecutedMigrations();
|
|
211
|
-
}
|
|
212
|
-
async ensureDatabase() {
|
|
213
|
-
this.ensureMigrationsDirExists();
|
|
214
|
-
const created = await this.schemaGenerator.ensureDatabase();
|
|
215
|
-
/* v8 ignore next */
|
|
216
|
-
if (created) {
|
|
217
|
-
this.createUmzug();
|
|
139
|
+
async getSchemaFromSnapshot() {
|
|
140
|
+
if (!this.options.snapshot) {
|
|
141
|
+
return undefined;
|
|
218
142
|
}
|
|
219
|
-
await this.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
* @inheritDoc
|
|
223
|
-
*/
|
|
224
|
-
async getPending() {
|
|
225
|
-
await this.ensureDatabase();
|
|
226
|
-
return this.umzug.pending();
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* @inheritDoc
|
|
230
|
-
*/
|
|
231
|
-
async up(options) {
|
|
232
|
-
return this.runMigrations('up', options);
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* @inheritDoc
|
|
236
|
-
*/
|
|
237
|
-
async down(options) {
|
|
238
|
-
return this.runMigrations('down', options);
|
|
239
|
-
}
|
|
240
|
-
getStorage() {
|
|
241
|
-
return this.storage;
|
|
242
|
-
}
|
|
243
|
-
resolve(params) {
|
|
244
|
-
const createMigrationHandler = async (method) => {
|
|
245
|
-
const migration = await fs.dynamicImport(params.path);
|
|
246
|
-
const MigrationClass = Object.values(migration).find(cls => typeof cls === 'function' && typeof cls.constructor === 'function');
|
|
247
|
-
const instance = new MigrationClass(this.driver, this.config);
|
|
248
|
-
await this.runner.run(instance, method);
|
|
249
|
-
};
|
|
250
|
-
return {
|
|
251
|
-
name: this.storage.getMigrationName(params.name),
|
|
252
|
-
up: () => createMigrationHandler('up'),
|
|
253
|
-
down: () => createMigrationHandler('down'),
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
getSchemaFromSnapshot() {
|
|
257
|
-
if (!this.options.snapshot || !existsSync(this.snapshotPath)) {
|
|
143
|
+
const snapshotPath = await this.getSnapshotPath();
|
|
144
|
+
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
145
|
+
if (!fs.pathExists(snapshotPath)) {
|
|
258
146
|
return undefined;
|
|
259
147
|
}
|
|
260
|
-
const data = fs.readJSONSync(
|
|
148
|
+
const data = fs.readJSONSync(snapshotPath);
|
|
261
149
|
const schema = new DatabaseSchema(this.driver.getPlatform(), this.config.get('schema'));
|
|
262
150
|
const { tables, namespaces, ...rest } = data;
|
|
263
151
|
const tableInstances = tables.map((tbl) => {
|
|
@@ -279,16 +167,10 @@ export class Migrator {
|
|
|
279
167
|
if (!this.options.snapshot) {
|
|
280
168
|
return;
|
|
281
169
|
}
|
|
170
|
+
const snapshotPath = await this.getSnapshotPath();
|
|
282
171
|
const schema = this.schemaGenerator.getTargetSchema();
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
initialize(MigrationClass, name) {
|
|
286
|
-
const instance = new MigrationClass(this.driver, this.config);
|
|
287
|
-
return {
|
|
288
|
-
name: this.storage.getMigrationName(name),
|
|
289
|
-
up: () => this.runner.run(instance, 'up'),
|
|
290
|
-
down: () => this.runner.run(instance, 'down'),
|
|
291
|
-
};
|
|
172
|
+
const { fs } = await import('@mikro-orm/core/fs-utils');
|
|
173
|
+
await fs.writeFile(snapshotPath, JSON.stringify(schema, null, 2));
|
|
292
174
|
}
|
|
293
175
|
async getSchemaDiff(blank, initial) {
|
|
294
176
|
const up = [];
|
|
@@ -296,17 +178,25 @@ export class Migrator {
|
|
|
296
178
|
// Split SQL by statement boundaries (semicolons followed by newline) rather than
|
|
297
179
|
// just newlines, to preserve multiline statements like view definitions.
|
|
298
180
|
// Blank lines (from double newlines) are preserved as empty strings for grouping.
|
|
181
|
+
// Splits inside single-quoted string literals are re-merged (GH #7185).
|
|
299
182
|
const splitStatements = (sql) => {
|
|
300
183
|
const result = [];
|
|
184
|
+
let buf = '';
|
|
301
185
|
for (const chunk of sql.split(/;\n/)) {
|
|
186
|
+
buf += (buf ? ';\n' : '') + chunk;
|
|
187
|
+
// odd number of single quotes means we're inside a string literal
|
|
188
|
+
if (buf.split(`'`).length % 2 === 0) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
302
191
|
// A chunk starting with \n indicates there was a blank line (grouping separator)
|
|
303
|
-
if (
|
|
192
|
+
if (buf.startsWith('\n')) {
|
|
304
193
|
result.push('');
|
|
305
194
|
}
|
|
306
|
-
const trimmed =
|
|
195
|
+
const trimmed = buf.trim();
|
|
307
196
|
if (trimmed) {
|
|
308
197
|
result.push(trimmed.endsWith(';') ? trimmed : trimmed + ';');
|
|
309
198
|
}
|
|
199
|
+
buf = '';
|
|
310
200
|
}
|
|
311
201
|
return result;
|
|
312
202
|
};
|
|
@@ -323,7 +213,7 @@ export class Migrator {
|
|
|
323
213
|
wrap: false,
|
|
324
214
|
safe: this.options.safe,
|
|
325
215
|
dropTables: this.options.dropTables,
|
|
326
|
-
fromSchema: this.getSchemaFromSnapshot(),
|
|
216
|
+
fromSchema: await this.getSchemaFromSnapshot(),
|
|
327
217
|
});
|
|
328
218
|
up.push(...splitStatements(diff.up));
|
|
329
219
|
down.push(...splitStatements(diff.down));
|
|
@@ -333,6 +223,7 @@ export class Migrator {
|
|
|
333
223
|
if (diff[i]) {
|
|
334
224
|
break;
|
|
335
225
|
}
|
|
226
|
+
/* v8 ignore next */
|
|
336
227
|
diff.splice(i, 1);
|
|
337
228
|
}
|
|
338
229
|
};
|
|
@@ -340,47 +231,4 @@ export class Migrator {
|
|
|
340
231
|
cleanUp(down);
|
|
341
232
|
return { up, down };
|
|
342
233
|
}
|
|
343
|
-
getMigrationFilename(name) {
|
|
344
|
-
name = name.replace(/\.[jt]s$/, '');
|
|
345
|
-
return name.match(/^\d{14}$/) ? this.options.fileName(name) : name;
|
|
346
|
-
}
|
|
347
|
-
prefix(options) {
|
|
348
|
-
if (typeof options === 'string' || Array.isArray(options)) {
|
|
349
|
-
return { migrations: Utils.asArray(options).map(name => this.getMigrationFilename(name)) };
|
|
350
|
-
}
|
|
351
|
-
if (!options) {
|
|
352
|
-
return {};
|
|
353
|
-
}
|
|
354
|
-
if (options.migrations) {
|
|
355
|
-
options.migrations = options.migrations.map(name => this.getMigrationFilename(name));
|
|
356
|
-
}
|
|
357
|
-
if (options.transaction) {
|
|
358
|
-
delete options.transaction;
|
|
359
|
-
}
|
|
360
|
-
['from', 'to'].filter(k => options[k]).forEach(k => options[k] = this.getMigrationFilename(options[k]));
|
|
361
|
-
return options;
|
|
362
|
-
}
|
|
363
|
-
async runMigrations(method, options) {
|
|
364
|
-
await this.ensureDatabase();
|
|
365
|
-
if (!this.options.transactional || !this.options.allOrNothing) {
|
|
366
|
-
return this.umzug[method](this.prefix(options));
|
|
367
|
-
}
|
|
368
|
-
if (Utils.isObject(options) && options.transaction) {
|
|
369
|
-
return this.runInTransaction(options.transaction, method, options);
|
|
370
|
-
}
|
|
371
|
-
return this.driver.getConnection().transactional(trx => this.runInTransaction(trx, method, options));
|
|
372
|
-
}
|
|
373
|
-
async runInTransaction(trx, method, options) {
|
|
374
|
-
this.runner.setMasterMigration(trx);
|
|
375
|
-
this.storage.setMasterMigration(trx);
|
|
376
|
-
const ret = await this.umzug[method](this.prefix(options));
|
|
377
|
-
this.runner.unsetMasterMigration();
|
|
378
|
-
this.storage.unsetMasterMigration();
|
|
379
|
-
return ret;
|
|
380
|
-
}
|
|
381
|
-
ensureMigrationsDirExists() {
|
|
382
|
-
if (!this.options.migrationsList) {
|
|
383
|
-
fs.ensureDir(this.absolutePath);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
234
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/migrations",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-rc.
|
|
4
|
+
"version": "7.0.0-rc.2",
|
|
5
5
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -50,13 +50,12 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@mikro-orm/sql": "7.0.0-rc.
|
|
54
|
-
"umzug": "3.8.2"
|
|
53
|
+
"@mikro-orm/sql": "7.0.0-rc.2"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
56
|
"@mikro-orm/core": "^6.6.4"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
|
-
"@mikro-orm/core": "7.0.0-rc.
|
|
59
|
+
"@mikro-orm/core": "7.0.0-rc.2"
|
|
61
60
|
}
|
|
62
61
|
}
|