Public: anyone can read this; the crew can change it.
Absorb: deleting an app leaves its feature rows and settings behind #9643
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/9542-absorb-deleting-an-app-leaves-its-featur → main 3 commits fork 1 thread · 1 unresolved
3 files
changed +25
−4
src/core/apps.ts +6 −2
| @@ -231,6 +231,10 @@ export function updateApp( | ||
| 231 | 231 | } |
| 232 | 232 | |
| 233 | 233 | export function deleteApp(db: Database, appId: string): boolean { |
| 234 | db.run("DELETE FROM app_vital WHERE app_id = ?1", [appId]); | |
| 235 | return db.query("DELETE FROM app WHERE id = ?1").run(appId).changes > 0; | |
| 234 | return db.transaction(() => { | |
| 235 | db.run("DELETE FROM app_vital WHERE app_id = ?1", [appId]); | |
| 236 | db.run("DELETE FROM app_feature WHERE app_id = ?1", [appId]); | |
| 237 | db.run("DELETE FROM app_feature_setting WHERE app_id = ?1", [appId]); | |
| 238 | return db.query("DELETE FROM app WHERE id = ?1").run(appId).changes > 0; | |
| 239 | })(); | |
| 236 | 240 | } |
test/apps-measure.test.ts +8 −1
| @@ -267,7 +267,14 @@ describe("what is kept", () => { | ||
| 267 | 267 | |
| 268 | 268 | test("the prune and the per-app reads use an index", () => { |
| 269 | 269 | const plan = (sql: string) => |
| 270 | app.db.query<{ detail: string }, []>(`EXPLAIN QUERY PLAN ${sql}`).all().map((r) => r.detail).join("\n"); | |
| 270 | { | |
| 271 | const q = app.db.prepare<{ detail: string }, []>(`EXPLAIN QUERY PLAN ${sql}`); | |
| 272 | try { | |
| 273 | return q.all().map((r) => r.detail).join("\n"); | |
| 274 | } finally { | |
| 275 | q.finalize(); | |
| 276 | } | |
| 277 | }; | |
| 271 | 278 | expect(plan("DELETE FROM app_vital WHERE at < 1")).toContain("app_vital_at"); |
| 272 | 279 | expect(plan("SELECT COUNT(*) FROM app_vital WHERE app_id = 'a' AND day = 'd'")).toContain("app_vital_app_day"); |
| 273 | 280 | }); |
test/features.test.ts +11 −1
| @@ -20,7 +20,7 @@ import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | ||
| 20 | 20 | import { checkSetting, featureEnv, parseFeature, settingEnvName } from "../src/apps/feature.ts"; |
| 21 | 21 | import { featureVarsAt } from "../src/apps/feature_env.ts"; |
| 22 | 22 | import { appEnv } from "../src/apps/process.ts"; |
| 23 | import { createApp as insertApp } from "../src/core/apps.ts"; | |
| 23 | import { createApp as insertApp, deleteApp } from "../src/core/apps.ts"; | |
| 24 | 24 | import { listEvents } from "../src/core/events.ts"; |
| 25 | 25 | import { absorb, featureSettings, getAbsorbed } from "../src/core/features.ts"; |
| 26 | 26 | import type { Repo } from "../src/core/repos.ts"; |
| @@ -363,4 +363,14 @@ describe("absorbing an app", () => { | ||
| 363 | 363 | const page = await (await web(adaCookie, "/settings")).text(); |
| 364 | 364 | expect(page).toContain("Many 19"); |
| 365 | 365 | }); |
| 366 | ||
| 367 | test("deleting the app takes its feature row and settings with it", () => { | |
| 368 | const rows = (table: string) => | |
| 369 | app.db.query(`SELECT 1 FROM ${table} WHERE app_id = ?1`).all(appId).length; | |
| 370 | expect(rows("app_feature")).toBe(1); | |
| 371 | expect(rows("app_feature_setting")).toBeGreaterThan(0); | |
| 372 | expect(deleteApp(app.db, appId)).toBe(true); | |
| 373 | expect(rows("app_feature")).toBe(0); | |
| 374 | expect(rows("app_feature_setting")).toBe(0); | |
| 375 | }); | |
| 366 | 376 | }); |
new above
offline
Clean up the nesting: write this as
const plan = (sql: string) => { ... }with normal indentation.