Fix delete FK exhaustively; unset-scope surfaces as drift
deleteScript: previous fix missed beta_servers.prior_version_id, beta_server_scripts.prior_version_id, and deployments.beta_id. Cascade from betas.script_id -> beta_servers/beta_server_scripts left dangling prior_version_id refs, and deletions of cascaded betas dangled deployments.beta_id. Now nulls every NO ACTION reference before the DELETE inside a single transaction. Scope unset no longer touches disk from the API. Instead it detaches inventory rows for scripts/plugins so drift Pass 1 flags the on-disk copies as untracked; configs rely on drift Pass 2's compose-diff, which already handles scope=null naturally. The operator reconciles from /deployments using the existing rescan + reconcile buttons — same visible flow as any other drift, no more silent synchronous file removal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -338,35 +338,29 @@ export function deleteScript(scriptId: number): void {
|
||||
.get(scriptId) as { id: number } | undefined;
|
||||
if (beta) throw new ScriptError(`beta ${beta.id} is still running against this script`, 'has-active-beta');
|
||||
|
||||
// Null out deployment-history FKs that would otherwise block the cascade.
|
||||
// deployments.script_id/script_version_id/prior_version_id and
|
||||
// deployment_scripts.prior_version_id are historical audit references
|
||||
// with no ON DELETE action; keep the deployment rows intact but drop
|
||||
// the FK to the script so we can remove it.
|
||||
// Every FK that references scripts(id) or script_versions(id) with NO
|
||||
// ACTION (the default) will abort the delete unless we null it first.
|
||||
// ON DELETE CASCADE / SET NULL fires automatically. The list below covers
|
||||
// every NO ACTION reference in schema.sql; add to it if new ones appear.
|
||||
// deployments.script_id, script_version_id, prior_version_id, beta_id
|
||||
// deployment_scripts.prior_version_id
|
||||
// beta_servers.prior_version_id
|
||||
// beta_server_scripts.prior_version_id
|
||||
// deployments.beta_id needs nulling because betas.script_id ON DELETE
|
||||
// CASCADE nukes any beta bundled against this script, which would then
|
||||
// dangle deployments.beta_id.
|
||||
const handle = db();
|
||||
const tx = handle.transaction((id: number) => {
|
||||
handle
|
||||
.prepare(
|
||||
`UPDATE deployments
|
||||
SET script_version_id = NULL
|
||||
WHERE script_version_id IN (SELECT id FROM script_versions WHERE script_id = ?)`
|
||||
)
|
||||
.run(id);
|
||||
handle
|
||||
.prepare(
|
||||
`UPDATE deployments
|
||||
SET prior_version_id = NULL
|
||||
WHERE prior_version_id IN (SELECT id FROM script_versions WHERE script_id = ?)`
|
||||
)
|
||||
.run(id);
|
||||
const inMyVersions = 'IN (SELECT id FROM script_versions WHERE script_id = ?)';
|
||||
const inMyBetas = 'IN (SELECT id FROM betas WHERE script_id = ? UNION SELECT beta_id FROM beta_scripts WHERE script_id = ?)';
|
||||
|
||||
handle.prepare(`UPDATE beta_servers SET prior_version_id = NULL WHERE prior_version_id ${inMyVersions}`).run(id);
|
||||
handle.prepare(`UPDATE beta_server_scripts SET prior_version_id = NULL WHERE prior_version_id ${inMyVersions}`).run(id);
|
||||
handle.prepare(`UPDATE deployment_scripts SET prior_version_id = NULL WHERE prior_version_id ${inMyVersions}`).run(id);
|
||||
handle.prepare(`UPDATE deployments SET prior_version_id = NULL WHERE prior_version_id ${inMyVersions}`).run(id);
|
||||
handle.prepare(`UPDATE deployments SET script_version_id = NULL WHERE script_version_id ${inMyVersions}`).run(id);
|
||||
handle.prepare(`UPDATE deployments SET beta_id = NULL WHERE beta_id ${inMyBetas}`).run(id, id);
|
||||
handle.prepare('UPDATE deployments SET script_id = NULL WHERE script_id = ?').run(id);
|
||||
handle
|
||||
.prepare(
|
||||
`UPDATE deployment_scripts
|
||||
SET prior_version_id = NULL
|
||||
WHERE prior_version_id IN (SELECT id FROM script_versions WHERE script_id = ?)`
|
||||
)
|
||||
.run(id);
|
||||
handle.prepare('DELETE FROM scripts WHERE id = ?').run(id);
|
||||
});
|
||||
tx(scriptId);
|
||||
|
||||
Reference in New Issue
Block a user