@sqb/migrator 4.9.0 → 4.10.0

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.
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PgMigrationAdapter = void 0;
4
+ const postgresql_client_1 = require("postgresql-client");
5
+ const postgres_1 = require("@sqb/postgres");
6
+ const migration_adapter_js_1 = require("../migration-adapter.js");
7
+ const migration_package_js_1 = require("../migration-package.js");
8
+ const types_js_1 = require("../types.js");
9
+ const pgAdapter = new postgres_1.PgAdapter();
10
+ class PgMigrationAdapter extends migration_adapter_js_1.MigrationAdapter {
11
+ constructor() {
12
+ super(...arguments);
13
+ this._infoSchema = 'public';
14
+ this._packageName = '';
15
+ this._version = 0;
16
+ this._status = types_js_1.MigrationStatus.idle;
17
+ this.defaultVariables = {
18
+ tablespace: 'pg_default',
19
+ schema: 'public',
20
+ owner: 'postgres'
21
+ };
22
+ this.summaryTable = 'migration_summary';
23
+ this.eventTable = 'migration_events';
24
+ }
25
+ get packageName() {
26
+ return this._packageName;
27
+ }
28
+ get version() {
29
+ return this._version;
30
+ }
31
+ get status() {
32
+ return this._status;
33
+ }
34
+ get infoSchema() {
35
+ return this._infoSchema;
36
+ }
37
+ get summaryTableFull() {
38
+ return this.infoSchema + '.' + this.summaryTable;
39
+ }
40
+ get eventTableFull() {
41
+ return this.infoSchema + '.' + this.eventTable;
42
+ }
43
+ static async create(options) {
44
+ // Create connection
45
+ const connection = (await pgAdapter.connect(options.connection)).intlcon;
46
+ try {
47
+ const adapter = new PgMigrationAdapter();
48
+ adapter._connection = connection;
49
+ adapter._infoSchema = options.infoSchema || '__migration';
50
+ adapter.defaultVariables.schema = options.connection.schema || '';
51
+ if (!adapter.defaultVariables.schema) {
52
+ const r = await connection.query('SELECT CURRENT_SCHEMA ', { objectRows: true });
53
+ adapter.defaultVariables.schema = (r.rows?.[0]?.current_schema) || 'public';
54
+ }
55
+ // Check if migration schema
56
+ await connection.query(`CREATE SCHEMA IF NOT EXISTS ${adapter.infoSchema} AUTHORIZATION postgres;`);
57
+ // Create summary table if not exists
58
+ await connection.execute(`
59
+ CREATE TABLE IF NOT EXISTS ${adapter.summaryTableFull}
60
+ (
61
+ package_name varchar not null,
62
+ status varchar(16) not null,
63
+ current_version integer not null default 0,
64
+ created_at timestamp without time zone not null default current_timestamp,
65
+ updated_at timestamp without time zone,
66
+ CONSTRAINT pk_${adapter.summaryTable} PRIMARY KEY (package_name)
67
+ )`);
68
+ // Create events table if not exists
69
+ await connection.execute(`
70
+ CREATE TABLE IF NOT EXISTS ${adapter.eventTableFull}
71
+ (
72
+ id serial not null,
73
+ package_name varchar not null,
74
+ version integer not null default 0,
75
+ event varchar(16) not null,
76
+ event_time timestamp without time zone not null,
77
+ message text not null,
78
+ details text,
79
+ CONSTRAINT pk_${adapter.eventTable} PRIMARY KEY (id)
80
+ )`);
81
+ // Insert summary record if not exists
82
+ const r = await connection.query(`SELECT status FROM ${adapter.summaryTableFull} WHERE package_name = $1`, { params: [adapter.packageName], objectRows: true });
83
+ if (!(r && r.rows?.length)) {
84
+ await connection.query(`insert into ${adapter.summaryTableFull} ` +
85
+ '(package_name, status) values ($1, $2)', { params: [adapter.packageName, types_js_1.MigrationStatus.idle] });
86
+ }
87
+ await adapter.refresh();
88
+ return adapter;
89
+ }
90
+ catch (e) {
91
+ await connection.close(0);
92
+ throw e;
93
+ }
94
+ }
95
+ async close() {
96
+ await this._connection.close();
97
+ }
98
+ async refresh() {
99
+ const r = await this._connection.query(`SELECT * FROM ${this.summaryTableFull} WHERE package_name = $1`, { params: [this.packageName], objectRows: true });
100
+ const row = r.rows && r.rows[0];
101
+ if (!row)
102
+ throw new Error('Summary record did not created');
103
+ this._version = row.current_version;
104
+ this._status = row.status;
105
+ }
106
+ async update(info) {
107
+ let sql = '';
108
+ const params = [];
109
+ if (info.status && info.status !== this.status) {
110
+ params.push(info.status);
111
+ sql += ', status = $' + (params.length);
112
+ }
113
+ if (info.version && info.version !== this.version) {
114
+ params.push(info.version);
115
+ sql += ', current_version = $' + (params.length);
116
+ }
117
+ if (sql) {
118
+ sql = `update ${this.summaryTableFull} set updated_at = current_timestamp` + sql;
119
+ await this._connection.query(sql, { params });
120
+ if (info.status)
121
+ this._status = info.status;
122
+ if (info.version)
123
+ this._version = info.version;
124
+ }
125
+ }
126
+ async writeEvent(event) {
127
+ 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
+ await this._connection.query(sql, {
131
+ params: [
132
+ this.packageName, event.version, event.event,
133
+ event.message, event.details
134
+ ]
135
+ });
136
+ }
137
+ async executeTask(task, variables) {
138
+ variables = {
139
+ ...this.defaultVariables,
140
+ ...variables
141
+ };
142
+ if ((0, migration_package_js_1.isSqlScriptMigrationTask)(task)) {
143
+ try {
144
+ const script = task.script
145
+ .replace(/(\${(\w+)})/g, (s, ...args) => variables[args[1]] || s);
146
+ await this._connection.execute(script);
147
+ }
148
+ catch (e) {
149
+ let msg = `Error in task "${task.title}"`;
150
+ if (task.filename)
151
+ msg += '\n at ' + task.filename;
152
+ if (e.lineNr) {
153
+ if (!task.filename)
154
+ e.message += '\n at';
155
+ msg += ` (${e.lineNr},${e.colNr}):\n` + e.line;
156
+ if (e.colNr)
157
+ msg += '\n' + ' '.repeat(e.colNr - 1) + '^';
158
+ }
159
+ e.message = msg + '\n\n' + e.message;
160
+ throw e;
161
+ }
162
+ return;
163
+ }
164
+ if ((0, migration_package_js_1.isCustomMigrationTask)(task)) {
165
+ await task.fn(this._connection, this);
166
+ return;
167
+ }
168
+ if ((0, migration_package_js_1.isInsertDataMigrationTask)(task)) {
169
+ const script = task.rows
170
+ .map(row => this.rowToSql(variables.schema + '.' + task.tableName, row))
171
+ .join('\n');
172
+ await this._connection.execute(script);
173
+ }
174
+ }
175
+ backupDatabase() {
176
+ return Promise.resolve(undefined);
177
+ }
178
+ lockSchema() {
179
+ return Promise.resolve(undefined);
180
+ }
181
+ restoreDatabase() {
182
+ return Promise.resolve(undefined);
183
+ }
184
+ unlockSchema() {
185
+ return Promise.resolve(undefined);
186
+ }
187
+ rowToSql(tableName, row) {
188
+ let sql = '';
189
+ const keys = Object.keys(row);
190
+ sql += `insert into ${tableName} (${keys}) values (`;
191
+ for (let i = 0; i < keys.length; i++) {
192
+ sql += (i ? ', ' : '') + (0, postgresql_client_1.stringifyValueForSQL)(row[keys[i]]);
193
+ }
194
+ sql += ');\n';
195
+ return sql;
196
+ }
197
+ }
198
+ exports.PgMigrationAdapter = PgMigrationAdapter;
@@ -1,215 +1,108 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DbMigrator = void 0;
4
- const tslib_1 = require("tslib");
5
- const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
6
- const node_path_1 = tslib_1.__importDefault(require("node:path"));
7
- const postgresql_client_1 = require("postgresql-client");
8
- const load_task_files_js_1 = require("./load-task-files.js");
9
- const ignoreEventListener = () => 0;
10
- class DbMigrator {
4
+ const strict_typed_events_1 = require("strict-typed-events");
5
+ const pg_migration_adapter_js_1 = require("./adapters/pg-migration-adapter.js");
6
+ const migration_adapter_js_1 = require("./migration-adapter.js");
7
+ const migration_package_js_1 = require("./migration-package.js");
8
+ const types_js_1 = require("./types.js");
9
+ class DbMigrator extends strict_typed_events_1.AsyncEventEmitter {
11
10
  async execute(options) {
12
- const { connection, schema } = options;
13
- const migrationPackage = await DbMigrator.loadMigrationPackage(options.migrationPackage);
14
- const targetVersion = Math.min(options.targetVersion || Number.MAX_SAFE_INTEGER, migrationPackage.maxVersion);
15
- if (targetVersion && targetVersion < migrationPackage.minVersion)
11
+ if (!options.connection.dialect)
12
+ throw new TypeError(`You must provide connection.dialect`);
13
+ const migrationPackage = await migration_package_js_1.MigrationPackage.load(options.migrationPackage);
14
+ let minVersion = migrationPackage.migrations
15
+ .reduce((a, m) => Math.min(a, m.version), Number.MAX_SAFE_INTEGER);
16
+ if (minVersion === Number.MAX_SAFE_INTEGER)
17
+ minVersion = 0;
18
+ const maxVersion = migrationPackage.migrations
19
+ .reduce((a, m) => Math.max(a, m.version), 0);
20
+ const targetVersion = Math.min(options?.targetVersion || Number.MAX_SAFE_INTEGER, maxVersion);
21
+ if (targetVersion && targetVersion < minVersion) { // noinspection ExceptionCaughtLocallyJS
16
22
  throw new Error(`Version mismatch. Target schema version (${targetVersion}) is lower than ` +
17
- `migration package min version (${migrationPackage.minVersion})`);
18
- const emit = options.eventListener || ignoreEventListener;
19
- const schemaInfo = await this._getSchemaInfo(options);
20
- if (schemaInfo.version && schemaInfo.version < migrationPackage.minVersion - 1)
21
- throw new Error(`This package can migrate starting from ${migrationPackage.minVersion - 1} but current version is ${schemaInfo.version}`);
22
- const { migrations } = migrationPackage;
23
- // calculate total scripts;
24
- const total = migrations
25
- .reduce((i, x) => i + x.tasks.length, 0);
26
- const needBackup = !!migrations.find(x => !!x.backup);
27
- emit('start');
28
- let task;
23
+ `migration package min version (${minVersion})`);
24
+ }
25
+ let migrationAdapter;
26
+ switch (options.connection.dialect) {
27
+ case 'postgres': {
28
+ migrationAdapter = await pg_migration_adapter_js_1.PgMigrationAdapter.create(options);
29
+ break;
30
+ }
31
+ default:
32
+ throw new TypeError(`Migration adapter for "${options.connection.dialect}" dialect is not implemented yet`);
33
+ }
34
+ let needBackup = false;
29
35
  try {
30
- await this._lockSchema();
36
+ if (migrationAdapter.version && migrationAdapter.version < minVersion - 1) { // noinspection ExceptionCaughtLocallyJS
37
+ throw new Error(`This package can migrate starting from ${minVersion - 1} but current version is ${migrationAdapter.version}`);
38
+ }
39
+ const { migrations } = migrationPackage;
40
+ // calculate total scripts;
41
+ const total = migrations
42
+ .reduce((i, x) => i + x.tasks.length, 0);
43
+ needBackup = !!migrations.find(x => !!x.backup);
44
+ await this.emitAsync('start');
45
+ let task;
46
+ await migrationAdapter.lockSchema();
31
47
  if (needBackup) {
32
- emit('backup');
33
- await this._backup();
48
+ await this.emitAsync('backup');
49
+ await migrationAdapter.backupDatabase();
34
50
  }
35
- await connection.execute(`update ${schema}.${schemaInfo.infTable} set status = 'migration'`);
36
51
  // Execute migration tasks
37
52
  for (const migration of migrations) {
38
- if (migration.version > targetVersion || schemaInfo.version >= migration.version)
53
+ if (migration.version > targetVersion || migrationAdapter.version >= migration.version)
39
54
  continue;
40
55
  for (let index = 0; index < migration.tasks.length; index++) {
41
56
  task = migration.tasks[index];
42
- emit('processing', { task: task.title, total, index });
43
- if ('fn' in task && typeof task.fn === 'function') {
44
- await task.fn(connection);
45
- }
46
- else if (task.script) {
47
- const script = task.script.replace(/(\${(\w+)})/gi, (s, ...args) => {
48
- switch (args[1].toLowerCase()) {
49
- case 'schema':
50
- return schema;
51
- case 'owner':
52
- return schemaInfo.owner;
53
- case 'tablespace':
54
- return schemaInfo.tablespace;
55
- }
56
- return s;
57
+ await this.emitAsync('task-start', { task: task.title, total, index });
58
+ await migrationAdapter.update({ status: types_js_1.MigrationStatus.busy });
59
+ await migrationAdapter.writeEvent({
60
+ event: migration_adapter_js_1.MigrationAdapter.EventKind.started,
61
+ version: migration.version,
62
+ message: `Task "${task.title}" started`
63
+ });
64
+ try {
65
+ await migrationAdapter.executeTask(task, {
66
+ schema: options.connection.schema,
67
+ ...options.scriptVariables,
68
+ });
69
+ await migrationAdapter.writeEvent({
70
+ event: migration_adapter_js_1.MigrationAdapter.EventKind.success,
71
+ version: migration.version,
72
+ message: `Task "${task.title}" completed`
57
73
  });
58
- try {
59
- await connection.execute(script);
60
- }
61
- catch (e) {
62
- e.message += `\n${task.title}`;
63
- if (e.lineNr)
64
- e.message += ` (${e.lineNr},${e.colNr}):\n` + e.line;
65
- if (e.colNr)
66
- e.message += '\n' + ' '.repeat(e.colNr - 1) + '^';
67
- // noinspection ExceptionCaughtLocallyJS
68
- throw e;
69
- }
70
74
  }
71
- else if ('tableName' in task) {
72
- const script = DbMigrator.objectDataToSql({ ...task, schema });
73
- await connection.execute(script);
75
+ catch (e) {
76
+ await migrationAdapter.writeEvent({
77
+ event: migration_adapter_js_1.MigrationAdapter.EventKind.error,
78
+ version: migration.version,
79
+ message: String(e)
80
+ });
81
+ // noinspection ExceptionCaughtLocallyJS
82
+ throw e;
74
83
  }
75
- emit('process', { task: task.title, total, index });
84
+ await this.emitAsync('task-finish', { task: task.title, total, index });
76
85
  }
86
+ await migrationAdapter.update({ version: migration.version });
77
87
  }
78
- await connection.query(`update ${schema}.${schemaInfo.infTable} set status = $1, schema_version = $2, ` +
79
- 'updated_at = current_timestamp', { params: ['ready', targetVersion] });
80
88
  }
81
89
  catch (e) {
82
90
  if (needBackup) {
83
- emit('backup');
84
- await this._restore();
91
+ await this.emitAsync('restore');
92
+ await migrationAdapter.restoreDatabase();
85
93
  }
86
94
  throw e;
87
95
  }
88
96
  finally {
89
- await this._unlockSchema();
90
- }
91
- emit('finish');
92
- return true;
93
- }
94
- static async loadMigrationPackage(pkg) {
95
- const migarr = typeof pkg.migrations === 'function' ? await pkg.migrations() : pkg.migrations;
96
- const migrations = [];
97
- for (const x of migarr) {
98
- if (typeof x === 'string')
99
- await locateMigrations(migrations, x);
100
- else
101
- migrations.push(x);
102
- }
103
- let minVersion = 0;
104
- let maxVersion = 0;
105
- migrations.sort((a, b) => a.version - b.version);
106
- for (const m of migrations) {
107
- minVersion = !minVersion ? m.version : Math.min(minVersion, m.version);
108
- maxVersion = Math.max(minVersion, m.version);
109
- for (const t of m.tasks) {
110
- if (typeof t === 'string') {
111
- m.tasks = (0, load_task_files_js_1.loadTaskFiles)(t);
112
- }
97
+ try {
98
+ await migrationAdapter.unlockSchema();
113
99
  }
114
- }
115
- return {
116
- minVersion,
117
- maxVersion,
118
- migrations
119
- };
120
- }
121
- async _lockSchema() {
122
- // todo
123
- }
124
- async _unlockSchema() {
125
- // todo
126
- }
127
- async _backup() {
128
- // todo
129
- }
130
- async _restore() {
131
- // todo
132
- }
133
- async _getSchemaInfo(options) {
134
- const { connection, schema } = options;
135
- let owner = options.owner || 'postgres';
136
- let tablespace = options.tablespace || 'pg_default';
137
- let version = 0;
138
- let status = '';
139
- let r = await connection.query('select schema_owner FROM information_schema.schemata WHERE schema_name = $1', { params: [schema], objectRows: true });
140
- if (r.rows && r.rows[0]) {
141
- owner = r.rows[0].schema_owner;
142
- }
143
- else {
144
- await connection.execute(`CREATE SCHEMA ${schema} AUTHORIZATION ${owner};`);
145
- }
146
- // Determine tablespace of schema
147
- const infTable = options.migrationPackage.informationTableName || '__schema_info';
148
- r = await connection.query('SELECT tablespace FROM pg_tables WHERE schemaname = $1 AND tablename = $2', { params: [schema, infTable], objectRows: true });
149
- if (r.rows && r.rows[0]) {
150
- tablespace = r.rows[0].tablespace || tablespace;
151
- r = await connection.query(`SELECT schema_version, status FROM ${schema}.${infTable}`, { objectRows: true });
152
- if (r.rows && r.rows[0]) {
153
- version = r.rows[0].schema_version;
154
- status = r.rows[0].status;
155
- }
156
- }
157
- else {
158
- // Create if not exists
159
- await connection.execute(`
160
- CREATE TABLE ${schema}.${infTable}
161
- (
162
- status varchar(16) not null,
163
- schema_version integer not null default 0,
164
- created_at timestamp without time zone not null default current_timestamp,
165
- updated_at timestamp without time zone
166
- ) TABLESPACE ${tablespace};
167
- insert into ${schema}.${infTable} (status) values ('init');
168
- `);
169
- status = 'init';
170
- }
171
- return {
172
- infTable,
173
- tablespace,
174
- owner,
175
- version,
176
- status
177
- };
178
- }
179
- static objectDataToSql(task) {
180
- let sql = '';
181
- for (const rows of task.rows) {
182
- const keys = Object.keys(rows);
183
- sql += `insert into ${task.schema}.${task.tableName} (${keys}) values (`;
184
- for (let i = 0; i < keys.length; i++) {
185
- sql += (i ? ', ' : '') + (0, postgresql_client_1.stringifyValueForSQL)(rows[keys[i]]);
100
+ finally {
101
+ await migrationAdapter.close();
186
102
  }
187
- sql += ');\n';
188
103
  }
189
- return sql;
104
+ await this.emitAsync('finish');
105
+ return true;
190
106
  }
191
107
  }
192
108
  exports.DbMigrator = DbMigrator;
193
- async function locateMigrations(trg, dir) {
194
- for (const f of ['migration.ts', 'migration.js', 'migration.json']) {
195
- const filename = node_path_1.default.join(dir, f);
196
- if (node_fs_1.default.existsSync(filename)) {
197
- const x = await Promise.resolve(`${filename}`).then(s => tslib_1.__importStar(require(s)));
198
- const fileDir = node_path_1.default.dirname(filename);
199
- const obj = x.default || x;
200
- if (obj.version && obj.tasks) {
201
- const migration = { ...obj };
202
- migration.tasks = obj.tasks.map(k => (typeof k === 'string' ? node_path_1.default.resolve(fileDir, k) : k));
203
- trg.push(migration);
204
- }
205
- return;
206
- }
207
- }
208
- const files = node_fs_1.default.readdirSync(dir);
209
- for (const f of files) {
210
- const dirname = node_path_1.default.join(dir, f);
211
- if (node_fs_1.default.statSync(dirname).isDirectory()) {
212
- await locateMigrations(trg, dirname);
213
- }
214
- }
215
- }
package/cjs/index.js CHANGED
@@ -2,4 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./db-migrator.js"), exports);
5
+ tslib_1.__exportStar(require("./migration-package.js"), exports);
6
+ tslib_1.__exportStar(require("./migration-adapter.js"), exports);
5
7
  tslib_1.__exportStar(require("./types.js"), exports);
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MigrationAdapter = void 0;
4
+ class MigrationAdapter {
5
+ }
6
+ exports.MigrationAdapter = MigrationAdapter;
7
+ (function (MigrationAdapter) {
8
+ let EventKind;
9
+ (function (EventKind) {
10
+ EventKind["started"] = "started";
11
+ EventKind["success"] = "success";
12
+ EventKind["error"] = "error";
13
+ })(EventKind = MigrationAdapter.EventKind || (MigrationAdapter.EventKind = {}));
14
+ })(MigrationAdapter || (exports.MigrationAdapter = MigrationAdapter = {}));
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MigrationPackage = exports.isCustomMigrationTask = exports.isInsertDataMigrationTask = exports.isSqlScriptMigrationTask = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
6
+ const promises_1 = tslib_1.__importDefault(require("fs/promises"));
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const get_calling_filename_js_1 = require("./utils/get-calling-filename.js");
9
+ function isSqlScriptMigrationTask(x) {
10
+ return typeof x === 'object' && typeof x.script === 'string';
11
+ }
12
+ exports.isSqlScriptMigrationTask = isSqlScriptMigrationTask;
13
+ function isInsertDataMigrationTask(x) {
14
+ return typeof x === 'object' &&
15
+ typeof x.tableName === 'string' &&
16
+ Array.isArray(x.rows);
17
+ }
18
+ exports.isInsertDataMigrationTask = isInsertDataMigrationTask;
19
+ function isCustomMigrationTask(x) {
20
+ return typeof x === 'object' &&
21
+ typeof x.fn === 'function';
22
+ }
23
+ exports.isCustomMigrationTask = isCustomMigrationTask;
24
+ var MigrationPackage;
25
+ (function (MigrationPackage) {
26
+ async function load(asyncConfig) {
27
+ const out = {
28
+ ...asyncConfig,
29
+ migrations: []
30
+ };
31
+ if (!Array.isArray(asyncConfig.migrations))
32
+ 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
+ if (asyncConfig.migrations?.length) {
35
+ const srcMigrations = [];
36
+ const trgMigrations = [];
37
+ out.migrations = trgMigrations;
38
+ let x;
39
+ for (x of asyncConfig.migrations) {
40
+ x = typeof x === 'function' ? await x() : x;
41
+ if (typeof x === 'object' && x.tasks)
42
+ srcMigrations.push(x);
43
+ else if (typeof x === 'string') {
44
+ srcMigrations.push(...await loadMigrations(path_1.default.resolve(baseDir, x.replace(/\\/g, '/'))));
45
+ }
46
+ }
47
+ srcMigrations.sort((a, b) => a.version - b.version);
48
+ for (const migration of srcMigrations) {
49
+ const trgMigration = { ...migration, tasks: [] };
50
+ trgMigrations.push(trgMigration);
51
+ const srcTasks = migration.tasks;
52
+ trgMigration.tasks = [];
53
+ for (const t of srcTasks) {
54
+ if (typeof t === 'object') {
55
+ trgMigration.tasks.push(t);
56
+ }
57
+ else if (typeof t === 'string') {
58
+ let pattern = t.replace(/\\/g, '/');
59
+ pattern = path_1.default.resolve(migration.dirname || baseDir, pattern);
60
+ const files = await (0, fast_glob_1.default)(pattern, { absolute: true, onlyFiles: true });
61
+ for (const filename of files) {
62
+ const ext = path_1.default.extname(filename).toLowerCase();
63
+ if (!path_1.default.basename(filename, ext).endsWith('.task'))
64
+ continue;
65
+ if (ext === '.sql') {
66
+ const script = await promises_1.default.readFile(filename, 'utf-8');
67
+ trgMigration.tasks.push({
68
+ title: path_1.default.basename(filename),
69
+ filename,
70
+ script
71
+ });
72
+ }
73
+ else if (ext === '.json') {
74
+ try {
75
+ const json = JSON.parse(await promises_1.default.readFile(filename, 'utf-8'));
76
+ if (typeof json !== 'object')
77
+ continue;
78
+ if (json.script) {
79
+ json.title = json.title || 'Run sql script';
80
+ json.filename = filename;
81
+ trgMigration.tasks.push(json);
82
+ continue;
83
+ }
84
+ if (json.tableName && json.rows) {
85
+ json.title = json.title || 'Migrate data into ' + json.tableName;
86
+ json.filename = filename;
87
+ trgMigration.tasks.push(json);
88
+ continue;
89
+ }
90
+ if (typeof json.fn === 'function') {
91
+ json.title = json.title || 'Run custom function';
92
+ json.filename = filename;
93
+ trgMigration.tasks.push(json);
94
+ }
95
+ }
96
+ catch (e) {
97
+ e.message = `Error in ${filename}\n` + e.message;
98
+ throw e;
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ return out;
107
+ }
108
+ MigrationPackage.load = load;
109
+ async function loadMigrations(pattern) {
110
+ const out = [];
111
+ const files = await (0, fast_glob_1.default)(pattern, { absolute: true, onlyFiles: true });
112
+ for (const filename of files) {
113
+ const ext = path_1.default.extname(filename).toLowerCase();
114
+ if (path_1.default.basename(filename, ext) !== 'migration')
115
+ continue;
116
+ let json;
117
+ if (['.js', '.ts', '.cjs', '.mjs'].includes(ext)) {
118
+ json = await Promise.resolve(`${filename}`).then(s => tslib_1.__importStar(require(s)));
119
+ if (json.__esModule)
120
+ json = json.default;
121
+ }
122
+ else if (ext === '.json') {
123
+ try {
124
+ json = JSON.parse(await promises_1.default.readFile(filename, 'utf-8'));
125
+ }
126
+ catch (e) {
127
+ e.message = `Error in ${filename}\n` + e.message;
128
+ throw e;
129
+ }
130
+ }
131
+ if (json && typeof json === 'object' && json.version && Array.isArray(json.tasks)) {
132
+ json.dirname = path_1.default.dirname(filename);
133
+ out.push(json);
134
+ }
135
+ }
136
+ return out;
137
+ }
138
+ })(MigrationPackage || (exports.MigrationPackage = MigrationPackage = {}));
package/cjs/types.js CHANGED
@@ -1,2 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MigrationStatus = void 0;
4
+ var MigrationStatus;
5
+ (function (MigrationStatus) {
6
+ MigrationStatus["idle"] = "idle";
7
+ MigrationStatus["busy"] = "busy";
8
+ })(MigrationStatus || (exports.MigrationStatus = MigrationStatus = {}));