semgrator
Version:
Run migrations code based on semantic version rules
81 lines • 2.82 kB
JavaScript
import semver from 'semver';
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { readdir } from 'node:fs/promises';
import rfdc from 'rfdc';
import abstractLogger from 'abstract-logging';
const clone = rfdc();
async function processAll(iterator) {
let lastResult;
do {
const result = await iterator.next();
if (result.done) {
return result.value || lastResult;
}
lastResult = result.value;
} while (true);
}
export async function* loadMigrationsFromPath(path) {
const files = (await readdir(path)).filter(file => file.match(/\.(c|m)?js$/));
const migrations = (await Promise.all(files.map(async (file) => {
const module = await import(pathToFileURL(join(path, file)).toString());
if (module.migration) {
return module.migration;
}
else if (module.default?.version &&
typeof module.default?.up === 'function') {
return module.default;
}
}))).filter(migration => !!migration);
migrations.sort((a, b) => semver.compare(a.version, b.version));
for (const migration of migrations) {
yield migration;
}
}
async function* processMigrations(input, migrations, version, logger) {
let result = input;
let lastVersion = version;
let changed = false;
for await (const migration of migrations) {
if (semver.gt(migration.version, lastVersion)) {
logger.info(`Migrating to version ${migration.version}`);
result = await migration.up(clone(result));
lastVersion = migration.toVersion || migration.version;
changed = true;
}
yield { version: lastVersion, result: result, changed };
}
}
function semgratorWithMigrations(params) {
const iterator = processMigrations(params.input, params.migrations, params.version, params.logger || abstractLogger);
let processing;
return {
[Symbol.asyncIterator]() {
return iterator;
},
then(onFulfilled, onRejected) {
if (!processing) {
processing = processAll(iterator);
}
return processing.then(onFulfilled, onRejected);
},
};
}
export function semgrator(params) {
if (typeof params.version !== 'string') {
throw new Error(`Invalid version. Must be a string. Got type "${typeof params.version}".`);
}
if ('path' in params) {
return semgratorWithMigrations({
...params,
migrations: loadMigrationsFromPath(params.path),
});
}
else if ('migrations' in params) {
return semgratorWithMigrations(params);
}
else {
throw new Error('Specify either path or migrations');
}
}
//# sourceMappingURL=semgrator.js.map