Skip to content

Commit d0e3be4

Browse files
JakeGinnivanelhigu
authored andcommitted
Extract MigrationGenerator from Migrator (knex#2786)
1 parent f01d5fa commit d0e3be4

File tree

3 files changed

+106
-85
lines changed

3 files changed

+106
-85
lines changed

.editorconfig

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
indent_style = space
6+
indent_size = 2

src/migrate/MigrationGenerator.js

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import mkdirp from 'mkdirp';
4+
import Promise from 'bluebird';
5+
import { template } from 'lodash';
6+
import { getMergedConfig } from './Migrator';
7+
8+
export default class MigrationGenerator {
9+
constructor(migrationConfig) {
10+
this.config = getMergedConfig(migrationConfig);
11+
}
12+
13+
// Creates a new migration, with a given name.
14+
make(name, config) {
15+
this.config = getMergedConfig(config, this.config);
16+
if (!name) {
17+
return Promise.reject(
18+
new Error('A name must be specified for the generated migration')
19+
);
20+
}
21+
22+
return this._ensureFolder(config)
23+
.then((val) => this._generateStubTemplate(val))
24+
.then((val) => this._writeNewMigration(name, val));
25+
}
26+
27+
// Ensures a folder for the migrations exist, dependent on the migration
28+
// config settings.
29+
_ensureFolder() {
30+
const dirs = this._absoluteConfigDirs();
31+
32+
const promises = dirs.map((dir) => {
33+
return Promise.promisify(fs.stat, { context: fs })(dir).catch(() =>
34+
Promise.promisify(mkdirp)(dir)
35+
);
36+
});
37+
38+
return Promise.all(promises);
39+
}
40+
41+
// Generates the stub template for the current migration, returning a compiled
42+
// template.
43+
_generateStubTemplate() {
44+
const stubPath =
45+
this.config.stub ||
46+
path.join(__dirname, 'stub', this.config.extension + '.stub');
47+
48+
return Promise.promisify(fs.readFile, { context: fs })(stubPath).then(
49+
(stub) => template(stub.toString(), { variable: 'd' })
50+
);
51+
}
52+
53+
// Write a new migration to disk, using the config and generated filename,
54+
// passing any `variables` given in the config to the template.
55+
_writeNewMigration(name, tmpl) {
56+
const { config } = this;
57+
const dirs = this._absoluteConfigDirs();
58+
const dir = dirs.slice(-1)[0]; // Get last specified directory
59+
60+
if (name[0] === '-') name = name.slice(1);
61+
const filename = yyyymmddhhmmss() + '_' + name + '.' + config.extension;
62+
63+
return Promise.promisify(fs.writeFile, { context: fs })(
64+
path.join(dir, filename),
65+
tmpl(config.variables || {})
66+
).return(path.join(dir, filename));
67+
}
68+
69+
_absoluteConfigDirs() {
70+
const directories = Array.isArray(this.config.directory)
71+
? this.config.directory
72+
: [this.config.directory];
73+
return directories.map((directory) => {
74+
return path.resolve(process.cwd(), directory);
75+
});
76+
}
77+
}
78+
79+
// Ensure that we have 2 places for each of the date segments.
80+
function padDate(segment) {
81+
segment = segment.toString();
82+
return segment[1] ? segment : `0${segment}`;
83+
}
84+
85+
// Get a date object in the correct format, without requiring a full out library
86+
// like "moment.js".
87+
function yyyymmddhhmmss() {
88+
const d = new Date();
89+
return (
90+
d.getFullYear().toString() +
91+
padDate(d.getMonth() + 1) +
92+
padDate(d.getDate()) +
93+
padDate(d.getHours()) +
94+
padDate(d.getMinutes()) +
95+
padDate(d.getSeconds())
96+
);
97+
}

src/migrate/Migrator.js

+3-85
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// Migrator
22
// -------
3-
import fs from 'fs';
4-
import path from 'path';
5-
import mkdirp from 'mkdirp';
63
import Promise from 'bluebird';
74
import {
85
assign,
@@ -14,7 +11,6 @@ import {
1411
isEmpty,
1512
isUndefined,
1613
max,
17-
template,
1814
} from 'lodash';
1915
import inherits from 'inherits';
2016
import {
@@ -26,6 +22,7 @@ import {
2622
import { getSchemaBuilder } from './table-creator';
2723
import * as migrationListResolver from './migration-list-resolver';
2824
import FsMigrations, { DEFAULT_LOAD_EXTENSIONS } from './sources/fs-migrations';
25+
import MigrationGenerator from './MigrationGenerator';
2926

3027
function LockError(msg) {
3128
this.name = 'MigrationLocked';
@@ -51,6 +48,7 @@ export default class Migrator {
5148
constructor(knex) {
5249
this.knex = knex;
5350
this.config = getMergedConfig(knex.client.config.migrations);
51+
this.generator = new MigrationGenerator(knex.client.config.migrations);
5452

5553
this._activeMigration = {
5654
fileName: null,
@@ -145,30 +143,7 @@ export default class Migrator {
145143
// Creates a new migration, with a given name.
146144
make(name, config) {
147145
this.config = getMergedConfig(config, this.config);
148-
149-
if (!name) {
150-
return Promise.reject(
151-
new Error('A name must be specified for the generated migration')
152-
);
153-
}
154-
155-
return this._ensureFolder(config)
156-
.then((val) => this._generateStubTemplate(val))
157-
.then((val) => this._writeNewMigration(name, val));
158-
}
159-
160-
// Ensures a folder for the migrations exist, dependent on the migration
161-
// config settings.
162-
_ensureFolder() {
163-
const dirs = this._absoluteConfigDirs();
164-
165-
const promises = dirs.map((dir) => {
166-
return Promise.promisify(fs.stat, { context: fs })(dir).catch(() =>
167-
Promise.promisify(mkdirp)(dir)
168-
);
169-
});
170-
171-
return Promise.all(promises);
146+
return this.generator.make(name, this.config);
172147
}
173148

174149
_isLocked(trx) {
@@ -305,33 +280,6 @@ export default class Migrator {
305280
return migration;
306281
}
307282

308-
// Generates the stub template for the current migration, returning a compiled
309-
// template.
310-
_generateStubTemplate() {
311-
const stubPath =
312-
this.config.stub ||
313-
path.join(__dirname, 'stub', this.config.extension + '.stub');
314-
return Promise.promisify(fs.readFile, { context: fs })(stubPath).then(
315-
(stub) => template(stub.toString(), { variable: 'd' })
316-
);
317-
}
318-
319-
// Write a new migration to disk, using the config and generated filename,
320-
// passing any `variables` given in the config to the template.
321-
_writeNewMigration(name, tmpl) {
322-
const { config } = this;
323-
const dirs = this._absoluteConfigDirs();
324-
const dir = dirs.slice(-1)[0]; // Get last specified directory
325-
326-
if (name[0] === '-') name = name.slice(1);
327-
const filename = yyyymmddhhmmss() + '_' + name + '.' + config.extension;
328-
329-
return Promise.promisify(fs.writeFile, { context: fs })(
330-
path.join(dir, filename),
331-
tmpl(config.variables || {})
332-
).return(path.join(dir, filename));
333-
}
334-
335283
// Get the last batch of migrations, by name, ordered by insert id in reverse
336284
// order.
337285
_getLastBatch([allMigrations]) {
@@ -433,16 +381,6 @@ export default class Migrator {
433381
);
434382
});
435383
}
436-
437-
/** Returns */
438-
_absoluteConfigDirs() {
439-
const directories = Array.isArray(this.config.directory)
440-
? this.config.directory
441-
: [this.config.directory];
442-
return directories.map((directory) => {
443-
return path.resolve(process.cwd(), directory);
444-
});
445-
}
446384
}
447385

448386
export function getMergedConfig(config, currentConfig) {
@@ -510,23 +448,3 @@ function warnPromise(knex, value, name, fn) {
510448
}
511449
return value;
512450
}
513-
514-
// Ensure that we have 2 places for each of the date segments.
515-
function padDate(segment) {
516-
segment = segment.toString();
517-
return segment[1] ? segment : `0${segment}`;
518-
}
519-
520-
// Get a date object in the correct format, without requiring a full out library
521-
// like "moment.js".
522-
function yyyymmddhhmmss() {
523-
const d = new Date();
524-
return (
525-
d.getFullYear().toString() +
526-
padDate(d.getMonth() + 1) +
527-
padDate(d.getDate()) +
528-
padDate(d.getHours()) +
529-
padDate(d.getMinutes()) +
530-
padDate(d.getSeconds())
531-
);
532-
}

0 commit comments

Comments
 (0)