mirror of
https://github.com/langgenius/dify.git
synced 2026-07-23 04:55:28 -04:00
4ee43b8afc
Import the committed KnowledgeFS snapshot dc4072ee302317145612087ce7440851dc329fd0 under knowledge-fs/ without its Git history, local IDE settings, or build artifacts.
104 lines
3.8 KiB
TypeScript
104 lines
3.8 KiB
TypeScript
import { readFile, readdir, writeFile } from "node:fs/promises";
|
|
import { resolve } from "node:path";
|
|
|
|
const mode = process.argv[2];
|
|
const root = resolve(import.meta.dirname, "../../..");
|
|
const migrationsDirectory = resolve(root, "packages/database/migrations");
|
|
const generatedRegistryPath = resolve(
|
|
root,
|
|
"packages/database/src/migration-artifacts.generated.ts",
|
|
);
|
|
|
|
if (mode !== "write" && mode !== "check") {
|
|
throw new Error("Usage: tsx packages/database/scripts/migration-artifacts.ts <write|check>");
|
|
}
|
|
|
|
const sourceArtifacts = await readMigrationSourceArtifacts();
|
|
const expectedRegistry = renderGeneratedRegistry(sourceArtifacts);
|
|
|
|
if (mode === "write") {
|
|
// SQL files are the immutable migration sources. Never regenerate or overwrite them from the
|
|
// current schema catalog; only refresh the registry embedded in the production bundle.
|
|
await writeFile(generatedRegistryPath, expectedRegistry, "utf8");
|
|
} else {
|
|
const currentRegistry = await readFile(generatedRegistryPath, "utf8").catch(() => undefined);
|
|
if (currentRegistry !== expectedRegistry) {
|
|
throw new Error("Database migration registry is out of date. Run pnpm db:migrations:write.");
|
|
}
|
|
}
|
|
|
|
interface SourceMigrationArtifact {
|
|
readonly content: string;
|
|
readonly filename: string;
|
|
readonly migrationId: string;
|
|
readonly path: string;
|
|
}
|
|
|
|
async function readMigrationSourceArtifacts(): Promise<readonly SourceMigrationArtifact[]> {
|
|
const filenames = (await readdir(migrationsDirectory))
|
|
.filter((filename) => filename.endsWith(".sql"))
|
|
.sort((left, right) => left.localeCompare(right));
|
|
const artifacts = await Promise.all(
|
|
filenames.map(async (filename): Promise<SourceMigrationArtifact> => {
|
|
const match = /^(\d{4}_[a-z0-9_]+)\.(postgres|tidb)\.sql$/u.exec(filename);
|
|
if (!match) {
|
|
throw new Error(`Invalid database migration filename: ${filename}`);
|
|
}
|
|
|
|
const migrationId = match[1];
|
|
const dialect = match[2];
|
|
if (!migrationId || !dialect) {
|
|
throw new Error(`Invalid database migration filename: ${filename}`);
|
|
}
|
|
|
|
const content = await readFile(resolve(migrationsDirectory, filename), "utf8");
|
|
if (!content.includes(`-- Migration id: ${migrationId}\n`)) {
|
|
throw new Error(`Migration ${filename} has a mismatched migration id header`);
|
|
}
|
|
if (!content.includes(`-- Dialect: ${dialect}\n`)) {
|
|
throw new Error(`Migration ${filename} has a mismatched dialect header`);
|
|
}
|
|
|
|
return {
|
|
content,
|
|
filename,
|
|
migrationId,
|
|
path: `packages/database/migrations/${filename}`,
|
|
};
|
|
}),
|
|
);
|
|
|
|
const dialectsByMigration = new Map<string, Set<string>>();
|
|
for (const artifact of artifacts) {
|
|
const dialect = artifact.filename.split(".").at(-2);
|
|
const dialects = dialectsByMigration.get(artifact.migrationId) ?? new Set<string>();
|
|
dialects.add(dialect ?? "");
|
|
dialectsByMigration.set(artifact.migrationId, dialects);
|
|
}
|
|
for (const [migrationId, dialects] of dialectsByMigration) {
|
|
if (!dialects.has("postgres") || !dialects.has("tidb") || dialects.size !== 2) {
|
|
throw new Error(`Migration ${migrationId} must provide exactly postgres and tidb artifacts`);
|
|
}
|
|
}
|
|
|
|
return artifacts;
|
|
}
|
|
|
|
function renderGeneratedRegistry(artifacts: readonly SourceMigrationArtifact[]): string {
|
|
const rows = artifacts.map(
|
|
(artifact) =>
|
|
` { content: ${JSON.stringify(artifact.content)}, path: ${JSON.stringify(artifact.path)} },`,
|
|
);
|
|
|
|
return [
|
|
"// Generated by packages/database/scripts/migration-artifacts.ts. Do not edit manually.",
|
|
'import type { MigrationArtifact } from "./migration-file";',
|
|
"",
|
|
"// biome-ignore format: one deterministic row per immutable SQL artifact keeps generation cheap.",
|
|
"export const migrationArtifacts = [",
|
|
...rows,
|
|
"] as const satisfies readonly MigrationArtifact[];",
|
|
"",
|
|
].join("\n");
|
|
}
|