@launchql/migrate
Version:
PostgreSQL Migration Tools
152 lines (151 loc) • 5.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extDeps = exports.getDeps = void 0;
const fs_1 = require("fs");
const glob_1 = require("glob");
const path_1 = require("path");
const makeKey = (sqlmodule) => `/deploy/${sqlmodule}.sql`;
const getDeps = (packageDir, extname) => {
const external = [];
const deps = {};
// Original dependency resolution algorithm
function dep_resolve(sqlmodule, resolved, unresolved) {
unresolved.push(sqlmodule);
let edges = deps[makeKey(sqlmodule)];
if (/:/.test(sqlmodule)) {
// Has a prefix — could be internal or external
const [project, localKey] = sqlmodule.split(':', 2);
if (project === extname) {
// Internal reference to current project
sqlmodule = localKey;
edges = deps[makeKey(localKey)];
if (!edges) {
throw new Error(`Internal module not found: ${localKey} (from ${project}:${localKey})`);
}
}
else {
// External reference — always OK, even if not in deps yet
external.push(sqlmodule);
deps[sqlmodule] = [];
return;
}
}
else {
// No prefix — must be internal
if (!edges) {
throw new Error(`Internal module not found: ${sqlmodule}`);
}
}
for (const dep of edges) {
if (!resolved.includes(dep)) {
if (unresolved.includes(dep)) {
throw new Error(`Circular reference detected ${sqlmodule}, ${dep}`);
}
dep_resolve(dep, resolved, unresolved);
}
}
resolved.push(sqlmodule);
const index = unresolved.indexOf(sqlmodule);
unresolved.splice(index);
}
// Process SQL files and build dependency graph
const files = (0, glob_1.sync)(`${packageDir}/deploy/**/*.sql`);
for (const file of files) {
const data = (0, fs_1.readFileSync)(file, 'utf-8');
const lines = data.split('\n');
const key = '/' + (0, path_1.relative)(packageDir, file);
deps[key] = [];
// console.log(key, data);
for (const line of lines) {
// Handle requires statements
const requiresMatch = line.match(/^-- requires: (.*)/);
if (requiresMatch) {
deps[key].push(requiresMatch[1].trim());
continue;
}
// Handle deploy statements - exactly as in original
let m2;
let keyToTest;
if (/:/.test(line)) {
m2 = line.match(/^-- Deploy ([^:]*):([\w\/]+) to pg/);
if (m2) {
const actualProject = m2[1];
keyToTest = m2[2];
if (extname !== actualProject) {
throw new Error(`Mismatched project name in deploy file:
Expected project: ${extname}
Found in line : ${actualProject}
Line : ${line}`);
}
const expectedKey = makeKey(keyToTest);
if (key !== expectedKey) {
throw new Error(`Deployment script path or internal name mismatch:
Expected key : ${key}
Found in line : ${expectedKey}
Line : ${line}`);
}
}
}
else {
m2 = line.match(/^-- Deploy (.*) to pg/);
if (m2) {
keyToTest = m2[1];
if (key !== makeKey(keyToTest)) {
throw new Error('deployment script in wrong place or is named wrong internally\n' + line);
}
}
}
}
}
let resolved = [];
const unresolved = [];
// Add synthetic root node - exactly as in original
deps[makeKey('apps/index')] = Object.keys(deps)
.filter((dep) => dep.startsWith('/deploy/'))
.map((dep) => dep.replace(/^\/deploy\//, '').replace(/\.sql$/, ''));
dep_resolve('apps/index', resolved, unresolved);
// Remove synthetic root
const index = resolved.indexOf('apps/index');
resolved.splice(index, 1);
delete deps[makeKey('apps/index')];
// Sort extensions first - exactly as in original
const extensions = resolved.filter((module) => module.startsWith('extensions/'));
const normalSql = resolved.filter((module) => !module.startsWith('extensions/'));
resolved = [...extensions, ...normalSql];
return { external, resolved, deps };
};
exports.getDeps = getDeps;
const extDeps = (name, modules) => {
if (!modules[name]) {
throw new Error(`module ${name} does not exist!`);
}
const external = [];
const deps = Object.keys(modules).reduce((memo, key) => {
memo[key] = modules[key].requires;
return memo;
}, {});
function dep_resolve(sqlmodule, resolved, unresolved) {
unresolved.push(sqlmodule);
let edges = deps[sqlmodule];
if (!edges) {
external.push(sqlmodule);
edges = deps[sqlmodule] = [];
}
for (const dep of edges) {
if (!resolved.includes(dep)) {
if (unresolved.includes(dep)) {
throw new Error(`Circular reference detected ${sqlmodule}, ${dep}`);
}
dep_resolve(dep, resolved, unresolved);
}
}
resolved.push(sqlmodule);
const index = unresolved.indexOf(sqlmodule);
unresolved.splice(index);
}
const resolved = [];
const unresolved = [];
dep_resolve(name, resolved, unresolved);
return { external, resolved };
};
exports.extDeps = extDeps;