Add migration verification reports
This commit is contained in:
1 parent
de63df7daf
commit
49c1dd2888
9 files changed
+117
No files matched your search
@@ -0,0 +1,65 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { DatabaseSync, type StatementSync } from "node:sqlite";
|
||||
import type { CreateMigrationReportInput } from "../../shared/commands";
|
||||
import { createId } from "../../shared/ids";
|
||||
import { AuditService } from "./audit-service";
|
||||
|
||||
const LEGACY_TABLES = [
|
||||
"organizations",
|
||||
"agents",
|
||||
"tasks",
|
||||
"approvals",
|
||||
"chat_messages",
|
||||
"providers",
|
||||
"skill_definitions",
|
||||
"file_objects",
|
||||
"social_accounts",
|
||||
];
|
||||
|
||||
export class MigrationService {
|
||||
private readonly audit: AuditService;
|
||||
|
||||
constructor(private readonly db: DatabaseSync) {
|
||||
this.audit = new AuditService(db);
|
||||
}
|
||||
|
||||
createReport(input: CreateMigrationReportInput): string {
|
||||
if (!existsSync(input.sourceDatabasePath)) throw new Error("Source database was not found.");
|
||||
const source = new DatabaseSync(input.sourceDatabasePath, { readOnly: true });
|
||||
try {
|
||||
const availableTables = new Set(
|
||||
source.prepare("select name from sqlite_master where type = 'table'")
|
||||
.all()
|
||||
.map((row) => (row as { name: string }).name),
|
||||
);
|
||||
const tableCounts = Object.fromEntries(
|
||||
LEGACY_TABLES
|
||||
.filter((table) => availableTables.has(table))
|
||||
.map((table) => [table, countRows(source.prepare(`select count(*) as count from ${table}`))]),
|
||||
);
|
||||
const missingTables = LEGACY_TABLES.filter((table) => !availableTables.has(table));
|
||||
const reportId = createId("mig");
|
||||
const now = new Date().toISOString();
|
||||
this.db.prepare(`
|
||||
insert into migration_reports(id, org_id, source_ref, report_json, created_at)
|
||||
values (?, ?, ?, ?, ?)
|
||||
`).run(reportId, input.orgId, input.sourceDatabasePath, JSON.stringify({ tableCounts, missingTables }), now);
|
||||
this.audit.record({
|
||||
orgId: input.orgId,
|
||||
entityType: "migration_report",
|
||||
entityId: reportId,
|
||||
actorType: "system",
|
||||
actorId: null,
|
||||
action: "created",
|
||||
payload: { sourceRef: input.sourceDatabasePath, tableCount: Object.keys(tableCounts).length },
|
||||
});
|
||||
return reportId;
|
||||
} finally {
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function countRows(statement: StatementSync): number {
|
||||
return (statement.get() as { count: number }).count;
|
||||
}
|
||||
@@ -57,6 +57,7 @@ export class SnapshotService {
|
||||
skillRuntimeSnapshots: list(this.db, "skill_runtime_snapshots", "created_at desc"),
|
||||
socialAccounts: list(this.db, "social_accounts", "created_at asc"),
|
||||
policyRules: list(this.db, "policy_rules", "created_at asc"),
|
||||
migrationReports: list(this.db, "migration_reports", "created_at desc"),
|
||||
auditEvents: list<AppSnapshot["auditEvents"][number]>(this.db, "audit_events", "created_at desc").slice(0, 200),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user