From ca45a5acc04cb8f96e00da60940e852990145110 Mon Sep 17 00:00:00 2001 From: 4aiman Date: Fri, 29 May 2026 22:12:37 +0300 Subject: [PATCH] Protect user-edited products from seed overwrites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- frontend/js/db.js | 1 + frontend/js/main.js | 1 + src-tauri/src/lib.rs | 41 +++++++++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/frontend/js/db.js b/frontend/js/db.js index 2d63ffa..35d8043 100644 --- a/frontend/js/db.js +++ b/frontend/js/db.js @@ -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"); diff --git a/frontend/js/main.js b/frontend/js/main.js index 093b7c7..33cf222 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -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", diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4e71f13..8b44060 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -149,6 +149,7 @@ fn import_seed_products(app: tauri::AppHandle) -> Result { "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 { 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", []); }