fix: extend source CHECK constraints to include visual_capture (kiwi#79)
Some checks are pending
CI / Frontend (Vue) (push) Waiting to run
CI / Backend (Python) (push) Waiting to run
Mirror / mirror (push) Waiting to run
Release / release (push) Waiting to run

Migrations 037 and 038 rebuild products and inventory_items tables
to add 'visual_capture' as a valid source value, which the label-confirm
endpoint sets when saving user-verified nutrition label data.
Adds 2 schema tests covering the new allowed value.
This commit is contained in:
pyr0ball 2026-04-25 08:46:44 -07:00
parent 0bac494ecd
commit e2c358c90a
3 changed files with 113 additions and 0 deletions

View file

@ -0,0 +1,34 @@
-- Migration 037: add 'visual_capture' to products.source CHECK constraint
-- SQLite cannot ALTER a CHECK constraint, so we rebuild the table.
PRAGMA foreign_keys = OFF;
BEGIN;
CREATE TABLE products_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
barcode TEXT UNIQUE,
name TEXT NOT NULL,
brand TEXT,
category TEXT,
description TEXT,
image_url TEXT,
nutrition_data TEXT NOT NULL DEFAULT '{}',
source TEXT NOT NULL DEFAULT 'openfoodfacts'
CHECK (source IN ('openfoodfacts', 'manual', 'receipt_ocr', 'visual_capture')),
source_data TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
INSERT INTO products_new
SELECT id, barcode, name, brand, category, description, image_url,
nutrition_data, source, source_data, created_at, updated_at
FROM products;
DROP TABLE products;
ALTER TABLE products_new RENAME TO products;
COMMIT;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,43 @@
-- Migration 038: add 'visual_capture' to inventory_items.source CHECK constraint
-- SQLite cannot ALTER a CHECK constraint, so we rebuild the table.
PRAGMA foreign_keys = OFF;
BEGIN;
CREATE TABLE inventory_items_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id INTEGER NOT NULL
REFERENCES products (id) ON DELETE RESTRICT,
receipt_id INTEGER
REFERENCES receipts (id) ON DELETE SET NULL,
quantity REAL NOT NULL DEFAULT 1 CHECK (quantity > 0),
unit TEXT NOT NULL DEFAULT 'count',
location TEXT NOT NULL,
sublocation TEXT,
purchase_date TEXT,
expiration_date TEXT,
status TEXT NOT NULL DEFAULT 'available'
CHECK (status IN ('available', 'consumed', 'expired', 'discarded')),
consumed_at TEXT,
notes TEXT,
source TEXT NOT NULL DEFAULT 'manual'
CHECK (source IN ('barcode_scan', 'manual', 'receipt', 'visual_capture')),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
opened_date TEXT,
disposal_reason TEXT
);
INSERT INTO inventory_items_new
SELECT id, product_id, receipt_id, quantity, unit, location, sublocation,
purchase_date, expiration_date, status, consumed_at, notes, source,
created_at, updated_at, opened_date, disposal_reason
FROM inventory_items;
DROP TABLE inventory_items;
ALTER TABLE inventory_items_new RENAME TO inventory_items;
COMMIT;
PRAGMA foreign_keys = ON;

View file

@ -11,6 +11,42 @@ def store(tmp_path: Path) -> Store:
s.close()
class TestProductsSchema:
"""Verify migrations 037/038 allow 'visual_capture' as a valid source."""
def test_products_accepts_visual_capture_source(self, store):
"""Migration 037: products.source CHECK includes 'visual_capture'."""
store.conn.execute(
"INSERT INTO products (name, source) VALUES (?, ?)",
("Test Product", "visual_capture"),
)
store.conn.commit()
row = store.conn.execute(
"SELECT source FROM products WHERE name='Test Product'"
).fetchone()
assert row[0] == "visual_capture"
def test_inventory_items_accepts_visual_capture_source(self, store):
"""Migration 038: inventory_items.source CHECK includes 'visual_capture'."""
store.conn.execute(
"INSERT INTO products (name, source) VALUES (?, ?)",
("Temp Product", "manual"),
)
store.conn.commit()
product_id = store.conn.execute(
"SELECT id FROM products WHERE name='Temp Product'"
).fetchone()[0]
store.conn.execute(
"INSERT INTO inventory_items (product_id, location, source) VALUES (?, ?, ?)",
(product_id, "pantry", "visual_capture"),
)
store.conn.commit()
row = store.conn.execute(
"SELECT source FROM inventory_items WHERE product_id=?", (product_id,)
).fetchone()
assert row[0] == "visual_capture"
class TestMigration:
def test_captured_products_table_exists(self, store):
cur = store.conn.execute(