UNPKG

@launchql/core

Version:

LaunchQL Package and Migration Tools

102 lines (101 loc) 4.16 kB
import { readFileSync } from 'fs'; import { getChanges, getExtensionName } from '../files'; import { parsePlanFile } from '../files/plan/parser'; import { resolveDependencies } from './deps'; import { errors } from '@launchql/types'; /** * Resolves SQL scripts for deployment or reversion. * * @param pkgDir - The package directory (defaults to the current working directory). * @param scriptType - The type of script to resolve (`deploy` or `revert`). * @returns A single concatenated SQL script as a string. */ export const resolve = (pkgDir = process.cwd(), scriptType = 'deploy') => { const sqlfile = []; const name = getExtensionName(pkgDir); const { resolved, external } = resolveDependencies(pkgDir, name, { tagResolution: 'resolve' }); const scripts = scriptType === 'revert' ? [...resolved].reverse() : resolved; for (const script of scripts) { if (external.includes(script)) continue; const file = `${pkgDir}/${scriptType}/${script}.sql`; const dscript = readFileSync(file, 'utf-8'); sqlfile.push(dscript); } return sqlfile.join('\n'); }; /** * Resolves SQL scripts based on the `launchql.plan` file. * * @param pkgDir - The package directory (defaults to the current working directory). * @param scriptType - The type of script to resolve (`deploy` or `revert`). * @returns A single concatenated SQL script as a string. */ export const resolveWithPlan = (pkgDir = process.cwd(), scriptType = 'deploy') => { const sqlfile = []; const planPath = `${pkgDir}/launchql.plan`; let resolved = getChanges(planPath); if (scriptType === 'revert') { resolved = resolved.reverse(); } for (const script of resolved) { const file = `${pkgDir}/${scriptType}/${script}.sql`; const dscript = readFileSync(file, 'utf-8'); sqlfile.push(dscript); } return sqlfile.join('\n'); }; /** * Resolves a tag reference to its corresponding change name. * Tags provide a way to reference specific points in a package's deployment history. * * @param planPath - Path to the plan file containing tag definitions * @param tagReference - The tag reference to resolve (e.g., "package:@tagName" or "@tagName") * @param currentPackage - The current package name (used when tag doesn't specify package) * @returns The resolved change name * @throws Error if tag format is invalid or tag is not found * * @example * // Resolve a tag in the current package * resolveTagToChangeName('/path/to/launchql.plan', '@v1.0.0', 'mypackage') * // Returns: 'schema/v1' * * @example * // Resolve a tag from another package * resolveTagToChangeName('/path/to/launchql.plan', 'auth:@v2.0.0') * // Returns: 'users/table' */ export const resolveTagToChangeName = (planPath, tagReference, currentProject) => { // If not a tag reference, return as-is if (!tagReference.includes('@')) { return tagReference; } // Handle simple tag format (@tagName) by prepending current package if (tagReference.startsWith('@') && !tagReference.includes(':')) { if (!currentProject) { const plan = parsePlanFile(planPath); if (!plan.data) { throw errors.PLAN_PARSE_ERROR({ planPath, errors: 'Could not parse plan file' }); } currentProject = plan.data.package; } tagReference = `${currentProject}:${tagReference}`; } // Parse package:@tagName format const match = tagReference.match(/^([^:]+):@(.+)$/); if (!match) { throw errors.INVALID_NAME({ name: tagReference, type: 'tag', rules: 'Expected format: package:@tagName or @tagName' }); } const [, projectName, tagName] = match; // Parse plan file to find tag const planResult = parsePlanFile(planPath); if (!planResult.data) { throw errors.PLAN_PARSE_ERROR({ planPath, errors: 'Could not parse plan file' }); } // Find the tag in the plan const tag = planResult.data.tags?.find((t) => t.name === tagName); if (!tag) { throw errors.TAG_NOT_FOUND({ tag: tagName, project: projectName }); } return tag.change; };