feat(intake): record the background-removal intent and the original path (#281)
Adds the two columns the background-removal feature (#281) is built on: item_drafts.remove_background (boolean, not null, default true) records the submitter's per-submission intent, and item_images.original_image_path (nullable text, no default) records where a cut-out photo came from so it can be restored. The default on remove_background is load-bearing — any row written by a path that does not mention the column behaves like the new default, so no backfill is needed. original_image_path stays null until a photo has actually been cut out, which doubles as the answer to "can this be restored?" rather than needing a separate flag. Also updates the Drizzle mirror in src/db-drizzle/schema.ts by hand (the local dev database was not running to re-pull from) and adds the integration test backgroundRemoval.integration.test.ts, including the exported seedSubmission helper that Task 3 will reuse. Closes #281 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { pool } from '../../src/db';
|
||||
import { resetDb, closeDb } from './setup/testDb';
|
||||
|
||||
beforeEach(async () => {
|
||||
await resetDb();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await pool.end();
|
||||
await closeDb();
|
||||
});
|
||||
|
||||
/** An item with a draft row and one image, which is what a submission leaves. */
|
||||
export async function seedSubmission(
|
||||
imagePath = '/uploads/photo.jpg'
|
||||
): Promise<{ itemId: number; imageId: number }> {
|
||||
const item = await pool.query<{ id: number }>(
|
||||
`INSERT INTO items (name, status) VALUES ('Submission placeholder', 'pending') RETURNING id`
|
||||
);
|
||||
const itemId = item.rows[0]!.id;
|
||||
await pool.query(`INSERT INTO item_drafts (item_id) VALUES ($1)`, [itemId]);
|
||||
const image = await pool.query<{ id: number }>(
|
||||
`INSERT INTO item_images (item_id, image_path, sort_order) VALUES ($1, $2, 0) RETURNING id`,
|
||||
[itemId, imagePath]
|
||||
);
|
||||
return { itemId, imageId: image.rows[0]!.id };
|
||||
}
|
||||
|
||||
describe('the background-removal columns', () => {
|
||||
// Default true because the submitter's checkbox is ticked by default, and
|
||||
// because a row written by any path that does not mention the column should
|
||||
// behave like the new default rather than needing a backfill.
|
||||
it('defaults remove_background to true', async () => {
|
||||
const { itemId } = await seedSubmission();
|
||||
|
||||
const { rows } = await pool.query<{ remove_background: boolean }>(
|
||||
`SELECT remove_background FROM item_drafts WHERE item_id = $1`,
|
||||
[itemId]
|
||||
);
|
||||
expect(rows[0]?.remove_background).toBe(true);
|
||||
});
|
||||
|
||||
// Null is also the answer to "can this be restored?", which is why there is
|
||||
// no separate flag: one fact, one place.
|
||||
it('leaves original_image_path null until a photo has been cut out', async () => {
|
||||
const { imageId } = await seedSubmission();
|
||||
|
||||
const { rows } = await pool.query<{ original_image_path: string | null }>(
|
||||
`SELECT original_image_path FROM item_images WHERE id = $1`,
|
||||
[imageId]
|
||||
);
|
||||
expect(rows[0]?.original_image_path).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user