Faster migrations, recalculate fixes point order, egg seed guard

Migrations:
- Batch PRAGMA table_info per table instead of N separate hasColumn calls
- Reduced IPC calls from ~22 to ~10 per startup
- Egg product_units seed only runs once (checks COUNT first)
- Removed unused hasColumn function

Recalculation:
- recalculateSession now re-orders points by timestamp
- Assigns seq = 1,2,3... in timestamp order
- Only updates if order is wrong (skips if already correct)
- Fixes tracks where points were recorded out of order
This commit is contained in:
4aiman 2026-05-25 02:42:52 +03:00
commit 606481103c
2 changed files with 49 additions and 54 deletions

View file

@ -807,25 +807,15 @@ window.DB.updateSessionBike = updateSessionBike;
// JS-side migrations — safe for any DB state (checks before altering)
async function runMigrations() {
async function hasColumn(table, col) {
const info = await select(`PRAGMA table_info(${table})`);
return info.some(r => r.name === col);
}
if (!(await hasColumn("products", "composition"))) {
await execute("ALTER TABLE products ADD COLUMN composition TEXT");
}
if (!(await hasColumn("products", "name_lower"))) {
await execute("ALTER TABLE products ADD COLUMN name_lower TEXT");
}
if (!(await hasColumn("gps_points", "seq"))) {
await execute("ALTER TABLE gps_points ADD COLUMN seq INTEGER");
}
// Batch column checks — one PRAGMA per table instead of N separate IPC calls
const productCols = (await select("PRAGMA table_info(products)")).map(r => r.name);
const addProdCol = async (col, type) => { if (!productCols.includes(col)) await execute(`ALTER TABLE products ADD COLUMN ${col} ${type}`); };
await addProdCol("composition", "TEXT");
await addProdCol("name_lower", "TEXT");
await addProdCol("nutrients_guessed", "INTEGER DEFAULT 0");
if (!(await hasColumn("products", "nutrients_guessed"))) {
await execute("ALTER TABLE products ADD COLUMN nutrients_guessed INTEGER DEFAULT 0");
}
console.log("[db.js] base migrations done, starting cooking_methods...");
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");
// --- Cooking methods table ---
await execute(`CREATE TABLE IF NOT EXISTS cooking_methods (
@ -865,23 +855,14 @@ async function runMigrations() {
console.log("[db.js] Seeded 6 cooking methods");
}
// --- Recipes table: add missing columns ---
if (!(await hasColumn("recipes", "cooking_method_id"))) {
await execute("ALTER TABLE recipes ADD COLUMN cooking_method_id INTEGER REFERENCES cooking_methods(id)");
}
if (!(await hasColumn("recipes", "created_at"))) {
await execute("ALTER TABLE recipes ADD COLUMN created_at TEXT DEFAULT (datetime('now'))");
}
// Ensure servings column exists (Rust creates it as INTEGER, we need REAL for half-portions)
// Column already exists from Rust, so we leave it as is.
// --- Recipes + ingredients: batch column checks ---
const recipeCols = (await select("PRAGMA table_info(recipes)")).map(r => r.name);
if (!recipeCols.includes("cooking_method_id")) await execute("ALTER TABLE recipes ADD COLUMN cooking_method_id INTEGER");
if (!recipeCols.includes("created_at")) await execute("ALTER TABLE recipes ADD COLUMN created_at TEXT DEFAULT (datetime('now'))");
// --- Recipe ingredients: add missing columns ---
if (!(await hasColumn("recipe_ingredients", "custom_name"))) {
await execute("ALTER TABLE recipe_ingredients ADD COLUMN custom_name TEXT");
}
if (!(await hasColumn("recipe_ingredients", "cooking_method_id"))) {
await execute("ALTER TABLE recipe_ingredients ADD COLUMN cooking_method_id INTEGER REFERENCES cooking_methods(id)");
}
const riCols = (await select("PRAGMA table_info(recipe_ingredients)")).map(r => r.name);
if (!riCols.includes("custom_name")) await execute("ALTER TABLE recipe_ingredients ADD COLUMN custom_name TEXT");
if (!riCols.includes("cooking_method_id")) await execute("ALTER TABLE recipe_ingredients ADD COLUMN cooking_method_id INTEGER");
// --- Serving units table ---
await execute(`CREATE TABLE IF NOT EXISTS serving_units (
@ -902,12 +883,9 @@ async function runMigrations() {
)`);
// --- Add unit columns to food_log ---
if (!(await hasColumn("food_log", "unit_id"))) {
await execute("ALTER TABLE food_log ADD COLUMN unit_id INTEGER");
}
if (!(await hasColumn("food_log", "unit_amount"))) {
await execute("ALTER TABLE food_log ADD COLUMN unit_amount REAL");
}
const flCols = (await select("PRAGMA table_info(food_log)")).map(r => r.name);
if (!flCols.includes("unit_id")) await execute("ALTER TABLE food_log ADD COLUMN unit_id INTEGER");
if (!flCols.includes("unit_amount")) await execute("ALTER TABLE food_log ADD COLUMN unit_amount REAL");
// Seed serving_units if empty
const suCnt = await select("SELECT COUNT(*) as cnt FROM serving_units");
@ -928,19 +906,20 @@ async function runMigrations() {
console.log("[db.js] Seeded 5 serving units");
}
// Seed product_units for eggs: link products with "яйц" AND "кур" to unit 1 (шт), 60g each
// Seed product_units for eggs (one-time)
try {
const eggProducts = await select(
`SELECT id FROM products WHERE name_lower LIKE '%яйц%' AND name_lower LIKE '%кур%'`
);
for (const ep of eggProducts) {
await execute(
`INSERT OR IGNORE INTO product_units (product_id, unit_id, grams_per_unit)
VALUES (?1, 1, 60)`, [ep.id]
const puCnt = await select("SELECT COUNT(*) as cnt FROM product_units");
if (puCnt[0].cnt === 0) {
const eggProducts = await select(
`SELECT id FROM products WHERE name_lower LIKE '%яйц%' AND name_lower LIKE '%кур%'`
);
}
if (eggProducts.length > 0) {
console.log(`[db.js] Linked ${eggProducts.length} egg products to шт unit`);
for (const ep of eggProducts) {
await execute(
`INSERT OR IGNORE INTO product_units (product_id, unit_id, grams_per_unit)
VALUES (?1, 1, 60)`, [ep.id]
);
}
if (eggProducts.length > 0) console.log(`[db.js] Linked ${eggProducts.length} egg products`);
}
} catch (e) { console.error("[db.js] egg unit seeding error:", e); }
@ -959,9 +938,8 @@ async function runMigrations() {
)`);
// Add bike_id column to gps_sessions
if (!(await hasColumn("gps_sessions", "bike_id"))) {
await execute("ALTER TABLE gps_sessions ADD COLUMN bike_id INTEGER");
}
const gsCols = (await select("PRAGMA table_info(gps_sessions)")).map(r => r.name);
if (!gsCols.includes("bike_id")) await execute("ALTER TABLE gps_sessions ADD COLUMN bike_id INTEGER");
// Seed default bike if table is empty
const bikeCnt = await select("SELECT COUNT(*) as cnt FROM bikes");

View file

@ -876,6 +876,23 @@ GPS.recalculateSession = async function(sessionId) {
const points = await DB.getGpsPoints(sessionId);
if (points.length < 2) return null;
// Fix point ordering: re-assign seq by timestamp
const sorted = points.slice().sort((a, b) => new Date(a.ts) - new Date(b.ts));
let needsReorder = false;
for (let i = 0; i < sorted.length; i++) {
if (sorted[i].seq !== i + 1) { needsReorder = true; break; }
}
if (needsReorder) {
for (let i = 0; i < sorted.length; i++) {
await window.__TAURI__.core.invoke("plugin:sql|execute", {
db: "sqlite:baldav.db",
query: "UPDATE gps_points SET seq = ?1 WHERE session_id = ?2 AND ts = ?3",
values: [i + 1, sessionId, sorted[i].ts],
});
}
console.log(`[GPS] Reordered ${sorted.length} points for session ${sessionId}`);
}
// Get user weight: latest weight log, or profile, or 80
const latestW = await DB.getLatestWeight();
const profile = await DB.getFullProfile();