@sqb/migrator 4.10.2 → 4.10.4
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/cjs/adapters/pg-migration-adapter.js +22 -11
- package/cjs/db-migrator.js +9 -3
- package/cjs/migration-adapter.js +3 -0
- package/cjs/migration-package.js +17 -11
- package/esm/adapters/pg-migration-adapter.js +21 -11
- package/esm/db-migrator.js +9 -3
- package/esm/migration-adapter.js +3 -0
- package/esm/migration-package.js +17 -11
- package/package.json +4 -4
- package/types/adapters/pg-migration-adapter.d.ts +7 -4
- package/types/db-migrator.d.ts +2 -2
- package/types/migration-adapter.d.ts +6 -3
- package/types/migration-package.d.ts +9 -11
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PgMigrationAdapter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
4
6
|
const postgresql_client_1 = require("postgresql-client");
|
|
5
7
|
const postgres_1 = require("@sqb/postgres");
|
|
6
8
|
const migration_adapter_js_1 = require("../migration-adapter.js");
|
|
@@ -11,7 +13,6 @@ class PgMigrationAdapter extends migration_adapter_js_1.MigrationAdapter {
|
|
|
11
13
|
constructor() {
|
|
12
14
|
super(...arguments);
|
|
13
15
|
this._infoSchema = 'public';
|
|
14
|
-
this._packageName = '';
|
|
15
16
|
this._version = 0;
|
|
16
17
|
this._status = types_js_1.MigrationStatus.idle;
|
|
17
18
|
this.defaultVariables = {
|
|
@@ -23,7 +24,7 @@ class PgMigrationAdapter extends migration_adapter_js_1.MigrationAdapter {
|
|
|
23
24
|
this.eventTable = 'migration_events';
|
|
24
25
|
}
|
|
25
26
|
get packageName() {
|
|
26
|
-
return this.
|
|
27
|
+
return this._migrationPackage.name;
|
|
27
28
|
}
|
|
28
29
|
get version() {
|
|
29
30
|
return this._version;
|
|
@@ -46,7 +47,7 @@ class PgMigrationAdapter extends migration_adapter_js_1.MigrationAdapter {
|
|
|
46
47
|
try {
|
|
47
48
|
const adapter = new PgMigrationAdapter();
|
|
48
49
|
adapter._connection = connection;
|
|
49
|
-
adapter.
|
|
50
|
+
adapter._migrationPackage = options.migrationPackage;
|
|
50
51
|
adapter._infoSchema = options.infoSchema || '__migration';
|
|
51
52
|
adapter.defaultVariables.schema = options.connection.schema || '';
|
|
52
53
|
if (!adapter.defaultVariables.schema) {
|
|
@@ -75,7 +76,9 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
75
76
|
version integer not null default 0,
|
|
76
77
|
event varchar(16) not null,
|
|
77
78
|
event_time timestamp without time zone not null,
|
|
79
|
+
title text,
|
|
78
80
|
message text not null,
|
|
81
|
+
filename text,
|
|
79
82
|
details text,
|
|
80
83
|
CONSTRAINT pk_${adapter.eventTable} PRIMARY KEY (id)
|
|
81
84
|
)`);
|
|
@@ -128,30 +131,37 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
128
131
|
}
|
|
129
132
|
async writeEvent(event) {
|
|
130
133
|
const sql = `insert into ${this.eventTableFull} ` +
|
|
131
|
-
'(package_name, version, event, event_time, message, details) ' +
|
|
132
|
-
'values ($1, $2, $3, CURRENT_TIMESTAMP, $4, $5)';
|
|
134
|
+
'(package_name, version, event, event_time, title, message, filename, details) ' +
|
|
135
|
+
'values ($1, $2, $3, CURRENT_TIMESTAMP, $4, $5, $6, $7)';
|
|
133
136
|
await this._connection.query(sql, {
|
|
134
137
|
params: [
|
|
135
138
|
this.packageName, event.version, event.event,
|
|
136
|
-
event.message, event.details
|
|
139
|
+
event.title, event.message, event.filename, event.details
|
|
137
140
|
]
|
|
138
141
|
});
|
|
139
142
|
}
|
|
140
|
-
async executeTask(task, variables) {
|
|
143
|
+
async executeTask(migrationPackage, migration, task, variables) {
|
|
141
144
|
variables = {
|
|
142
145
|
...this.defaultVariables,
|
|
143
146
|
...variables
|
|
144
147
|
};
|
|
145
148
|
if ((0, migration_package_js_1.isSqlScriptMigrationTask)(task)) {
|
|
146
149
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
let script;
|
|
151
|
+
if (typeof task.script === 'function') {
|
|
152
|
+
script = await task.script({ migrationPackage, migration, task, variables });
|
|
153
|
+
}
|
|
154
|
+
else
|
|
155
|
+
script = task.script;
|
|
156
|
+
if (typeof script !== 'string')
|
|
157
|
+
return;
|
|
158
|
+
script = this.replaceVariables(script, variables);
|
|
149
159
|
await this._connection.execute(script);
|
|
150
160
|
}
|
|
151
161
|
catch (e) {
|
|
152
162
|
let msg = `Error in task "${task.title}"`;
|
|
153
163
|
if (task.filename)
|
|
154
|
-
msg += '\n at ' + task.filename;
|
|
164
|
+
msg += '\n at ' + path_1.default.relative(migrationPackage.baseDir, task.filename);
|
|
155
165
|
if (e.lineNr) {
|
|
156
166
|
if (!task.filename)
|
|
157
167
|
e.message += '\n at';
|
|
@@ -169,8 +179,9 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
169
179
|
return;
|
|
170
180
|
}
|
|
171
181
|
if ((0, migration_package_js_1.isInsertDataMigrationTask)(task)) {
|
|
182
|
+
const tableName = this.replaceVariables(task.tableName, variables);
|
|
172
183
|
const script = task.rows
|
|
173
|
-
.map(row => this.rowToSql(
|
|
184
|
+
.map(row => this.rowToSql(tableName, row))
|
|
174
185
|
.join('\n');
|
|
175
186
|
await this._connection.execute(script);
|
|
176
187
|
}
|
package/cjs/db-migrator.js
CHANGED
|
@@ -25,7 +25,7 @@ class DbMigrator extends strict_typed_events_1.AsyncEventEmitter {
|
|
|
25
25
|
let migrationAdapter;
|
|
26
26
|
switch (options.connection.dialect) {
|
|
27
27
|
case 'postgres': {
|
|
28
|
-
migrationAdapter = await pg_migration_adapter_js_1.PgMigrationAdapter.create(options);
|
|
28
|
+
migrationAdapter = await pg_migration_adapter_js_1.PgMigrationAdapter.create({ ...options, migrationPackage });
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
31
31
|
default:
|
|
@@ -66,23 +66,29 @@ class DbMigrator extends strict_typed_events_1.AsyncEventEmitter {
|
|
|
66
66
|
await migrationAdapter.writeEvent({
|
|
67
67
|
event: migration_adapter_js_1.MigrationAdapter.EventKind.started,
|
|
68
68
|
version: migration.version,
|
|
69
|
+
title: task.title,
|
|
70
|
+
filename: task.filename,
|
|
69
71
|
message: `Task "${task.title}" started`
|
|
70
72
|
});
|
|
71
73
|
try {
|
|
72
|
-
await migrationAdapter.executeTask(task, {
|
|
74
|
+
await migrationAdapter.executeTask(migrationPackage, migration, task, {
|
|
73
75
|
schema: options.connection.schema,
|
|
74
76
|
...options.scriptVariables,
|
|
75
77
|
});
|
|
76
78
|
await migrationAdapter.writeEvent({
|
|
77
79
|
event: migration_adapter_js_1.MigrationAdapter.EventKind.success,
|
|
78
80
|
version: migration.version,
|
|
79
|
-
|
|
81
|
+
title: task.title,
|
|
82
|
+
filename: task.filename,
|
|
83
|
+
message: `Task "${task.title}" completed`,
|
|
80
84
|
});
|
|
81
85
|
}
|
|
82
86
|
catch (e) {
|
|
83
87
|
await migrationAdapter.writeEvent({
|
|
84
88
|
event: migration_adapter_js_1.MigrationAdapter.EventKind.error,
|
|
85
89
|
version: migration.version,
|
|
90
|
+
title: task.title,
|
|
91
|
+
filename: task.filename,
|
|
86
92
|
message: String(e),
|
|
87
93
|
details: e.message + '\n\n' +
|
|
88
94
|
Object.keys(e)
|
package/cjs/migration-adapter.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MigrationAdapter = void 0;
|
|
4
4
|
class MigrationAdapter {
|
|
5
|
+
replaceVariables(text, variables) {
|
|
6
|
+
return text.replace(/(\$\((\w+)\))/g, (s, ...args) => variables[args[1]] || s);
|
|
7
|
+
}
|
|
5
8
|
}
|
|
6
9
|
exports.MigrationAdapter = MigrationAdapter;
|
|
7
10
|
(function (MigrationAdapter) {
|
package/cjs/migration-package.js
CHANGED
|
@@ -7,7 +7,8 @@ const promises_1 = tslib_1.__importDefault(require("fs/promises"));
|
|
|
7
7
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
8
8
|
const get_calling_filename_js_1 = require("./utils/get-calling-filename.js");
|
|
9
9
|
function isSqlScriptMigrationTask(x) {
|
|
10
|
-
return typeof x === 'object' &&
|
|
10
|
+
return typeof x === 'object' &&
|
|
11
|
+
(typeof x.script === 'string' || typeof x.script === 'function');
|
|
11
12
|
}
|
|
12
13
|
exports.isSqlScriptMigrationTask = isSqlScriptMigrationTask;
|
|
13
14
|
function isInsertDataMigrationTask(x) {
|
|
@@ -24,13 +25,14 @@ exports.isCustomMigrationTask = isCustomMigrationTask;
|
|
|
24
25
|
var MigrationPackage;
|
|
25
26
|
(function (MigrationPackage) {
|
|
26
27
|
async function load(asyncConfig) {
|
|
28
|
+
const baseDir = asyncConfig.baseDir || path_1.default.dirname((0, get_calling_filename_js_1.getCallingFilename)(1));
|
|
27
29
|
const out = {
|
|
28
30
|
...asyncConfig,
|
|
31
|
+
baseDir,
|
|
29
32
|
migrations: []
|
|
30
33
|
};
|
|
31
34
|
if (!Array.isArray(asyncConfig.migrations))
|
|
32
35
|
throw new TypeError('You must provide array of MigrationConfig in "migrations" property');
|
|
33
|
-
const baseDir = path_1.default.dirname((0, get_calling_filename_js_1.getCallingFilename)(1));
|
|
34
36
|
if (asyncConfig.migrations?.length) {
|
|
35
37
|
const srcMigrations = [];
|
|
36
38
|
const trgMigrations = [];
|
|
@@ -41,12 +43,12 @@ var MigrationPackage;
|
|
|
41
43
|
if (typeof x === 'object' && x.tasks)
|
|
42
44
|
srcMigrations.push(x);
|
|
43
45
|
else if (typeof x === 'string') {
|
|
44
|
-
srcMigrations.push(...await loadMigrations(
|
|
46
|
+
srcMigrations.push(...await loadMigrations(baseDir, x.replace(/\\/g, '/')));
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
srcMigrations.sort((a, b) => a.version - b.version);
|
|
48
50
|
for (const migration of srcMigrations) {
|
|
49
|
-
const trgMigration = { ...migration, tasks: [] };
|
|
51
|
+
const trgMigration = { baseDir: '', ...migration, tasks: [] };
|
|
50
52
|
trgMigrations.push(trgMigration);
|
|
51
53
|
const srcTasks = migration.tasks;
|
|
52
54
|
trgMigration.tasks = [];
|
|
@@ -56,7 +58,7 @@ var MigrationPackage;
|
|
|
56
58
|
}
|
|
57
59
|
else if (typeof t === 'string') {
|
|
58
60
|
let pattern = t.replace(/\\/g, '/');
|
|
59
|
-
pattern = path_1.default.resolve(
|
|
61
|
+
pattern = path_1.default.resolve(path_1.default.join(baseDir, trgMigration.baseDir, pattern));
|
|
60
62
|
const files = await (0, fast_glob_1.default)(pattern, {
|
|
61
63
|
absolute: true,
|
|
62
64
|
onlyFiles: true
|
|
@@ -69,16 +71,20 @@ var MigrationPackage;
|
|
|
69
71
|
if (ext === '.sql') {
|
|
70
72
|
const script = await promises_1.default.readFile(filename, 'utf-8');
|
|
71
73
|
trgMigration.tasks.push({
|
|
72
|
-
title: path_1.default.basename(filename),
|
|
74
|
+
title: path_1.default.basename(filename, ext),
|
|
73
75
|
filename,
|
|
74
76
|
script
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
|
-
else if (
|
|
79
|
+
else if (['.json', '.js', '.ts', '.cjs', '.mjs'].includes(ext)) {
|
|
78
80
|
try {
|
|
79
|
-
|
|
81
|
+
let json = ext === '.json'
|
|
82
|
+
? JSON.parse(await promises_1.default.readFile(filename, 'utf-8'))
|
|
83
|
+
: await Promise.resolve(`${filename}`).then(s => tslib_1.__importStar(require(s)));
|
|
80
84
|
if (typeof json !== 'object')
|
|
81
85
|
continue;
|
|
86
|
+
if (json.__esModule)
|
|
87
|
+
json = json.default;
|
|
82
88
|
if (json.script) {
|
|
83
89
|
json.title = json.title || 'Run sql script';
|
|
84
90
|
json.filename = filename;
|
|
@@ -110,9 +116,9 @@ var MigrationPackage;
|
|
|
110
116
|
return out;
|
|
111
117
|
}
|
|
112
118
|
MigrationPackage.load = load;
|
|
113
|
-
async function loadMigrations(pattern) {
|
|
119
|
+
async function loadMigrations(baseDir, pattern) {
|
|
114
120
|
const out = [];
|
|
115
|
-
const files = await (0, fast_glob_1.default)(pattern, { absolute: true, onlyFiles: true });
|
|
121
|
+
const files = await (0, fast_glob_1.default)(path_1.default.join(baseDir, pattern), { absolute: true, onlyFiles: true });
|
|
116
122
|
for (const filename of files) {
|
|
117
123
|
const ext = path_1.default.extname(filename).toLowerCase();
|
|
118
124
|
if (path_1.default.basename(filename, ext) !== 'migration')
|
|
@@ -133,7 +139,7 @@ var MigrationPackage;
|
|
|
133
139
|
}
|
|
134
140
|
}
|
|
135
141
|
if (json && typeof json === 'object' && json.version && Array.isArray(json.tasks)) {
|
|
136
|
-
json.
|
|
142
|
+
json.baseDir = path_1.default.relative(baseDir, path_1.default.dirname(filename));
|
|
137
143
|
out.push(json);
|
|
138
144
|
}
|
|
139
145
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'path';
|
|
1
2
|
import { stringifyValueForSQL } from 'postgresql-client';
|
|
2
3
|
import { PgAdapter } from '@sqb/postgres';
|
|
3
4
|
import { MigrationAdapter } from '../migration-adapter.js';
|
|
@@ -8,7 +9,6 @@ export class PgMigrationAdapter extends MigrationAdapter {
|
|
|
8
9
|
constructor() {
|
|
9
10
|
super(...arguments);
|
|
10
11
|
this._infoSchema = 'public';
|
|
11
|
-
this._packageName = '';
|
|
12
12
|
this._version = 0;
|
|
13
13
|
this._status = MigrationStatus.idle;
|
|
14
14
|
this.defaultVariables = {
|
|
@@ -20,7 +20,7 @@ export class PgMigrationAdapter extends MigrationAdapter {
|
|
|
20
20
|
this.eventTable = 'migration_events';
|
|
21
21
|
}
|
|
22
22
|
get packageName() {
|
|
23
|
-
return this.
|
|
23
|
+
return this._migrationPackage.name;
|
|
24
24
|
}
|
|
25
25
|
get version() {
|
|
26
26
|
return this._version;
|
|
@@ -43,7 +43,7 @@ export class PgMigrationAdapter extends MigrationAdapter {
|
|
|
43
43
|
try {
|
|
44
44
|
const adapter = new PgMigrationAdapter();
|
|
45
45
|
adapter._connection = connection;
|
|
46
|
-
adapter.
|
|
46
|
+
adapter._migrationPackage = options.migrationPackage;
|
|
47
47
|
adapter._infoSchema = options.infoSchema || '__migration';
|
|
48
48
|
adapter.defaultVariables.schema = options.connection.schema || '';
|
|
49
49
|
if (!adapter.defaultVariables.schema) {
|
|
@@ -72,7 +72,9 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
72
72
|
version integer not null default 0,
|
|
73
73
|
event varchar(16) not null,
|
|
74
74
|
event_time timestamp without time zone not null,
|
|
75
|
+
title text,
|
|
75
76
|
message text not null,
|
|
77
|
+
filename text,
|
|
76
78
|
details text,
|
|
77
79
|
CONSTRAINT pk_${adapter.eventTable} PRIMARY KEY (id)
|
|
78
80
|
)`);
|
|
@@ -125,30 +127,37 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
125
127
|
}
|
|
126
128
|
async writeEvent(event) {
|
|
127
129
|
const sql = `insert into ${this.eventTableFull} ` +
|
|
128
|
-
'(package_name, version, event, event_time, message, details) ' +
|
|
129
|
-
'values ($1, $2, $3, CURRENT_TIMESTAMP, $4, $5)';
|
|
130
|
+
'(package_name, version, event, event_time, title, message, filename, details) ' +
|
|
131
|
+
'values ($1, $2, $3, CURRENT_TIMESTAMP, $4, $5, $6, $7)';
|
|
130
132
|
await this._connection.query(sql, {
|
|
131
133
|
params: [
|
|
132
134
|
this.packageName, event.version, event.event,
|
|
133
|
-
event.message, event.details
|
|
135
|
+
event.title, event.message, event.filename, event.details
|
|
134
136
|
]
|
|
135
137
|
});
|
|
136
138
|
}
|
|
137
|
-
async executeTask(task, variables) {
|
|
139
|
+
async executeTask(migrationPackage, migration, task, variables) {
|
|
138
140
|
variables = {
|
|
139
141
|
...this.defaultVariables,
|
|
140
142
|
...variables
|
|
141
143
|
};
|
|
142
144
|
if (isSqlScriptMigrationTask(task)) {
|
|
143
145
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
let script;
|
|
147
|
+
if (typeof task.script === 'function') {
|
|
148
|
+
script = await task.script({ migrationPackage, migration, task, variables });
|
|
149
|
+
}
|
|
150
|
+
else
|
|
151
|
+
script = task.script;
|
|
152
|
+
if (typeof script !== 'string')
|
|
153
|
+
return;
|
|
154
|
+
script = this.replaceVariables(script, variables);
|
|
146
155
|
await this._connection.execute(script);
|
|
147
156
|
}
|
|
148
157
|
catch (e) {
|
|
149
158
|
let msg = `Error in task "${task.title}"`;
|
|
150
159
|
if (task.filename)
|
|
151
|
-
msg += '\n at ' + task.filename;
|
|
160
|
+
msg += '\n at ' + path.relative(migrationPackage.baseDir, task.filename);
|
|
152
161
|
if (e.lineNr) {
|
|
153
162
|
if (!task.filename)
|
|
154
163
|
e.message += '\n at';
|
|
@@ -166,8 +175,9 @@ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
|
|
|
166
175
|
return;
|
|
167
176
|
}
|
|
168
177
|
if (isInsertDataMigrationTask(task)) {
|
|
178
|
+
const tableName = this.replaceVariables(task.tableName, variables);
|
|
169
179
|
const script = task.rows
|
|
170
|
-
.map(row => this.rowToSql(
|
|
180
|
+
.map(row => this.rowToSql(tableName, row))
|
|
171
181
|
.join('\n');
|
|
172
182
|
await this._connection.execute(script);
|
|
173
183
|
}
|
package/esm/db-migrator.js
CHANGED
|
@@ -22,7 +22,7 @@ export class DbMigrator extends AsyncEventEmitter {
|
|
|
22
22
|
let migrationAdapter;
|
|
23
23
|
switch (options.connection.dialect) {
|
|
24
24
|
case 'postgres': {
|
|
25
|
-
migrationAdapter = await PgMigrationAdapter.create(options);
|
|
25
|
+
migrationAdapter = await PgMigrationAdapter.create({ ...options, migrationPackage });
|
|
26
26
|
break;
|
|
27
27
|
}
|
|
28
28
|
default:
|
|
@@ -63,23 +63,29 @@ export class DbMigrator extends AsyncEventEmitter {
|
|
|
63
63
|
await migrationAdapter.writeEvent({
|
|
64
64
|
event: MigrationAdapter.EventKind.started,
|
|
65
65
|
version: migration.version,
|
|
66
|
+
title: task.title,
|
|
67
|
+
filename: task.filename,
|
|
66
68
|
message: `Task "${task.title}" started`
|
|
67
69
|
});
|
|
68
70
|
try {
|
|
69
|
-
await migrationAdapter.executeTask(task, {
|
|
71
|
+
await migrationAdapter.executeTask(migrationPackage, migration, task, {
|
|
70
72
|
schema: options.connection.schema,
|
|
71
73
|
...options.scriptVariables,
|
|
72
74
|
});
|
|
73
75
|
await migrationAdapter.writeEvent({
|
|
74
76
|
event: MigrationAdapter.EventKind.success,
|
|
75
77
|
version: migration.version,
|
|
76
|
-
|
|
78
|
+
title: task.title,
|
|
79
|
+
filename: task.filename,
|
|
80
|
+
message: `Task "${task.title}" completed`,
|
|
77
81
|
});
|
|
78
82
|
}
|
|
79
83
|
catch (e) {
|
|
80
84
|
await migrationAdapter.writeEvent({
|
|
81
85
|
event: MigrationAdapter.EventKind.error,
|
|
82
86
|
version: migration.version,
|
|
87
|
+
title: task.title,
|
|
88
|
+
filename: task.filename,
|
|
83
89
|
message: String(e),
|
|
84
90
|
details: e.message + '\n\n' +
|
|
85
91
|
Object.keys(e)
|
package/esm/migration-adapter.js
CHANGED
package/esm/migration-package.js
CHANGED
|
@@ -3,7 +3,8 @@ import fs from 'fs/promises';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { getCallingFilename } from './utils/get-calling-filename.js';
|
|
5
5
|
export function isSqlScriptMigrationTask(x) {
|
|
6
|
-
return typeof x === 'object' &&
|
|
6
|
+
return typeof x === 'object' &&
|
|
7
|
+
(typeof x.script === 'string' || typeof x.script === 'function');
|
|
7
8
|
}
|
|
8
9
|
export function isInsertDataMigrationTask(x) {
|
|
9
10
|
return typeof x === 'object' &&
|
|
@@ -17,13 +18,14 @@ export function isCustomMigrationTask(x) {
|
|
|
17
18
|
export var MigrationPackage;
|
|
18
19
|
(function (MigrationPackage) {
|
|
19
20
|
async function load(asyncConfig) {
|
|
21
|
+
const baseDir = asyncConfig.baseDir || path.dirname(getCallingFilename(1));
|
|
20
22
|
const out = {
|
|
21
23
|
...asyncConfig,
|
|
24
|
+
baseDir,
|
|
22
25
|
migrations: []
|
|
23
26
|
};
|
|
24
27
|
if (!Array.isArray(asyncConfig.migrations))
|
|
25
28
|
throw new TypeError('You must provide array of MigrationConfig in "migrations" property');
|
|
26
|
-
const baseDir = path.dirname(getCallingFilename(1));
|
|
27
29
|
if (asyncConfig.migrations?.length) {
|
|
28
30
|
const srcMigrations = [];
|
|
29
31
|
const trgMigrations = [];
|
|
@@ -34,12 +36,12 @@ export var MigrationPackage;
|
|
|
34
36
|
if (typeof x === 'object' && x.tasks)
|
|
35
37
|
srcMigrations.push(x);
|
|
36
38
|
else if (typeof x === 'string') {
|
|
37
|
-
srcMigrations.push(...await loadMigrations(
|
|
39
|
+
srcMigrations.push(...await loadMigrations(baseDir, x.replace(/\\/g, '/')));
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
srcMigrations.sort((a, b) => a.version - b.version);
|
|
41
43
|
for (const migration of srcMigrations) {
|
|
42
|
-
const trgMigration = { ...migration, tasks: [] };
|
|
44
|
+
const trgMigration = { baseDir: '', ...migration, tasks: [] };
|
|
43
45
|
trgMigrations.push(trgMigration);
|
|
44
46
|
const srcTasks = migration.tasks;
|
|
45
47
|
trgMigration.tasks = [];
|
|
@@ -49,7 +51,7 @@ export var MigrationPackage;
|
|
|
49
51
|
}
|
|
50
52
|
else if (typeof t === 'string') {
|
|
51
53
|
let pattern = t.replace(/\\/g, '/');
|
|
52
|
-
pattern = path.resolve(
|
|
54
|
+
pattern = path.resolve(path.join(baseDir, trgMigration.baseDir, pattern));
|
|
53
55
|
const files = await glob(pattern, {
|
|
54
56
|
absolute: true,
|
|
55
57
|
onlyFiles: true
|
|
@@ -62,16 +64,20 @@ export var MigrationPackage;
|
|
|
62
64
|
if (ext === '.sql') {
|
|
63
65
|
const script = await fs.readFile(filename, 'utf-8');
|
|
64
66
|
trgMigration.tasks.push({
|
|
65
|
-
title: path.basename(filename),
|
|
67
|
+
title: path.basename(filename, ext),
|
|
66
68
|
filename,
|
|
67
69
|
script
|
|
68
70
|
});
|
|
69
71
|
}
|
|
70
|
-
else if (
|
|
72
|
+
else if (['.json', '.js', '.ts', '.cjs', '.mjs'].includes(ext)) {
|
|
71
73
|
try {
|
|
72
|
-
|
|
74
|
+
let json = ext === '.json'
|
|
75
|
+
? JSON.parse(await fs.readFile(filename, 'utf-8'))
|
|
76
|
+
: await import(filename);
|
|
73
77
|
if (typeof json !== 'object')
|
|
74
78
|
continue;
|
|
79
|
+
if (json.__esModule)
|
|
80
|
+
json = json.default;
|
|
75
81
|
if (json.script) {
|
|
76
82
|
json.title = json.title || 'Run sql script';
|
|
77
83
|
json.filename = filename;
|
|
@@ -103,9 +109,9 @@ export var MigrationPackage;
|
|
|
103
109
|
return out;
|
|
104
110
|
}
|
|
105
111
|
MigrationPackage.load = load;
|
|
106
|
-
async function loadMigrations(pattern) {
|
|
112
|
+
async function loadMigrations(baseDir, pattern) {
|
|
107
113
|
const out = [];
|
|
108
|
-
const files = await glob(pattern, { absolute: true, onlyFiles: true });
|
|
114
|
+
const files = await glob(path.join(baseDir, pattern), { absolute: true, onlyFiles: true });
|
|
109
115
|
for (const filename of files) {
|
|
110
116
|
const ext = path.extname(filename).toLowerCase();
|
|
111
117
|
if (path.basename(filename, ext) !== 'migration')
|
|
@@ -126,7 +132,7 @@ export var MigrationPackage;
|
|
|
126
132
|
}
|
|
127
133
|
}
|
|
128
134
|
if (json && typeof json === 'object' && json.version && Array.isArray(json.tasks)) {
|
|
129
|
-
json.
|
|
135
|
+
json.baseDir = path.relative(baseDir, path.dirname(filename));
|
|
130
136
|
out.push(json);
|
|
131
137
|
}
|
|
132
138
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sqb/migrator",
|
|
3
3
|
"description": "Database migrator for SQB",
|
|
4
|
-
"version": "4.10.
|
|
4
|
+
"version": "4.10.4",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Eray Hanoglu <e.hanoglu@panates.com>",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"ts-gems": "^2.5.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@sqb/builder": "^4.10.
|
|
40
|
-
"@sqb/connect": "^4.10.
|
|
41
|
-
"@sqb/postgres": "^4.10.
|
|
39
|
+
"@sqb/builder": "^4.10.4",
|
|
40
|
+
"@sqb/connect": "^4.10.4",
|
|
41
|
+
"@sqb/postgres": "^4.10.4"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=16.0",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Connection } from 'postgresql-client';
|
|
2
|
+
import { StrictOmit } from 'ts-gems';
|
|
2
3
|
import type { DbMigratorOptions } from '../db-migrator.js';
|
|
3
4
|
import { MigrationAdapter } from '../migration-adapter.js';
|
|
4
|
-
import { MigrationTask } from '../migration-package.js';
|
|
5
|
+
import { Migration, MigrationPackage, MigrationTask } from '../migration-package.js';
|
|
5
6
|
import { MigrationStatus } from '../types.js';
|
|
6
7
|
export declare class PgMigrationAdapter extends MigrationAdapter {
|
|
7
8
|
protected _connection: Connection;
|
|
8
9
|
protected _infoSchema: string;
|
|
9
|
-
protected
|
|
10
|
+
protected _migrationPackage: MigrationPackage;
|
|
10
11
|
protected _version: number;
|
|
11
12
|
protected _status: MigrationStatus;
|
|
12
13
|
protected defaultVariables: {
|
|
@@ -22,7 +23,9 @@ export declare class PgMigrationAdapter extends MigrationAdapter {
|
|
|
22
23
|
get infoSchema(): string;
|
|
23
24
|
get summaryTableFull(): string;
|
|
24
25
|
get eventTableFull(): string;
|
|
25
|
-
static create(options: DbMigratorOptions
|
|
26
|
+
static create(options: StrictOmit<DbMigratorOptions, 'migrationPackage'> & {
|
|
27
|
+
migrationPackage: MigrationPackage;
|
|
28
|
+
}): Promise<PgMigrationAdapter>;
|
|
26
29
|
close(): Promise<void>;
|
|
27
30
|
refresh(): Promise<void>;
|
|
28
31
|
update(info: {
|
|
@@ -30,7 +33,7 @@ export declare class PgMigrationAdapter extends MigrationAdapter {
|
|
|
30
33
|
version?: number;
|
|
31
34
|
}): Promise<void>;
|
|
32
35
|
writeEvent(event: MigrationAdapter.Event): Promise<void>;
|
|
33
|
-
executeTask(task: MigrationTask, variables: Record<string, any>): Promise<void>;
|
|
36
|
+
executeTask(migrationPackage: MigrationPackage, migration: Migration, task: MigrationTask, variables: Record<string, any>): Promise<void>;
|
|
34
37
|
backupDatabase(): Promise<void>;
|
|
35
38
|
lockSchema(): Promise<void>;
|
|
36
39
|
restoreDatabase(): Promise<void>;
|
package/types/db-migrator.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AsyncEventEmitter } from 'strict-typed-events';
|
|
2
2
|
import { ClientConfiguration } from '@sqb/connect';
|
|
3
3
|
import { MigrationAdapter } from './migration-adapter.js';
|
|
4
|
-
import { MigrationPackage,
|
|
4
|
+
import { MigrationPackage, MigrationPackageConfig } from './migration-package.js';
|
|
5
5
|
export interface DbMigratorOptions {
|
|
6
6
|
connection: ClientConfiguration;
|
|
7
|
-
migrationPackage: MigrationPackage |
|
|
7
|
+
migrationPackage: MigrationPackage | MigrationPackageConfig;
|
|
8
8
|
infoSchema?: string;
|
|
9
9
|
scriptVariables?: Record<string, string>;
|
|
10
10
|
targetVersion?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { MigrationTask } from './migration-package.js';
|
|
2
|
-
import { MigrationStatus } from './types.js';
|
|
1
|
+
import type { Migration, MigrationPackage, MigrationTask } from './migration-package.js';
|
|
2
|
+
import type { MigrationStatus } from './types.js';
|
|
3
3
|
export declare abstract class MigrationAdapter {
|
|
4
4
|
abstract readonly packageName: string;
|
|
5
5
|
abstract readonly status: MigrationStatus;
|
|
@@ -11,11 +11,12 @@ export declare abstract class MigrationAdapter {
|
|
|
11
11
|
version?: number;
|
|
12
12
|
}): Promise<void>;
|
|
13
13
|
abstract writeEvent(event: MigrationAdapter.Event): Promise<void>;
|
|
14
|
-
abstract executeTask(task: MigrationTask, variables: Record<string, any>): Promise<void>;
|
|
14
|
+
abstract executeTask(migrationPackage: MigrationPackage, migration: Migration, task: MigrationTask, variables: Record<string, any>): Promise<void>;
|
|
15
15
|
abstract lockSchema(): Promise<void>;
|
|
16
16
|
abstract unlockSchema(): Promise<void>;
|
|
17
17
|
abstract backupDatabase(): Promise<void>;
|
|
18
18
|
abstract restoreDatabase(): Promise<void>;
|
|
19
|
+
protected replaceVariables(text: string, variables: Record<string, string>): string;
|
|
19
20
|
}
|
|
20
21
|
export declare namespace MigrationAdapter {
|
|
21
22
|
enum EventKind {
|
|
@@ -27,6 +28,8 @@ export declare namespace MigrationAdapter {
|
|
|
27
28
|
event: EventKind;
|
|
28
29
|
version: number;
|
|
29
30
|
message: string;
|
|
31
|
+
title?: string;
|
|
32
|
+
filename?: string;
|
|
30
33
|
details?: string;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -1,44 +1,42 @@
|
|
|
1
|
-
import { StrictOmit } from 'ts-gems';
|
|
1
|
+
import { PartialSome, StrictOmit } from 'ts-gems';
|
|
2
2
|
import type { MigrationAdapter } from './migration-adapter.js';
|
|
3
3
|
export interface MigrationPackage {
|
|
4
4
|
name: string;
|
|
5
5
|
description?: string;
|
|
6
6
|
migrations: Migration[];
|
|
7
|
+
baseDir: string;
|
|
7
8
|
informationTableName?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface Migration {
|
|
10
11
|
version: number;
|
|
11
12
|
tasks: MigrationTask[];
|
|
12
|
-
|
|
13
|
+
baseDir: string;
|
|
13
14
|
backup?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export type MigrationTask = SqlScriptMigrationTask | CustomMigrationTask | InsertDataMigrationTask;
|
|
16
17
|
export interface BaseMigrationTask {
|
|
17
|
-
title
|
|
18
|
+
title?: string;
|
|
18
19
|
filename?: string;
|
|
19
20
|
}
|
|
20
21
|
export interface SqlScriptMigrationTask extends BaseMigrationTask {
|
|
21
|
-
|
|
22
|
-
script: string;
|
|
22
|
+
script: string | Function;
|
|
23
23
|
}
|
|
24
24
|
export interface InsertDataMigrationTask extends BaseMigrationTask {
|
|
25
|
-
title: string;
|
|
26
25
|
tableName: string;
|
|
27
26
|
rows: Record<string, any>[];
|
|
28
27
|
}
|
|
29
28
|
export interface CustomMigrationTask extends BaseMigrationTask {
|
|
30
|
-
title: string;
|
|
31
29
|
fn: (connection: any, adapter: MigrationAdapter) => void | Promise<void>;
|
|
32
30
|
}
|
|
33
31
|
export declare function isSqlScriptMigrationTask(x: any): x is SqlScriptMigrationTask;
|
|
34
32
|
export declare function isInsertDataMigrationTask(x: any): x is InsertDataMigrationTask;
|
|
35
33
|
export declare function isCustomMigrationTask(x: any): x is CustomMigrationTask;
|
|
36
|
-
export interface
|
|
37
|
-
migrations: (string |
|
|
34
|
+
export interface MigrationPackageConfig extends PartialSome<StrictOmit<MigrationPackage, 'migrations'>, 'baseDir'> {
|
|
35
|
+
migrations: (string | MigrationConfig | (() => MigrationConfig) | (() => Promise<MigrationConfig>))[];
|
|
38
36
|
}
|
|
39
|
-
export interface
|
|
37
|
+
export interface MigrationConfig extends StrictOmit<Migration, 'tasks' | 'baseDir'> {
|
|
40
38
|
tasks: (string | MigrationTask | (() => MigrationTask) | (() => Promise<MigrationTask>))[];
|
|
41
39
|
}
|
|
42
40
|
export declare namespace MigrationPackage {
|
|
43
|
-
function load(asyncConfig:
|
|
41
|
+
function load(asyncConfig: MigrationPackageConfig): Promise<MigrationPackage>;
|
|
44
42
|
}
|