Protect user-edited products from seed overwrites

New column: user_edited INTEGER DEFAULT 0 on products table.
- JS migration adds column
- showEditProductModal sets user_edited=1 on save
- Rust seed import: UPDATE store products (source IN magnit/5ka/kdv/ion)
  WHERE user_edited IS NULL OR user_edited = 0
- Now updates KBJU + all micronutrients from seed (not just INSERT OR IGNORE)
- User edits preserved: user_edited=1 products never touched by seed import
- Manual/recipe_import products also never touched (source check)

Flow: seed update fixes wrong KBJU (e.g. bread 268→243) automatically,
but if user already fixed it manually — their fix stays.
This commit is contained in:
4aiman 2026-05-29 22:12:37 +03:00
commit ca45a5acc0
3 changed files with 27 additions and 16 deletions

View file

@ -965,6 +965,7 @@ async function runMigrations() {
await addProdCol("composition", "TEXT");
await addProdCol("name_lower", "TEXT");
await addProdCol("nutrients_guessed", "INTEGER DEFAULT 0");
await addProdCol("user_edited", "INTEGER DEFAULT 0");
const gpsCols = (await select("PRAGMA table_info(gps_points)")).map(r => r.name);
if (!gpsCols.includes("seq")) await execute("ALTER TABLE gps_points ADD COLUMN seq INTEGER");

View file

@ -1468,6 +1468,7 @@ function showEditProductModal(p, onSaved) {
vals.push(val);
idx++;
}
sets.push(`user_edited=1`);
vals.push(p.id);
await window.__TAURI__.core.invoke("plugin:sql|execute", {
db: "sqlite:baldav.db",

View file

@ -149,6 +149,7 @@ fn import_seed_products(app: tauri::AppHandle) -> Result<String, String> {
"vit_a_mcg REAL", "vit_b1_mg REAL", "vit_b2_mg REAL",
"vit_b3_mg REAL", "vit_c_mg REAL", "vit_e_mg REAL", "carotene_mcg REAL",
"nutrients_guessed INTEGER DEFAULT 0",
"user_edited INTEGER DEFAULT 0",
];
for col in &extra_cols {
let _ = main_db.execute(&format!("ALTER TABLE products ADD COLUMN {}", col), []);
@ -245,24 +246,32 @@ fn import_seed_products(app: tauri::AppHandle) -> Result<String, String> {
WHERE (nutrients_guessed IS NULL OR nutrients_guessed = 0)
AND name_lower IN (SELECT s.name_lower FROM seed.products s WHERE s.nutrients_guessed = 1)"
);
// Sync micronutrients for products that have them in seed but not in main
// Update KBJU + micronutrients for store products that user hasn't manually edited.
// This ensures seed corrections (e.g. bread 268→243) flow through to app DB.
let _ = main_db.execute_batch(
"UPDATE main.products SET
sodium_mg = COALESCE(sodium_mg, (SELECT s.sodium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
potassium_mg = COALESCE(potassium_mg, (SELECT s.potassium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
calcium_mg = COALESCE(calcium_mg, (SELECT s.calcium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
magnesium_mg = COALESCE(magnesium_mg, (SELECT s.magnesium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
phosphorus_mg= COALESCE(phosphorus_mg,(SELECT s.phosphorus_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
iron_mg = COALESCE(iron_mg, (SELECT s.iron_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_a_mcg = COALESCE(vit_a_mcg, (SELECT s.vit_a_mcg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_b1_mg = COALESCE(vit_b1_mg, (SELECT s.vit_b1_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_b2_mg = COALESCE(vit_b2_mg, (SELECT s.vit_b2_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_b3_mg = COALESCE(vit_b3_mg, (SELECT s.vit_b3_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_c_mg = COALESCE(vit_c_mg, (SELECT s.vit_c_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
vit_e_mg = COALESCE(vit_e_mg, (SELECT s.vit_e_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1)),
carotene_mcg = COALESCE(carotene_mcg, (SELECT s.carotene_mcg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1))
WHERE main.products.sodium_mg IS NULL
AND main.products.name_lower IN (SELECT s2.name_lower FROM seed.products s2 WHERE s2.sodium_mg IS NOT NULL)"
kcal_per_100g = (SELECT s.kcal_per_100g FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1),
protein_per_100g = (SELECT s.protein_per_100g FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1),
fat_per_100g = (SELECT s.fat_per_100g FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1),
carbs_per_100g = (SELECT s.carbs_per_100g FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1),
fiber_per_100g = (SELECT s.fiber_per_100g FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1),
nutrients_guessed= COALESCE((SELECT s.nutrients_guessed FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), nutrients_guessed),
sodium_mg = COALESCE((SELECT s.sodium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), sodium_mg),
potassium_mg = COALESCE((SELECT s.potassium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), potassium_mg),
calcium_mg = COALESCE((SELECT s.calcium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), calcium_mg),
magnesium_mg = COALESCE((SELECT s.magnesium_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), magnesium_mg),
phosphorus_mg = COALESCE((SELECT s.phosphorus_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), phosphorus_mg),
iron_mg = COALESCE((SELECT s.iron_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), iron_mg),
vit_a_mcg = COALESCE((SELECT s.vit_a_mcg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_a_mcg),
vit_b1_mg = COALESCE((SELECT s.vit_b1_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_b1_mg),
vit_b2_mg = COALESCE((SELECT s.vit_b2_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_b2_mg),
vit_b3_mg = COALESCE((SELECT s.vit_b3_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_b3_mg),
vit_c_mg = COALESCE((SELECT s.vit_c_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_c_mg),
vit_e_mg = COALESCE((SELECT s.vit_e_mg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), vit_e_mg),
carotene_mcg = COALESCE((SELECT s.carotene_mcg FROM seed.products s WHERE s.name_lower = main.products.name_lower LIMIT 1), carotene_mcg)
WHERE (main.products.user_edited IS NULL OR main.products.user_edited = 0)
AND main.products.source IN ('magnit', '5ka', 'kdv', 'ion')
AND main.products.name_lower IN (SELECT s2.name_lower FROM seed.products s2)"
);
let _ = main_db.execute("DETACH DATABASE seed", []);
}